Browse Source

Merge remote-tracking branch 'upstream/develop' into evmjit

cl-refactor
Paweł Bylica 10 years ago
parent
commit
3a7bbb3b6a
  1. 2
      alethzero/CMakeLists.txt
  2. 2
      alethzero/Context.h
  3. 2
      eth/CMakeLists.txt
  4. 2
      exp/CMakeLists.txt
  5. 2
      libdevcore/CMakeLists.txt
  6. 2
      libdevcore/RLP.cpp
  7. 2
      libdevcrypto/CMakeLists.txt
  8. 6
      libethcore/BlockInfo.cpp
  9. 2
      libethcore/CMakeLists.txt
  10. 1
      libethcore/Exceptions.h
  11. 2
      libethereum/CMakeLists.txt
  12. 14
      libethereum/Client.cpp
  13. 2
      libethereum/Client.h
  14. 2
      libethereum/Interface.h
  15. 7
      libethereum/State.cpp
  16. 2
      libethereum/State.h
  17. 3
      libethereumx/CMakeLists.txt
  18. 2
      libevm/CMakeLists.txt
  19. 2
      libevmcore/CMakeLists.txt
  20. 2
      liblll/CMakeLists.txt
  21. 2
      libnatspec/CMakeLists.txt
  22. 2
      libp2p/CMakeLists.txt
  23. 2
      libserpent/CMakeLists.txt
  24. 37
      libsolidity/AST.cpp
  25. 23
      libsolidity/AST.h
  26. 17
      libsolidity/ASTJsonConverter.cpp
  27. 2
      libsolidity/CMakeLists.txt
  28. 53
      libsolidity/Compiler.cpp
  29. 6
      libsolidity/Compiler.h
  30. 102
      libsolidity/CompilerUtils.cpp
  31. 16
      libsolidity/CompilerUtils.h
  32. 13
      libsolidity/DeclarationContainer.cpp
  33. 6
      libsolidity/DeclarationContainer.h
  34. 26
      libsolidity/ExpressionCompiler.cpp
  35. 9
      libsolidity/NameAndTypeResolver.cpp
  36. 4
      libsolidity/Parser.cpp
  37. 4
      libsolidity/Token.h
  38. 20
      libsolidity/Types.cpp
  39. 7
      libsolidity/Types.h
  40. 4
      libweb3jsonrpc/CMakeLists.txt
  41. 43
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  42. 5
      libweb3jsonrpc/WebThreeStubServerBase.h
  43. 30
      libweb3jsonrpc/abstractwebthreestubserver.h
  44. 7
      libweb3jsonrpc/spec.json
  45. 2
      libwebthree/CMakeLists.txt
  46. 2
      libwhisper/CMakeLists.txt
  47. 2
      lllc/CMakeLists.txt
  48. 4
      mix/CMakeLists.txt
  49. 70
      mix/ClientModel.cpp
  50. 21
      mix/ClientModel.h
  51. 2
      mix/CodeHighlighter.cpp
  52. 213
      mix/CodeModel.cpp
  53. 76
      mix/CodeModel.h
  54. 2
      mix/ContractCallDataEncoder.cpp
  55. 18
      mix/MixClient.cpp
  56. 2
      mix/MixClient.h
  57. 2
      mix/QContractDefinition.cpp
  58. 2
      mix/QContractDefinition.h
  59. 4
      mix/QVariableDefinition.h
  60. 11
      mix/StatusPane.cpp
  61. 4
      mix/StatusPane.h
  62. 4
      mix/main.cpp
  63. 2
      mix/qml/CodeEditorView.qml
  64. 9
      mix/qml/Debugger.qml
  65. 6
      mix/qml/DefaultLabel.qml
  66. 7
      mix/qml/DefaultTextField.qml
  67. 8
      mix/qml/Ether.qml
  68. 2
      mix/qml/MainContent.qml
  69. 21
      mix/qml/ProjectList.qml
  70. 2
      mix/qml/ProjectModel.qml
  71. 2
      mix/qml/StateDialog.qml
  72. 27
      mix/qml/StateListModel.qml
  73. 14
      mix/qml/StatusPane.qml
  74. 117
      mix/qml/TransactionDialog.qml
  75. 32
      mix/qml/WebPreview.qml
  76. 16
      mix/qml/html/WebContainer.html
  77. 77
      mix/qml/js/ProjectModel.js
  78. 1
      mix/qml/js/TransactionHelper.js
  79. 4
      mix/qml/main.qml
  80. 2
      neth/CMakeLists.txt
  81. 2
      sc/CMakeLists.txt
  82. 2
      solc/CMakeLists.txt
  83. 2
      test/CMakeLists.txt
  84. 1513
      test/ManyFunctions.sol
  85. 24
      test/ManyFunctionsGenerator.py
  86. 10
      test/SolidityCompiler.cpp
  87. 49
      test/SolidityEndToEndTest.cpp
  88. 80
      test/SolidityNameAndTypeResolution.cpp
  89. 18
      test/SolidityParser.cpp
  90. 43
      test/TestHelper.cpp
  91. 3
      test/TestHelper.h
  92. 687
      test/blInvalidHeaderTestFiller.json
  93. 381
      test/blValidBlockTestFiller.json
  94. 509
      test/block.cpp
  95. 4
      test/stSystemOperationsTestFiller.json
  96. 47
      test/transaction.cpp
  97. 29
      test/vmPerformanceTestFiller.json
  98. 50
      test/webthreestubclient.h
  99. 2
      third/CMakeLists.txt

2
alethzero/CMakeLists.txt

@ -10,8 +10,8 @@ endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
qt5_wrap_ui(ui_Main.h Main.ui) qt5_wrap_ui(ui_Main.h Main.ui)

2
alethzero/Context.h

@ -29,7 +29,7 @@
class QComboBox; class QComboBox;
namespace dev { namespace eth { class StateDiff; } } namespace dev { namespace eth { struct StateDiff; } }
#define Small "font-size: small; " #define Small "font-size: small; "
#define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; " #define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; "

2
eth/CMakeLists.txt

@ -3,9 +3,9 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE eth) set(EXECUTABLE eth)

2
exp/CMakeLists.txt

@ -3,8 +3,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE exp) set(EXECUTABLE exp)

2
libdevcore/CMakeLists.txt

@ -12,8 +12,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE devcore) set(EXECUTABLE devcore)

2
libdevcore/RLP.cpp

@ -177,7 +177,7 @@ void RLPStream::noteAppended(unsigned _itemCount)
while (m_listStack.size()) while (m_listStack.size())
{ {
if (m_listStack.back().first < _itemCount) if (m_listStack.back().first < _itemCount)
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large")); BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large") << RequirementError((bigint)m_listStack.back().first, (bigint)_itemCount));
m_listStack.back().first -= _itemCount; m_listStack.back().first -= _itemCount;
if (m_listStack.back().first) if (m_listStack.back().first)
break; break;

2
libdevcrypto/CMakeLists.txt

@ -9,10 +9,10 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE devcrypto) set(EXECUTABLE devcrypto)

6
libethcore/BlockInfo.cpp

@ -134,7 +134,7 @@ void BlockInfo::populate(bytesConstRef _block, bool _checkNonce)
RLP header = root[0]; RLP header = root[0];
if (!header.isList()) if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data())); BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data()) << errinfo_comment("block header needs to be a list"));
populateFromHeader(header, _checkNonce); populateFromHeader(header, _checkNonce);
if (!root[1].isList()) if (!root[1].isList())
@ -157,8 +157,8 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
{ {
bytes k = rlp(i); bytes k = rlp(i);
t.insert(&k, tr.data()); t.insert(&k, tr.data());
u256 gp = tr[1].toInt<u256>(); u256 gasprice = tr[1].toInt<u256>();
mgp = min(mgp, gp); mgp = min(mgp, gasprice); // the minimum gas price is not used for anything //TODO delete?
++i; ++i;
} }
if (transactionsRoot != t.root()) if (transactionsRoot != t.root())

2
libethcore/CMakeLists.txt

@ -9,8 +9,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE ethcore) set(EXECUTABLE ethcore)

1
libethcore/Exceptions.h

@ -51,6 +51,7 @@ struct UncleTooOld: virtual dev::Exception {};
class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; }; class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; };
struct DuplicateUncleNonce: virtual dev::Exception {}; struct DuplicateUncleNonce: virtual dev::Exception {};
struct InvalidStateRoot: virtual dev::Exception {}; struct InvalidStateRoot: virtual dev::Exception {};
struct InvalidGasUsed: virtual dev::Exception {};
class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; }; class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; };
struct InvalidTransaction: virtual dev::Exception {}; struct InvalidTransaction: virtual dev::Exception {};
struct InvalidDifficulty: virtual dev::Exception {}; struct InvalidDifficulty: virtual dev::Exception {};

2
libethereum/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE ethereum) set(EXECUTABLE ethereum)

14
libethereum/Client.cpp

@ -714,6 +714,20 @@ BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const
return BlockInfo(); return BlockInfo();
} }
unsigned Client::transactionCount(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return b[1].itemCount();
}
unsigned Client::uncleCount(h256 _blockHash) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return b[2].itemCount();
}
LocalisedLogEntries Client::logs(LogFilter const& _f) const LocalisedLogEntries Client::logs(LogFilter const& _f) const
{ {
LocalisedLogEntries ret; LocalisedLogEntries ret;

2
libethereum/Client.h

@ -229,6 +229,8 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); } virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); }
virtual Transaction transaction(h256 _blockHash, unsigned _i) const; virtual Transaction transaction(h256 _blockHash, unsigned _i) const;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const;
virtual unsigned transactionCount(h256 _blockHash) const;
virtual unsigned uncleCount(h256 _blockHash) const;
/// Differences between transactions. /// Differences between transactions.
using Interface::diff; using Interface::diff;

2
libethereum/Interface.h

@ -103,6 +103,8 @@ public:
virtual BlockDetails blockDetails(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0;
virtual unsigned transactionCount(h256 _blockHash) const = 0;
virtual unsigned uncleCount(h256 _blockHash) const = 0;
// [EXTRA API]: // [EXTRA API]:

7
libethereum/State.cpp

@ -600,6 +600,13 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
BOOST_THROW_EXCEPTION(InvalidStateRoot()); BOOST_THROW_EXCEPTION(InvalidStateRoot());
} }
if (m_currentBlock.gasUsed != gasUsed())
{
// Rollback the trie.
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed)));
}
return tdIncrease; return tdIncrease;
} }

2
libethereum/State.h

@ -132,7 +132,7 @@ public:
* commitToMine(_blockChain); // will call uncommitToMine if a repeat. * commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* // unlock * // unlock
* MineInfo info; * MineInfo info;
* for (info.complete = false; !info.complete; info = mine()) {} * for (info.completed = false; !info.completed; info = mine()) {}
* } * }
* // lock * // lock
* completeMine(); * completeMine();

3
libethereumx/CMakeLists.txt

@ -4,7 +4,8 @@ set(CMAKE_AUTOMOC OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ..)
set(EXECUTABLE ethereumx) set(EXECUTABLE ethereumx)

2
libevm/CMakeLists.txt

@ -13,8 +13,8 @@ aux_source_directory(. SRC_LIST)
# we may not use it in libevm, but one of our dependecies is including boost in header file # we may not use it in libevm, but one of our dependecies is including boost in header file
# and windows is failing to build without that # and windows is failing to build without that
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE evm) set(EXECUTABLE evm)

2
libevmcore/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE evmcore) set(EXECUTABLE evmcore)

2
liblll/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE lll) set(EXECUTABLE lll)

2
libnatspec/CMakeLists.txt

@ -13,7 +13,7 @@ set(CMAKE_AUTOMOC OFF)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(BEFORE ..)
set(EXECUTABLE natspec) set(EXECUTABLE natspec)

2
libp2p/CMakeLists.txt

@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
# we may not use it in libp2p, but one of our dependecies is including leveldb in header file # we may not use it in libp2p, but one of our dependecies is including leveldb in header file
# and windows is failing to build without that # and windows is failing to build without that
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
@ -18,7 +19,6 @@ include_directories(${LEVELDB_INCLUDE_DIRS})
if (MINIUPNPC_FOUND) if (MINIUPNPC_FOUND)
include_directories(${MINIUPNPC_INCLUDE_DIRS}) include_directories(${MINIUPNPC_INCLUDE_DIRS})
endif() endif()
include_directories(..)
set(EXECUTABLE p2p) set(EXECUTABLE p2p)

2
libserpent/CMakeLists.txt

@ -11,7 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(BEFORE ..)
set(EXECUTABLE serpent) set(EXECUTABLE serpent)

37
libsolidity/AST.cpp

@ -274,6 +274,15 @@ TypePointer FunctionDefinition::getType(ContractDefinition const*) const
void FunctionDefinition::checkTypeRequirements() void FunctionDefinition::checkTypeRequirements()
{ {
// change all byte arrays parameters to point to calldata
if (getVisibility() == Visibility::External)
for (ASTPointer<VariableDeclaration> const& var: getParameters())
{
auto const& type = var->getType();
solAssert(!!type, "");
if (auto const* byteArrayType = dynamic_cast<ByteArrayType const*>(type.get()))
var->setType(byteArrayType->copyForLocation(ByteArrayType::Location::CallData));
}
for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters()) for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters())
if (!var->getType()->canLiveOutsideStorage()) if (!var->getType()->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
@ -288,12 +297,23 @@ string FunctionDefinition::getCanonicalSignature() const
return FunctionType(*this).getCanonicalSignature(getName()); return FunctionType(*this).getCanonicalSignature(getName());
} }
Declaration::LValueType VariableDeclaration::getLValueType() const bool VariableDeclaration::isLValue() const
{ {
if (dynamic_cast<FunctionDefinition const*>(getScope()) || dynamic_cast<ModifierDefinition const*>(getScope())) if (auto const* function = dynamic_cast<FunctionDefinition const*>(getScope()))
return Declaration::LValueType::Local; if (function->getVisibility() == Declaration::Visibility::External && isFunctionParameter())
else return false;
return Declaration::LValueType::Storage; return true;
}
bool VariableDeclaration::isFunctionParameter() const
{
auto const* function = dynamic_cast<FunctionDefinition const*>(getScope());
if (!function)
return false;
for (auto const& variable: function->getParameters())
if (variable.get() == this)
return true;
return false;
} }
TypePointer ModifierDefinition::getType(ContractDefinition const*) const TypePointer ModifierDefinition::getType(ContractDefinition const*) const
@ -586,8 +606,7 @@ void MemberAccess::checkTypeRequirements()
if (!m_type) if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not " BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
"visible in " + type.toString())); "visible in " + type.toString()));
//@todo later, this will not always be STORAGE m_isLValue = (type.getCategory() == Type::Category::Struct);
m_lvalue = type.getCategory() == Type::Category::Struct ? Declaration::LValueType::Storage : Declaration::LValueType::None;
} }
void IndexAccess::checkTypeRequirements() void IndexAccess::checkTypeRequirements()
@ -599,14 +618,14 @@ void IndexAccess::checkTypeRequirements()
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType()); MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
m_index->expectType(*type.getKeyType()); m_index->expectType(*type.getKeyType());
m_type = type.getValueType(); m_type = type.getValueType();
m_lvalue = Declaration::LValueType::Storage; m_isLValue = true;
} }
void Identifier::checkTypeRequirements() void Identifier::checkTypeRequirements()
{ {
solAssert(m_referencedDeclaration, "Identifier not resolved."); solAssert(m_referencedDeclaration, "Identifier not resolved.");
m_lvalue = m_referencedDeclaration->getLValueType(); m_isLValue = m_referencedDeclaration->isLValue();
m_type = m_referencedDeclaration->getType(m_currentContract); m_type = m_referencedDeclaration->getType(m_currentContract);
if (!m_type) if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined.")); BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined."));

23
libsolidity/AST.h

@ -132,8 +132,8 @@ private:
class Declaration: public ASTNode class Declaration: public ASTNode
{ {
public: public:
enum class LValueType { None, Local, Storage }; /// Visibility ordered from restricted to unrestricted.
enum class Visibility { Default, Public, Protected, Private }; enum class Visibility { Default, Private, Protected, Public, External };
Declaration(Location const& _location, ASTPointer<ASTString> const& _name, Declaration(Location const& _location, ASTPointer<ASTString> const& _name,
Visibility _visibility = Visibility::Default): Visibility _visibility = Visibility::Default):
@ -142,7 +142,9 @@ public:
/// @returns the declared name. /// @returns the declared name.
ASTString const& getName() const { return *m_name; } ASTString const& getName() const { return *m_name; }
Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; }
bool isPublic() const { return getVisibility() == Visibility::Public; } bool isPublic() const { return getVisibility() >= Visibility::Public; }
bool isVisibleInContract() const { return getVisibility() != Visibility::External; }
bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Protected; }
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step. /// Available only after name and type resolution step.
@ -153,8 +155,7 @@ public:
/// The current contract has to be given since this context can change the type, especially of /// The current contract has to be given since this context can change the type, especially of
/// contract types. /// contract types.
virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0; virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0;
/// @returns the lvalue type of expressions referencing this declaration virtual bool isLValue() const { return false; }
virtual LValueType getLValueType() const { return LValueType::None; }
protected: protected:
virtual Visibility getDefaultVisibility() const { return Visibility::Public; } virtual Visibility getDefaultVisibility() const { return Visibility::Public; }
@ -445,8 +446,9 @@ public:
TypePointer getType(ContractDefinition const* = nullptr) const { return m_type; } TypePointer getType(ContractDefinition const* = nullptr) const { return m_type; }
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; } void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
virtual LValueType getLValueType() const override; virtual bool isLValue() const override;
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); } bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
bool isFunctionParameter() const;
bool isStateVariable() const { return m_isStateVariable; } bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; } bool isIndexed() const { return m_isIndexed; }
@ -884,8 +886,7 @@ public:
virtual void checkTypeRequirements() = 0; virtual void checkTypeRequirements() = 0;
std::shared_ptr<Type const> const& getType() const { return m_type; } std::shared_ptr<Type const> const& getType() const { return m_type; }
bool isLValue() const { return m_lvalue != Declaration::LValueType::None; } bool isLValue() const { return m_isLValue; }
bool isLocalLValue() const { return m_lvalue == Declaration::LValueType::Local; }
/// Helper function, infer the type via @ref checkTypeRequirements and then check that it /// Helper function, infer the type via @ref checkTypeRequirements and then check that it
/// is implicitly convertible to @a _expectedType. If not, throw exception. /// is implicitly convertible to @a _expectedType. If not, throw exception.
@ -900,9 +901,9 @@ public:
protected: protected:
//! Inferred type of the expression, only filled after a call to checkTypeRequirements(). //! Inferred type of the expression, only filled after a call to checkTypeRequirements().
std::shared_ptr<Type const> m_type; std::shared_ptr<Type const> m_type;
//! If this expression is an lvalue (i.e. something that can be assigned to) and is stored //! If this expression is an lvalue (i.e. something that can be assigned to).
//! locally or in storage. This is set during calls to @a checkTypeRequirements() //! This is set during calls to @a checkTypeRequirements()
Declaration::LValueType m_lvalue = Declaration::LValueType::None; bool m_isLValue = false;
//! Whether the outer expression requested the address (true) or the value (false) of this expression. //! Whether the outer expression requested the address (true) or the value (false) of this expression.
bool m_lvalueRequested = false; bool m_lvalueRequested = false;
}; };

17
libsolidity/ASTJsonConverter.cpp

@ -118,11 +118,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
bool ASTJsonConverter::visit(VariableDeclaration const& _node) bool ASTJsonConverter::visit(VariableDeclaration const& _node)
{ {
bool isLocalVariable = (_node.getLValueType() == VariableDeclaration::LValueType::Local); addJsonNode("VariableDeclaration", { make_pair("name", _node.getName()) }, true);
addJsonNode("VariableDeclaration",
{ make_pair("name", _node.getName()),
make_pair("local", boost::lexical_cast<std::string>(isLocalVariable))},
true);
return true; return true;
} }
@ -216,11 +212,12 @@ bool ASTJsonConverter::visit(ExpressionStatement const&)
bool ASTJsonConverter::visit(Expression const& _node) bool ASTJsonConverter::visit(Expression const& _node)
{ {
addJsonNode("Expression", addJsonNode(
{ make_pair("type", getType(_node)), "Expression",
make_pair("lvalue", boost::lexical_cast<std::string>(_node.isLValue())), { make_pair("type", getType(_node)),
make_pair("local_lvalue", boost::lexical_cast<std::string>(_node.isLocalLValue())) }, make_pair("lvalue", boost::lexical_cast<std::string>(_node.isLValue())) },
true); true
);
return true; return true;
} }

2
libsolidity/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE solidity) set(EXECUTABLE solidity)

53
libsolidity/Compiler.cpp

@ -147,7 +147,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
// retrieve the function signature hash from the calldata // retrieve the function signature hash from the calldata
if (!interfaceFunctions.empty()) if (!interfaceFunctions.empty())
CompilerUtils(m_context).loadFromMemory(0, 4, false, true); CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true);
// stack now is: 1 0 <funhash> // stack now is: 1 0 <funhash>
for (auto const& it: interfaceFunctions) for (auto const& it: interfaceFunctions)
@ -178,23 +178,46 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
} }
} }
unsigned Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory)
{ {
// We do not check the calldata size, everything is zero-padded. // We do not check the calldata size, everything is zero-padded.
unsigned dataOffset = CompilerUtils::dataStartOffset; // the 4 bytes of the function hash signature unsigned offset(CompilerUtils::dataStartOffset);
//@todo this can be done more efficiently, saving some CALLDATALOAD calls bool const c_padToWords = true;
unsigned dynamicParameterCount = 0;
for (TypePointer const& type: _typeParameters) for (TypePointer const& type: _typeParameters)
{ if (type->isDynamicallySized())
unsigned const c_numBytes = type->getCalldataEncodedSize(); dynamicParameterCount++;
if (c_numBytes > 32) offset += dynamicParameterCount * 32;
BOOST_THROW_EXCEPTION(CompilerError() unsigned currentDynamicParameter = 0;
<< errinfo_comment("Type " + type->toString() + " not yet supported.")); for (TypePointer const& type: _typeParameters)
bool const c_leftAligned = type->getCategory() == Type::Category::String; if (type->isDynamicallySized())
bool const c_padToWords = true; {
dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, c_numBytes, c_leftAligned, // value on stack: [calldata_offset] (only if we are already in dynamic mode)
!_fromMemory, c_padToWords); if (currentDynamicParameter == 0)
} // switch from static to dynamic
return dataOffset; m_context << u256(offset);
// retrieve length
CompilerUtils(m_context).loadFromMemory(
CompilerUtils::dataStartOffset + currentDynamicParameter * 32,
IntegerType(256), !_fromMemory, c_padToWords);
// stack: offset length
// add 32-byte padding to copy of length
m_context << u256(32) << eth::Instruction::DUP1 << u256(31)
<< eth::Instruction::DUP4 << eth::Instruction::ADD
<< eth::Instruction::DIV << eth::Instruction::MUL;
// stack: offset length padded_length
m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
currentDynamicParameter++;
// stack: offset length next_calldata_offset
}
else if (currentDynamicParameter == 0)
// we can still use static load
offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, c_padToWords);
else
CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, c_padToWords);
if (dynamicParameterCount > 0)
m_context << eth::Instruction::POP;
} }
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)

6
libsolidity/Compiler.h

@ -20,6 +20,8 @@
* Solidity AST to EVM bytecode compiler. * Solidity AST to EVM bytecode compiler.
*/ */
#pragma once
#include <ostream> #include <ostream>
#include <functional> #include <functional>
#include <libsolidity/ASTVisitor.h> #include <libsolidity/ASTVisitor.h>
@ -52,8 +54,8 @@ private:
void appendConstructorCall(FunctionDefinition const& _constructor); void appendConstructorCall(FunctionDefinition const& _constructor);
void appendFunctionSelector(ContractDefinition const& _contract); void appendFunctionSelector(ContractDefinition const& _contract);
/// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers. /// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers.
/// From memory if @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes. /// From memory if @a _fromMemory is true, otherwise from call data.
unsigned appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false); void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false);
void appendReturnValuePacker(TypePointers const& _typeParameters); void appendReturnValuePacker(TypePointers const& _typeParameters);
void registerStateVariables(ContractDefinition const& _contract); void registerStateVariables(ContractDefinition const& _contract);

102
libsolidity/CompilerUtils.cpp

@ -33,35 +33,26 @@ namespace solidity
const unsigned int CompilerUtils::dataStartOffset = 4; const unsigned int CompilerUtils::dataStartOffset = 4;
unsigned CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, unsigned CompilerUtils::loadFromMemory(unsigned _offset, Type const& _type,
bool _fromCalldata, bool _padToWordBoundaries) bool _fromCalldata, bool _padToWordBoundaries)
{ {
if (_bytes == 0) solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically load dynamic type.");
{ m_context << u256(_offset);
m_context << u256(0); return loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries);
return 0;
}
eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD;
solAssert(_bytes <= 32, "Memory load of more than 32 bytes requested.");
if (_bytes == 32 || _padToWordBoundaries)
{
m_context << u256(_offset) << load;
return 32;
}
else
{
// load data and add leading or trailing zeros by dividing/multiplying depending on alignment
u256 shiftFactor = u256(1) << ((32 - _bytes) * 8);
m_context << shiftFactor;
if (_leftAligned)
m_context << eth::Instruction::DUP1;
m_context << u256(_offset) << load << eth::Instruction::DIV;
if (_leftAligned)
m_context << eth::Instruction::MUL;
return _bytes;
}
} }
void CompilerUtils::loadFromMemoryDynamic(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
solAssert(_type.getCategory() != Type::Category::ByteArray, "Byte arrays not yet implemented.");
m_context << eth::Instruction::DUP1;
unsigned numBytes = loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries);
// update memory counter
for (unsigned i = 0; i < _type.getSizeOnStack(); ++i)
m_context << eth::swapInstruction(1 + i);
m_context << u256(numBytes) << eth::Instruction::ADD;
}
unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries) unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries)
{ {
solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically store dynamic type."); solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically store dynamic type.");
@ -79,9 +70,12 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
if (type.getLocation() == ByteArrayType::Location::CallData) if (type.getLocation() == ByteArrayType::Location::CallData)
{ {
m_context << eth::Instruction::CALLDATASIZE << u256(0) << eth::Instruction::DUP3 // stack: target source_offset source_len
<< eth::Instruction::CALLDATACOPY m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5
<< eth::Instruction::CALLDATASIZE << eth::Instruction::ADD; // stack: target source_offset source_len source_len source_offset target
<< eth::Instruction::CALLDATACOPY
<< eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP;
} }
else else
{ {
@ -120,6 +114,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
if (numBytes > 0) if (numBytes > 0)
{ {
solAssert(_type.getSizeOnStack() == 1, "Memory store of types with stack size != 1 not implemented.");
m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE;
m_context << u256(numBytes) << eth::Instruction::ADD; m_context << u256(numBytes) << eth::Instruction::ADD;
} }
@ -179,29 +174,32 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType,
{ {
case ByteArrayType::Location::CallData: case ByteArrayType::Location::CallData:
{ {
// @todo this does not take length into account. It also assumes that after "CALLDATALENGTH" we only have zeros. // This also assumes that after "length" we only have zeros, i.e. it cannot be used to
// slice a byte array from calldata.
// stack: source_offset source_len target_ref
// fetch old length and convert to words // fetch old length and convert to words
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
m_context << u256(31) << eth::Instruction::ADD m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV; << u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
// stack here: target_ref target_length_words // stack here: source_offset source_len target_ref target_length_words
// actual array data is stored at SHA3(storage_offset) // actual array data is stored at SHA3(storage_offset)
m_context << eth::Instruction::DUP2; m_context << eth::Instruction::DUP2;
CompilerUtils(m_context).computeHashStatic(); CompilerUtils(m_context).computeHashStatic();
// compute target_data_end // compute target_data_end
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1; << eth::Instruction::SWAP1;
// stack here: target_ref target_data_end target_data_ref // stack here: source_offset source_len target_ref target_data_end target_data_ref
// store length (in bytes) // store length (in bytes)
m_context << eth::Instruction::CALLDATASIZE; m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP5 << eth::Instruction::SSTORE; << eth::Instruction::SSTORE;
// jump to end if length is zero // jump to end if length is zero
m_context << eth::Instruction::ISZERO; m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag(); eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd); m_context.appendConditionalJumpTo(copyLoopEnd);
// store start offset // store start offset
m_context << u256(0); m_context << eth::Instruction::DUP5;
// stack now: target_ref target_data_end target_data_ref calldata_offset // stack now: source_offset source_len target_ref target_data_end target_data_ref calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag(); eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart m_context << copyLoopStart
// copy from calldata and store // copy from calldata and store
@ -212,16 +210,18 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType,
// increment calldata_offset by 32 // increment calldata_offset by 32
<< eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD
// check for loop condition // check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::CALLDATASIZE << eth::Instruction::GT; << eth::Instruction::DUP1 << eth::Instruction::DUP6 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(copyLoopStart); m_context.appendConditionalJumpTo(copyLoopStart);
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
m_context << copyLoopEnd; m_context << copyLoopEnd;
// now clear leftover bytes of the old value // now clear leftover bytes of the old value
// stack now: target_ref target_data_end target_data_ref // stack now: source_offset source_len target_ref target_data_end target_data_ref
clearStorageLoop(); clearStorageLoop();
// stack now: source_offset source_len target_ref target_data_end
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP << eth::Instruction::SWAP2
<< eth::Instruction::POP << eth::Instruction::POP;
break; break;
} }
case ByteArrayType::Location::Storage: case ByteArrayType::Location::Storage:
@ -289,6 +289,30 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType,
} }
} }
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
unsigned _encodedSize = _type.getCalldataEncodedSize();
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
bool leftAligned = _type.getCategory() == Type::Category::String;
if (numBytes == 0)
m_context << eth::Instruction::POP << u256(0);
else
{
solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
m_context << (_fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD);
if (numBytes != 32)
{
// add leading or trailing zeros by dividing/multiplying depending on alignment
u256 shiftFactor = u256(1) << ((32 - numBytes) * 8);
m_context << shiftFactor << eth::Instruction::SWAP1 << eth::Instruction::DIV;
if (leftAligned)
m_context << shiftFactor << eth::Instruction::MUL;
}
}
return numBytes;
}
void CompilerUtils::clearByteArray(ByteArrayType const& _type) const void CompilerUtils::clearByteArray(ByteArrayType const& _type) const
{ {
solAssert(_type.getLocation() == ByteArrayType::Location::Storage, ""); solAssert(_type.getLocation() == ByteArrayType::Location::Storage, "");

16
libsolidity/CompilerUtils.h

@ -37,14 +37,16 @@ public:
/// Loads data from memory to the stack. /// Loads data from memory to the stack.
/// @param _offset offset in memory (or calldata) /// @param _offset offset in memory (or calldata)
/// @param _bytes number of bytes to load /// @param _type data type to load
/// @param _leftAligned if true, store left aligned on stack (otherwise right aligned)
/// @param _fromCalldata if true, load from calldata, not from memory /// @param _fromCalldata if true, load from calldata, not from memory
/// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries /// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries
/// @returns the number of bytes consumed in memory (can be different from _bytes if /// @returns the number of bytes consumed in memory.
/// _padToWordBoundaries is true) unsigned loadFromMemory(unsigned _offset, Type const& _type = IntegerType(256),
unsigned loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, bool _fromCalldata = false, bool _padToWordBoundaries = false);
bool _fromCalldata = false, bool _padToWordBoundaries = false); /// Dynamic version of @see loadFromMemory, expects the memory offset on the stack.
/// Stack pre: memory_offset
/// Stack post: value... (memory_offset+length)
void loadFromMemoryDynamic(Type const& _type, bool _fromCalldata = false, bool _padToWordBoundaries = true);
/// Stores data from stack in memory. /// Stores data from stack in memory.
/// @param _offset offset in memory /// @param _offset offset in memory
/// @param _type type of the data on the stack /// @param _type type of the data on the stack
@ -93,6 +95,8 @@ public:
private: private:
/// Prepares the given type for storing in memory by shifting it if necessary. /// Prepares the given type for storing in memory by shifting it if necessary.
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const; unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const;
/// Loads type from memory assuming memory offset is on stack top.
unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries);
/// Appends a loop that clears a sequence of storage slots (excluding end). /// Appends a loop that clears a sequence of storage slots (excluding end).
/// Stack pre: end_ref start_ref /// Stack pre: end_ref start_ref
/// Stack post: end_ref /// Stack post: end_ref

13
libsolidity/DeclarationContainer.cpp

@ -28,14 +28,19 @@ namespace dev
namespace solidity namespace solidity
{ {
bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _update) bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update)
{ {
if (_declaration.getName().empty()) ASTString const& name(_declaration.getName());
if (name.empty())
return true; return true;
if (!_update && m_declarations.find(_declaration.getName()) != m_declarations.end()) if (!_update && (m_declarations.count(name) || m_invisibleDeclarations.count(name)))
return false; return false;
m_declarations[_declaration.getName()] = &_declaration;
if (_invisible)
m_invisibleDeclarations.insert(name);
else
m_declarations[name] = &_declaration;
return true; return true;
} }

6
libsolidity/DeclarationContainer.h

@ -23,6 +23,7 @@
#pragma once #pragma once
#include <map> #include <map>
#include <set>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <libsolidity/ASTForward.h> #include <libsolidity/ASTForward.h>
@ -43,8 +44,10 @@ public:
DeclarationContainer const* _enclosingContainer = nullptr): DeclarationContainer const* _enclosingContainer = nullptr):
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {} m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
/// Registers the declaration in the scope unless its name is already declared or the name is empty. /// Registers the declaration in the scope unless its name is already declared or the name is empty.
/// @param _invisible if true, registers the declaration, reports name clashes but does not return it in @a resolveName
/// @param _update if true, replaces a potential declaration that is already present
/// @returns false if the name was already declared. /// @returns false if the name was already declared.
bool registerDeclaration(Declaration const& _declaration, bool _update = false); bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false);
Declaration const* resolveName(ASTString const& _name, bool _recursive = false) const; Declaration const* resolveName(ASTString const& _name, bool _recursive = false) const;
Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
std::map<ASTString, Declaration const*> const& getDeclarations() const { return m_declarations; } std::map<ASTString, Declaration const*> const& getDeclarations() const { return m_declarations; }
@ -53,6 +56,7 @@ private:
Declaration const* m_enclosingDeclaration; Declaration const* m_enclosingDeclaration;
DeclarationContainer const* m_enclosingContainer; DeclarationContainer const* m_enclosingContainer;
std::map<ASTString, Declaration const*> m_declarations; std::map<ASTString, Declaration const*> m_declarations;
std::set<ASTString> m_invisibleDeclarations;
}; };
} }

26
libsolidity/ExpressionCompiler.cpp

@ -475,9 +475,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
else if (member == "gasprice") else if (member == "gasprice")
m_context << eth::Instruction::GASPRICE; m_context << eth::Instruction::GASPRICE;
else if (member == "data") else if (member == "data")
{ m_context << u256(0) << eth::Instruction::CALLDATASIZE;
// nothing to store on the stack
}
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member."));
break; break;
@ -510,6 +508,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
m_context << m_context.getFunctionEntryLabel(*function).pushTag(); m_context << m_context.getFunctionEntryLabel(*function).pushTag();
return; return;
} }
solAssert(false, "Function not found in member access.");
} }
else if (auto enumType = dynamic_cast<EnumType const*>(type.getActualType().get())) else if (auto enumType = dynamic_cast<EnumType const*>(type.getActualType().get()))
m_context << enumType->getMemberValue(_memberAccess.getMemberName()); m_context << enumType->getMemberValue(_memberAccess.getMemberName());
@ -518,7 +517,19 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case Type::Category::ByteArray: case Type::Category::ByteArray:
{ {
solAssert(member == "length", "Illegal bytearray member."); solAssert(member == "length", "Illegal bytearray member.");
m_context << eth::Instruction::SLOAD; auto const& type = dynamic_cast<ByteArrayType const&>(*_memberAccess.getExpression().getType());
switch (type.getLocation())
{
case ByteArrayType::Location::CallData:
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
break;
case ByteArrayType::Location::Storage:
m_context << eth::Instruction::SLOAD;
break;
default:
solAssert(false, "Unsupported byte array location.");
break;
}
break; break;
} }
default: default:
@ -885,11 +896,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
m_context << eth::Instruction::POP; // pop contract address m_context << eth::Instruction::POP; // pop contract address
if (retSize > 0) if (firstType)
{ CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true);
bool const c_leftAligned = firstType->getCategory() == Type::Category::String;
CompilerUtils(m_context).loadFromMemory(0, retSize, c_leftAligned, false, true);
}
} }
void ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expression const>> const& _arguments, void ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expression const>> const& _arguments,

9
libsolidity/NameAndTypeResolver.cpp

@ -86,7 +86,7 @@ void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract)
void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
{ {
m_scopes[nullptr].registerDeclaration(_declaration, true); m_scopes[nullptr].registerDeclaration(_declaration, false, true);
solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope."); solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope.");
} }
@ -110,8 +110,9 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base)
for (auto const& nameAndDeclaration: iterator->second.getDeclarations()) for (auto const& nameAndDeclaration: iterator->second.getDeclarations())
{ {
Declaration const* declaration = nameAndDeclaration.second; Declaration const* declaration = nameAndDeclaration.second;
// Import if it was declared in the base and is not the constructor // Import if it was declared in the base, is not the constructor and is visible in derived classes
if (declaration->getScope() == &_base && declaration->getName() != _base.getName()) if (declaration->getScope() == &_base && declaration->getName() != _base.getName() &&
declaration->isVisibleInDerivedContracts())
m_currentScope->registerDeclaration(*declaration); m_currentScope->registerDeclaration(*declaration);
} }
} }
@ -308,7 +309,7 @@ void DeclarationRegistrationHelper::closeCurrentScope()
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
{ {
if (!m_scopes[m_currentScope].registerDeclaration(_declaration)) if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract()))
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation())
<< errinfo_comment("Identifier already declared.")); << errinfo_comment("Identifier already declared."));
//@todo the exception should also contain the location of the first declaration //@todo the exception should also contain the location of the first declaration

4
libsolidity/Parser.cpp

@ -190,6 +190,8 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
visibility = Declaration::Visibility::Protected; visibility = Declaration::Visibility::Protected;
else if (_token == Token::Private) else if (_token == Token::Private)
visibility = Declaration::Visibility::Private; visibility = Declaration::Visibility::Private;
else if (_token == Token::External)
visibility = Declaration::Visibility::External;
else else
solAssert(false, "Invalid visibility specifier."); solAssert(false, "Invalid visibility specifier.");
m_scanner->next(); m_scanner->next();
@ -306,7 +308,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOp
ASTPointer<ASTString> identifier; ASTPointer<ASTString> identifier;
Token::Value token = m_scanner->getCurrentToken(); Token::Value token = m_scanner->getCurrentToken();
Declaration::Visibility visibility(Declaration::Visibility::Default); Declaration::Visibility visibility(Declaration::Visibility::Default);
if (_options.isStateVariable && Token::isVisibilitySpecifier(token)) if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token))
visibility = parseVisibilitySpecifier(token); visibility = parseVisibilitySpecifier(token);
if (_options.allowIndexed && token == Token::Indexed) if (_options.allowIndexed && token == Token::Indexed)
{ {

4
libsolidity/Token.h

@ -150,6 +150,7 @@ namespace solidity
K(Do, "do", 0) \ K(Do, "do", 0) \
K(Else, "else", 0) \ K(Else, "else", 0) \
K(Event, "event", 0) \ K(Event, "event", 0) \
K(External, "external", 0) \
K(Is, "is", 0) \ K(Is, "is", 0) \
K(Indexed, "indexed", 0) \ K(Indexed, "indexed", 0) \
K(For, "for", 0) \ K(For, "for", 0) \
@ -378,7 +379,8 @@ public:
static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; } static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; }
static bool isCountOp(Value op) { return op == Inc || op == Dec; } static bool isCountOp(Value op) { return op == Inc || op == Dec; }
static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); }
static bool isVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Protected; } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Protected; }
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; }
// Returns a string corresponding to the JS token string // Returns a string corresponding to the JS token string

20
libsolidity/Types.cpp

@ -540,12 +540,19 @@ bool ByteArrayType::operator==(Type const& _other) const
unsigned ByteArrayType::getSizeOnStack() const unsigned ByteArrayType::getSizeOnStack() const
{ {
if (m_location == Location::CallData) if (m_location == Location::CallData)
return 0; // offset, length (stack top)
return 2;
else else
// offset
return 1; return 1;
} }
const MemberList ByteArrayType::s_byteArrayMemberList = MemberList({{"length", make_shared<IntegerType >(256)}}); shared_ptr<ByteArrayType> ByteArrayType::copyForLocation(ByteArrayType::Location _location) const
{
return make_shared<ByteArrayType>(_location);
}
const MemberList ByteArrayType::s_byteArrayMemberList = MemberList({{"length", make_shared<IntegerType>(256)}});
bool ContractType::operator==(Type const& _other) const bool ContractType::operator==(Type const& _other) const
{ {
@ -572,7 +579,8 @@ MemberList const& ContractType::getMembers() const
{ {
for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts()) for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions())
if (!function->isConstructor() && !function->getName().empty()) if (!function->isConstructor() && !function->getName().empty() &&
function->isVisibleInDerivedContracts())
members.insert(make_pair(function->getName(), make_shared<FunctionType>(*function, true))); members.insert(make_pair(function->getName(), make_shared<FunctionType>(*function, true)));
} }
else else
@ -769,7 +777,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
} }
FunctionType::FunctionType(const EventDefinition& _event): FunctionType::FunctionType(const EventDefinition& _event):
m_location(Location::Event), m_declaration(&_event) m_location(Location::Event), m_isConstant(true), m_declaration(&_event)
{ {
TypePointers params; TypePointers params;
vector<string> paramNames; vector<string> paramNames;
@ -957,10 +965,10 @@ MemberList const& TypeType::getMembers() const
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).getContractDefinition(); ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).getContractDefinition();
vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts(); vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts();
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end()) if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
// We are accessing the type of a base contract, so add all public and private // We are accessing the type of a base contract, so add all public and protected
// functions. Note that this does not add inherited functions on purpose. // functions. Note that this does not add inherited functions on purpose.
for (ASTPointer<FunctionDefinition> const& f: contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& f: contract.getDefinedFunctions())
if (!f->isConstructor() && !f->getName().empty()) if (!f->isConstructor() && !f->getName().empty() && f->isVisibleInDerivedContracts())
members[f->getName()] = make_shared<FunctionType>(*f); members[f->getName()] = make_shared<FunctionType>(*f);
} }
else if (m_actualType->getCategory() == Category::Enum) else if (m_actualType->getCategory() == Category::Enum)

7
libsolidity/Types.h

@ -122,6 +122,8 @@ public:
/// is not a simple big-endian encoding or the type cannot be stored in calldata. /// is not a simple big-endian encoding or the type cannot be stored in calldata.
/// Note that irrespective of this size, each calldata element is padded to a multiple of 32 bytes. /// Note that irrespective of this size, each calldata element is padded to a multiple of 32 bytes.
virtual unsigned getCalldataEncodedSize() const { return 0; } virtual unsigned getCalldataEncodedSize() const { return 0; }
/// @returns true if the type is dynamically encoded in calldata
virtual bool isDynamicallySized() const { return false; }
/// @returns number of bytes required to hold this value in storage. /// @returns number of bytes required to hold this value in storage.
/// For dynamically "allocated" types, it returns the size of the statically allocated head, /// For dynamically "allocated" types, it returns the size of the statically allocated head,
virtual u256 getStorageSize() const { return 1; } virtual u256 getStorageSize() const { return 1; }
@ -289,12 +291,17 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override; virtual bool operator==(const Type& _other) const override;
virtual bool isDynamicallySized() const { return true; }
virtual unsigned getSizeOnStack() const override; virtual unsigned getSizeOnStack() const override;
virtual std::string toString() const override { return "bytes"; } virtual std::string toString() const override { return "bytes"; }
virtual MemberList const& getMembers() const override { return s_byteArrayMemberList; } virtual MemberList const& getMembers() const override { return s_byteArrayMemberList; }
Location getLocation() const { return m_location; } Location getLocation() const { return m_location; }
/// @returns a copy of this type with location changed to @a _location
/// @todo this might move as far up as Type later
std::shared_ptr<ByteArrayType> copyForLocation(Location _location) const;
private: private:
Location m_location; Location m_location;
static const MemberList s_byteArrayMemberList; static const MemberList s_byteArrayMemberList;

4
libweb3jsonrpc/CMakeLists.txt

@ -9,8 +9,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..)
include_directories(${MHD_INCLUDE_DIRS}) include_directories(${MHD_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})

43
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -367,6 +367,26 @@ double WebThreeStubServerBase::eth_countAt(string const& _address)
return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault()); return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault());
} }
double WebThreeStubServerBase::eth_transactionCountByHash(std::string const& _hash)
{
return client()->transactionCount(jsToFixed<32>(_hash));
}
double WebThreeStubServerBase::eth_transactionCountByNumber(int _number)
{
return client()->transactionCount(client()->hashFromNumber(_number));
}
double WebThreeStubServerBase::eth_uncleCountByHash(std::string const& _hash)
{
return client()->transactionCount(jsToFixed<32>(_hash));
}
double WebThreeStubServerBase::eth_uncleCountByNumber(int _number)
{
return client()->transactionCount(client()->hashFromNumber(_number));
}
int WebThreeStubServerBase::eth_defaultBlock() int WebThreeStubServerBase::eth_defaultBlock()
{ {
return client()->getDefault(); return client()->getDefault();
@ -613,6 +633,29 @@ Json::Value WebThreeStubServerBase::shh_changed(int _id)
return ret; return ret;
} }
Json::Value WebThreeStubServerBase::shh_getMessages(int _id)
{
Json::Value ret(Json::arrayValue);
auto pub = m_shhWatches[_id];
if (!pub || m_ids.count(pub))
for (h256 const& h: face()->watchMessages(_id))
{
auto e = face()->envelope(h);
shh::Message m;
if (pub)
{
cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here.";
m = e.open(face()->fullTopic(_id), m_ids[pub]);
}
else
m = e.open(face()->fullTopic(_id));
if (!m)
continue;
ret.append(toJson(h, e, m));
}
return ret;
}
int WebThreeStubServerBase::shh_newFilter(Json::Value const& _json) int WebThreeStubServerBase::shh_newFilter(Json::Value const& _json)
{ {
auto w = toWatch(_json); auto w = toWatch(_json);

5
libweb3jsonrpc/WebThreeStubServerBase.h

@ -76,6 +76,10 @@ public:
virtual std::string eth_coinbase(); virtual std::string eth_coinbase();
virtual Json::Value eth_compilers(); virtual Json::Value eth_compilers();
virtual double eth_countAt(std::string const& _address); virtual double eth_countAt(std::string const& _address);
virtual double eth_transactionCountByHash(std::string const& _hash);
virtual double eth_transactionCountByNumber(int _number);
virtual double eth_uncleCountByHash(std::string const& _hash);
virtual double eth_uncleCountByNumber(int _number);
virtual int eth_defaultBlock(); virtual int eth_defaultBlock();
virtual std::string eth_gasPrice(); virtual std::string eth_gasPrice();
virtual Json::Value eth_filterLogs(int _id); virtual Json::Value eth_filterLogs(int _id);
@ -113,6 +117,7 @@ public:
virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who); virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who);
virtual Json::Value shh_changed(int _id); virtual Json::Value shh_changed(int _id);
virtual Json::Value shh_getMessages(int _id);
virtual bool shh_haveIdentity(std::string const& _id); virtual bool shh_haveIdentity(std::string const& _id);
virtual int shh_newFilter(Json::Value const& _json); virtual int shh_newFilter(Json::Value const& _json);
virtual std::string shh_newGroup(std::string const& _id, std::string const& _who); virtual std::string shh_newGroup(std::string const& _id, std::string const& _who);

30
libweb3jsonrpc/abstractwebthreestubserver.h

@ -29,6 +29,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(jsonrpc::Procedure("eth_stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_stateAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_stateAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_storageAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_storageAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_storageAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_storageAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_countAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_countAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_transactionCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_transactionCountByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_transactionCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionCountByNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_uncleCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_uncleCountByHashI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_uncleCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleCountByNumberI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_codeAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_codeAtI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_transactI); this->bindAndAddMethod(jsonrpc::Procedure("eth_transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_transactI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_callI); this->bindAndAddMethod(jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_callI);
@ -63,6 +67,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(jsonrpc::Procedure("shh_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_newFilterI); this->bindAndAddMethod(jsonrpc::Procedure("shh_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_newFilterI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI); this->bindAndAddMethod(jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_changedI); this->bindAndAddMethod(jsonrpc::Procedure("shh_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_changedI);
this->bindAndAddMethod(jsonrpc::Procedure("shh_getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_getMessagesI);
} }
inline virtual void web3_sha3I(const Json::Value &request, Json::Value &response) inline virtual void web3_sha3I(const Json::Value &request, Json::Value &response)
@ -141,6 +146,22 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{ {
response = this->eth_countAt(request[0u].asString()); response = this->eth_countAt(request[0u].asString());
} }
inline virtual void eth_transactionCountByHashI(const Json::Value &request, Json::Value &response)
{
response = this->eth_transactionCountByHash(request[0u].asString());
}
inline virtual void eth_transactionCountByNumberI(const Json::Value &request, Json::Value &response)
{
response = this->eth_transactionCountByNumber(request[0u].asInt());
}
inline virtual void eth_uncleCountByHashI(const Json::Value &request, Json::Value &response)
{
response = this->eth_uncleCountByHash(request[0u].asString());
}
inline virtual void eth_uncleCountByNumberI(const Json::Value &request, Json::Value &response)
{
response = this->eth_uncleCountByNumber(request[0u].asInt());
}
inline virtual void eth_codeAtI(const Json::Value &request, Json::Value &response) inline virtual void eth_codeAtI(const Json::Value &request, Json::Value &response)
{ {
response = this->eth_codeAt(request[0u].asString()); response = this->eth_codeAt(request[0u].asString());
@ -281,6 +302,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{ {
response = this->shh_changed(request[0u].asInt()); response = this->shh_changed(request[0u].asInt());
} }
inline virtual void shh_getMessagesI(const Json::Value &request, Json::Value &response)
{
response = this->shh_getMessages(request[0u].asInt());
}
virtual std::string web3_sha3(const std::string& param1) = 0; virtual std::string web3_sha3(const std::string& param1) = 0;
virtual std::string eth_coinbase() = 0; virtual std::string eth_coinbase() = 0;
virtual bool eth_setCoinbase(const std::string& param1) = 0; virtual bool eth_setCoinbase(const std::string& param1) = 0;
@ -298,6 +323,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual std::string eth_stateAt(const std::string& param1, const std::string& param2) = 0; virtual std::string eth_stateAt(const std::string& param1, const std::string& param2) = 0;
virtual Json::Value eth_storageAt(const std::string& param1) = 0; virtual Json::Value eth_storageAt(const std::string& param1) = 0;
virtual double eth_countAt(const std::string& param1) = 0; virtual double eth_countAt(const std::string& param1) = 0;
virtual double eth_transactionCountByHash(const std::string& param1) = 0;
virtual double eth_transactionCountByNumber(int param1) = 0;
virtual double eth_uncleCountByHash(const std::string& param1) = 0;
virtual double eth_uncleCountByNumber(int param1) = 0;
virtual std::string eth_codeAt(const std::string& param1) = 0; virtual std::string eth_codeAt(const std::string& param1) = 0;
virtual std::string eth_transact(const Json::Value& param1) = 0; virtual std::string eth_transact(const Json::Value& param1) = 0;
virtual std::string eth_call(const Json::Value& param1) = 0; virtual std::string eth_call(const Json::Value& param1) = 0;
@ -332,6 +361,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual int shh_newFilter(const Json::Value& param1) = 0; virtual int shh_newFilter(const Json::Value& param1) = 0;
virtual bool shh_uninstallFilter(int param1) = 0; virtual bool shh_uninstallFilter(int param1) = 0;
virtual Json::Value shh_changed(int param1) = 0; virtual Json::Value shh_changed(int param1) = 0;
virtual Json::Value shh_getMessages(int param1) = 0;
}; };
#endif //JSONRPC_CPP_STUB_ABSTRACTWEBTHREESTUBSERVER_H_ #endif //JSONRPC_CPP_STUB_ABSTRACTWEBTHREESTUBSERVER_H_

7
libweb3jsonrpc/spec.json

@ -18,6 +18,10 @@
{ "name": "eth_stateAt", "params": ["", ""], "order": [], "returns": ""}, { "name": "eth_stateAt", "params": ["", ""], "order": [], "returns": ""},
{ "name": "eth_storageAt", "params": [""], "order": [], "returns": {}}, { "name": "eth_storageAt", "params": [""], "order": [], "returns": {}},
{ "name": "eth_countAt", "params": [""], "order": [], "returns" : 0.0}, { "name": "eth_countAt", "params": [""], "order": [], "returns" : 0.0},
{ "name": "eth_transactionCountByHash", "params": [""], "order": [], "returns" : 0.0},
{ "name": "eth_transactionCountByNumber", "params": [0], "order": [], "returns" : 0.0},
{ "name": "eth_uncleCountByHash", "params": [""], "order": [], "returns" : 0.0},
{ "name": "eth_uncleCountByNumber", "params": [0], "order": [], "returns" : 0.0},
{ "name": "eth_codeAt", "params": [""], "order": [], "returns": ""}, { "name": "eth_codeAt", "params": [""], "order": [], "returns": ""},
{ "name": "eth_transact", "params": [{}], "order": [], "returns": ""}, { "name": "eth_transact", "params": [{}], "order": [], "returns": ""},
@ -59,6 +63,7 @@
{ "name": "shh_newFilter", "params": [{}], "order": [], "returns": 0}, { "name": "shh_newFilter", "params": [{}], "order": [], "returns": 0},
{ "name": "shh_uninstallFilter", "params": [0], "order": [], "returns": true}, { "name": "shh_uninstallFilter", "params": [0], "order": [], "returns": true},
{ "name": "shh_changed", "params": [0], "order": [], "returns": []} { "name": "shh_changed", "params": [0], "order": [], "returns": []},
{ "name": "shh_getMessages", "params": [0], "order": [], "returns": []}
] ]

2
libwebthree/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE webthree) set(EXECUTABLE webthree)

2
libwhisper/CMakeLists.txt

@ -11,7 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
set(EXECUTABLE whisper) set(EXECUTABLE whisper)

2
lllc/CMakeLists.txt

@ -3,8 +3,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE lllc) set(EXECUTABLE lllc)

4
mix/CMakeLists.txt

@ -11,8 +11,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
find_package (Qt5WebEngine QUIET) find_package (Qt5WebEngine QUIET)
qt5_add_resources(UI_RESOURCES res.qrc) qt5_add_resources(UI_RESOURCES res.qrc)
@ -71,4 +71,4 @@ eth_install_executable(${EXECUTABLE}
#add qml asnd stdc files to project tree in Qt creator #add qml asnd stdc files to project tree in Qt creator
file(GLOB_RECURSE QMLFILES "qml/*.*") file(GLOB_RECURSE QMLFILES "qml/*.*")
file(GLOB_RECURSE SOLFILES "stdc/*.*") file(GLOB_RECURSE SOLFILES "stdc/*.*")
add_custom_target(dummy SOURCES ${QMLFILES} ${SOLFILES}) add_custom_target(mix_qml SOURCES ${QMLFILES} ${SOLFILES})

70
mix/ClientModel.cpp

@ -65,7 +65,7 @@ private:
ClientModel::ClientModel(AppContext* _context): ClientModel::ClientModel(AppContext* _context):
m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address()) m_context(_context), m_running(false), m_rpcConnector(new RpcConnector())
{ {
qRegisterMetaType<QBigInt*>("QBigInt*"); qRegisterMetaType<QBigInt*>("QBigInt*");
qRegisterMetaType<QIntType*>("QIntType*"); qRegisterMetaType<QIntType*>("QIntType*");
@ -136,9 +136,12 @@ void ClientModel::mine()
}); });
} }
QString ClientModel::contractAddress() const QVariantMap ClientModel::contractAddresses() const
{ {
return QString::fromStdString(dev::toJS(m_contractAddress)); QVariantMap res;
for (auto const& c: m_contractAddresses)
res.insert(c.first, QString::fromStdString(dev::toJS(c.second)));
return res;
} }
void ClientModel::debugDeployment() void ClientModel::debugDeployment()
@ -155,8 +158,8 @@ void ClientModel::setupState(QVariantMap _state)
for (auto const& t: transactions) for (auto const& t: transactions)
{ {
QVariantMap transaction = t.toMap(); QVariantMap transaction = t.toMap();
QString contractId = transaction.value("contractId").toString();
QString functionId = transaction.value("functionId").toString(); QString functionId = transaction.value("functionId").toString();
u256 gas = boost::get<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue()); u256 gas = boost::get<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue());
u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei(); u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei();
u256 gasPrice = (qvariant_cast<QEther*>(transaction.value("gasPrice")))->toU256Wei(); u256 gasPrice = (qvariant_cast<QEther*>(transaction.value("gasPrice")))->toU256Wei();
@ -164,7 +167,9 @@ void ClientModel::setupState(QVariantMap _state)
bool isStdContract = (transaction.value("stdContract").toBool()); bool isStdContract = (transaction.value("stdContract").toBool());
if (isStdContract) if (isStdContract)
{ {
TransactionSettings transactionSettings(functionId, transaction.value("url").toString()); if (contractId.isEmpty()) //TODO: This is to support old project files, remove later
contractId = functionId;
TransactionSettings transactionSettings(contractId, transaction.value("url").toString());
transactionSettings.gasPrice = 10000000000000; transactionSettings.gasPrice = 10000000000000;
transactionSettings.gas = 125000; transactionSettings.gas = 125000;
transactionSettings.value = 0; transactionSettings.value = 0;
@ -172,8 +177,10 @@ void ClientModel::setupState(QVariantMap _state)
} }
else else
{ {
if (contractId.isEmpty() && m_context->codeModel()->hasContract()) //TODO: This is to support old project files, remove later
contractId = m_context->codeModel()->contracts().keys()[0];
QVariantList qParams = transaction.value("qType").toList(); QVariantList qParams = transaction.value("qType").toList();
TransactionSettings transactionSettings(functionId, value, gas, gasPrice); TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice);
for (QVariant const& variant: qParams) for (QVariant const& variant: qParams)
{ {
@ -181,7 +188,7 @@ void ClientModel::setupState(QVariantMap _state)
transactionSettings.parameterValues.push_back(param); transactionSettings.parameterValues.push_back(param);
} }
if (transaction.value("executeConstructor").toBool()) if (contractId == functionId || functionId == "Constructor")
transactionSettings.functionId.clear(); transactionSettings.functionId.clear();
transactionSequence.push_back(transactionSettings); transactionSequence.push_back(transactionSettings);
@ -194,8 +201,6 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
{ {
if (m_running) if (m_running)
BOOST_THROW_EXCEPTION(ExecutionStateException()); BOOST_THROW_EXCEPTION(ExecutionStateException());
CompilationResult* compilerRes = m_context->codeModel()->code();
std::shared_ptr<QContractDefinition> contractDef = compilerRes->sharedContract();
m_running = true; m_running = true;
emit runStarted(); emit runStarted();
@ -206,25 +211,26 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
{ {
try try
{ {
bytes contractCode = compilerRes->bytes();
m_client->resetState(_balance); m_client->resetState(_balance);
onStateReset(); onStateReset();
for (TransactionSettings const& transaction: _sequence) for (TransactionSettings const& transaction: _sequence)
{ {
ContractCallDataEncoder encoder; ContractCallDataEncoder encoder;
QFunctionDefinition const* f = nullptr;
if (!transaction.stdContractUrl.isEmpty()) if (!transaction.stdContractUrl.isEmpty())
{ {
//std contract //std contract
dev::bytes const& stdContractCode = m_context->codeModel()->getStdContractCode(transaction.functionId, transaction.stdContractUrl); dev::bytes const& stdContractCode = m_context->codeModel()->getStdContractCode(transaction.contractId, transaction.stdContractUrl);
Address address = deployContract(stdContractCode, transaction); Address address = deployContract(stdContractCode, transaction);
m_stdContractAddresses[transaction.functionId] = address; m_stdContractAddresses[transaction.contractId] = address;
m_stdContractNames[address] = transaction.functionId; m_stdContractNames[address] = transaction.contractId;
} }
else else
{ {
//encode data //encode data
f = nullptr; CompiledContract const& compilerRes = m_context->codeModel()->contract(transaction.contractId);
QFunctionDefinition const* f = nullptr;
bytes contractCode = compilerRes.bytes();
std::shared_ptr<QContractDefinition> contractDef = compilerRes.sharedContract();
if (transaction.functionId.isEmpty()) if (transaction.functionId.isEmpty())
f = contractDef->constructor(); f = contractDef->constructor();
else else
@ -240,24 +246,31 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
encoder.encode(f); encoder.encode(f);
for (int p = 0; p < transaction.parameterValues.size(); p++) for (int p = 0; p < transaction.parameterValues.size(); p++)
{ {
if (f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type()) if (f->parametersList().size() <= p || f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type())
BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(f->parametersList().at(p)->type().toStdString())); BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(transaction.functionId.toStdString()));
encoder.push(transaction.parameterValues.at(p)->encodeValue()); encoder.push(transaction.parameterValues.at(p)->encodeValue());
} }
if (transaction.functionId.isEmpty()) if (transaction.functionId.isEmpty() || transaction.functionId == transaction.contractId)
{ {
bytes param = encoder.encodedData(); bytes param = encoder.encodedData();
contractCode.insert(contractCode.end(), param.begin(), param.end()); contractCode.insert(contractCode.end(), param.begin(), param.end());
Address newAddress = deployContract(contractCode, transaction); Address newAddress = deployContract(contractCode, transaction);
if (newAddress != m_contractAddress) auto contractAddressIter = m_contractAddresses.find(transaction.contractId);
if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second)
{ {
m_contractAddress = newAddress; m_contractAddresses[transaction.contractId] = newAddress;
contractAddressChanged(); m_contractNames[newAddress] = transaction.contractId;
contractAddressesChanged();
} }
} }
else else
callContract(m_contractAddress, encoder.encodedData(), transaction); {
auto contractAddressIter = m_contractAddresses.find(transaction.contractId);
if (contractAddressIter == m_contractAddresses.end())
BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Contract not deployed: " + transaction.contractId.toStdString()));
callContract(contractAddressIter->second, encoder.encodedData(), transaction);
}
} }
onNewTransaction(); onNewTransaction();
} }
@ -338,7 +351,8 @@ void ClientModel::callContract(Address const& _contract, bytes const& _data, Tra
void ClientModel::onStateReset() void ClientModel::onStateReset()
{ {
m_contractAddress = dev::Address(); m_contractAddresses.clear();
m_contractNames.clear();
m_stdContractAddresses.clear(); m_stdContractAddresses.clear();
m_stdContractNames.clear(); m_stdContractNames.clear();
emit stateCleared(); emit stateCleared();
@ -389,14 +403,16 @@ void ClientModel::onNewTransaction()
if (creation) if (creation)
returned = QString::fromStdString(toJS(tr.contractAddress)); returned = QString::fromStdString(toJS(tr.contractAddress));
if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress)) Address contractAddress = tr.address != 0 ? tr.address : tr.contractAddress;
auto contractAddressIter = m_contractNames.find(contractAddress);
if (contractAddressIter != m_contractNames.end())
{ {
auto compilerRes = m_context->codeModel()->code(); CompiledContract const& compilerRes = m_context->codeModel()->contract(contractAddressIter->second);
QContractDefinition* def = compilerRes->contract(); const QContractDefinition* def = compilerRes.contract();
contract = def->name(); contract = def->name();
if (abi) if (abi)
{ {
QFunctionDefinition* funcDef = def->getFunction(functionHash); QFunctionDefinition const* funcDef = def->getFunction(functionHash);
if (funcDef) if (funcDef)
{ {
function = funcDef->name(); function = funcDef->name();

21
mix/ClientModel.h

@ -46,13 +46,13 @@ class QVariableDefinition;
struct TransactionSettings struct TransactionSettings
{ {
TransactionSettings() {} TransactionSettings() {}
TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice):
functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {}
TransactionSettings(u256 _value, u256 _gas, u256 _gasPrice):
value(_value), gas(_gas), gasPrice(_gasPrice) {}
TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl):
functionId(_stdContractName), stdContractUrl(_stdContractUrl) {} contractId(_stdContractName), stdContractUrl(_stdContractUrl) {}
/// Contract name
QString contractId;
/// Contract function name /// Contract function name
QString functionId; QString functionId;
/// Transaction value /// Transaction value
@ -121,8 +121,8 @@ public:
Q_PROPERTY(bool running MEMBER m_running NOTIFY runStateChanged) Q_PROPERTY(bool running MEMBER m_running NOTIFY runStateChanged)
/// @returns true if currently mining /// @returns true if currently mining
Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged) Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged)
/// @returns address of the last executed contract /// @returns deployed contracts addresses
Q_PROPERTY(QString contractAddress READ contractAddress NOTIFY contractAddressChanged) Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged)
/// ethereum.js RPC request entry point /// ethereum.js RPC request entry point
/// @param _message RPC request in Json format /// @param _message RPC request in Json format
/// @returns RPC response in Json format /// @returns RPC response in Json format
@ -161,7 +161,7 @@ signals:
/// @param _message Error message /// @param _message Error message
void runFailed(QString const& _message); void runFailed(QString const& _message);
/// Contract address changed /// Contract address changed
void contractAddressChanged(); void contractAddressesChanged();
/// Execution state changed /// Execution state changed
void newBlock(); void newBlock();
/// Execution state changed /// Execution state changed
@ -177,7 +177,7 @@ signals:
void stateCleared(); void stateCleared();
private: private:
QString contractAddress() const; QVariantMap contractAddresses() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance); void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
@ -191,7 +191,8 @@ private:
std::unique_ptr<MixClient> m_client; std::unique_ptr<MixClient> m_client;
std::unique_ptr<RpcConnector> m_rpcConnector; std::unique_ptr<RpcConnector> m_rpcConnector;
std::unique_ptr<Web3Server> m_web3Server; std::unique_ptr<Web3Server> m_web3Server;
Address m_contractAddress; std::map<QString, Address> m_contractAddresses;
std::map<Address, QString> m_contractNames;
std::map<QString, Address> m_stdContractAddresses; std::map<QString, Address> m_stdContractAddresses;
std::map<Address, QString> m_stdContractNames; std::map<Address, QString> m_stdContractNames;
}; };

2
mix/CodeHighlighter.cpp

@ -119,7 +119,7 @@ void CodeHighlighter::processComments(std::string const& _source)
//add single line comment //add single line comment
int start = i; int start = i;
i += 2; i += 2;
while (_source[i] != '\n' && i < size) while (i < size && _source[i] != '\n')
++i; ++i;
m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start)); m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start));
} }

213
mix/CodeModel.cpp

@ -21,6 +21,7 @@
*/ */
#include <sstream> #include <sstream>
#include <memory>
#include <QDebug> #include <QDebug>
#include <QApplication> #include <QApplication>
#include <QtQml> #include <QtQml>
@ -38,51 +39,31 @@
using namespace dev::mix; using namespace dev::mix;
void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) const std::set<std::string> c_predefinedContracts =
{ "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" };
void BackgroundWorker::queueCodeChange(int _jobId)
{ {
m_model->runCompilationJob(_jobId, _content); m_model->runCompilationJob(_jobId);
} }
CompilationResult::CompilationResult(): CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler, QString const& _contractName, QString const& _source):
QObject(nullptr),
m_successful(false),
m_codeHash(qHash(QString())),
m_contract(new QContractDefinition()),
m_contractInterface("[]"),
m_codeHighlighter(new CodeHighlighter())
{}
CompilationResult::CompilationResult(const dev::solidity::CompilerStack& _compiler):
QObject(nullptr), QObject(nullptr),
m_successful(true), m_sourceHash(qHash(_source))
m_codeHash(qHash(QString()))
{ {
if (!_compiler.getContractNames().empty()) auto const& contractDefinition = _compiler.getContractDefinition(_contractName.toStdString());
{ m_contract.reset(new QContractDefinition(&contractDefinition));
auto const& contractDefinition = _compiler.getContractDefinition(std::string()); QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership);
m_contract.reset(new QContractDefinition(&contractDefinition)); m_bytes = _compiler.getBytecode(_contractName.toStdString());
m_bytes = _compiler.getBytecode(); dev::solidity::InterfaceHandler interfaceHandler;
dev::solidity::InterfaceHandler interfaceHandler; m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition));
m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition)); if (m_contractInterface.isEmpty())
if (m_contractInterface.isEmpty()) m_contractInterface = "[]";
m_contractInterface = "[]"; if (contractDefinition.getLocation().sourceName.get())
} m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName);
else
m_contract.reset(new QContractDefinition());
} }
CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): QString CompiledContract::codeHex() const
QObject(nullptr),
m_successful(false),
m_codeHash(qHash(QString())),
m_contract(_prev.m_contract),
m_compilerMessage(_compilerMessage),
m_bytes(_prev.m_bytes),
m_contractInterface(_prev.m_contractInterface),
m_codeHighlighter(_prev.m_codeHighlighter)
{}
QString CompilationResult::codeHex() const
{ {
return QString::fromStdString(toJS(m_bytes)); return QString::fromStdString(toJS(m_bytes));
} }
@ -90,27 +71,26 @@ QString CompilationResult::codeHex() const
CodeModel::CodeModel(QObject* _parent): CodeModel::CodeModel(QObject* _parent):
QObject(_parent), QObject(_parent),
m_compiling(false), m_compiling(false),
m_result(new CompilationResult()),
m_codeHighlighterSettings(new CodeHighlighterSettings()), m_codeHighlighterSettings(new CodeHighlighterSettings()),
m_backgroundWorker(this), m_backgroundWorker(this),
m_backgroundJobId(0) m_backgroundJobId(0)
{ {
m_backgroundThread.start();
m_backgroundWorker.moveToThread(&m_backgroundThread); m_backgroundWorker.moveToThread(&m_backgroundThread);
connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection);
connect(this, &CodeModel::compilationCompleteInternal, this, &CodeModel::onCompilationComplete, Qt::QueuedConnection); qRegisterMetaType<CompiledContract*>("CompiledContract*");
qRegisterMetaType<CompilationResult*>("CompilationResult*");
qRegisterMetaType<QContractDefinition*>("QContractDefinition*"); qRegisterMetaType<QContractDefinition*>("QContractDefinition*");
qRegisterMetaType<QFunctionDefinition*>("QFunctionDefinition*"); qRegisterMetaType<QFunctionDefinition*>("QFunctionDefinition*");
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*"); qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
qmlRegisterType<QFunctionDefinition>("org.ethereum.qml", 1, 0, "QFunctionDefinition"); qmlRegisterType<QFunctionDefinition>("org.ethereum.qml", 1, 0, "QFunctionDefinition");
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml", 1, 0, "QVariableDeclaration"); qmlRegisterType<QVariableDeclaration>("org.ethereum.qml", 1, 0, "QVariableDeclaration");
m_backgroundThread.start();
} }
CodeModel::~CodeModel() CodeModel::~CodeModel()
{ {
stop(); stop();
disconnect(this); disconnect(this);
releaseContracts();
} }
void CodeModel::stop() void CodeModel::stop()
@ -120,80 +100,133 @@ void CodeModel::stop()
m_backgroundThread.wait(); m_backgroundThread.wait();
} }
void CodeModel::registerCodeChange(QString const& _code) void CodeModel::reset(QVariantMap const& _documents)
{ {
///@todo: cancel bg job
Guard l(x_contractMap);
releaseContracts();
Guard pl(x_pendingContracts);
m_pendingContracts.clear();
for (QVariantMap::const_iterator d = _documents.cbegin(); d != _documents.cend(); ++d)
m_pendingContracts[d.key()] = d.value().toString();
// launch the background thread // launch the background thread
uint hash = qHash(_code);
if (m_result->m_codeHash == hash)
return;
m_backgroundJobId++;
m_compiling = true; m_compiling = true;
emit stateChanged(); emit stateChanged();
emit scheduleCompilationJob(m_backgroundJobId, _code); emit scheduleCompilationJob(++m_backgroundJobId);
} }
void CodeModel::runCompilationJob(int _jobId, QString const& _code) void CodeModel::registerCodeChange(QString const& _documentId, QString const& _code)
{ {
if (_jobId != m_backgroundJobId) {
return; //obsolete job Guard l(x_contractMap);
CompiledContract* contract = m_contractMap.value(_documentId);
if (contract != nullptr && contract->m_sourceHash == qHash(_code))
return;
solidity::CompilerStack cs(true); Guard pl(x_pendingContracts);
std::unique_ptr<CompilationResult> result; m_pendingContracts[_documentId] = _code;
}
// launch the background thread
m_compiling = true;
emit stateChanged();
emit scheduleCompilationJob(++m_backgroundJobId);
}
QVariantMap CodeModel::contracts() const
{
QVariantMap result;
Guard l(x_contractMap);
for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); ++c)
result.insert(c.key(), QVariant::fromValue(c.value()));
return result;
}
std::string source = _code.toStdString(); CompiledContract* CodeModel::contractByDocumentId(QString _documentId) const
// run syntax highlighting first {
// @todo combine this with compilation step Guard l(x_contractMap);
auto codeHighlighter = std::make_shared<CodeHighlighter>(); for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); ++c)
codeHighlighter->processSource(source); if (c.value()->m_documentId == _documentId)
return c.value();
return nullptr;
}
CompiledContract const& CodeModel::contract(QString _name) const
{
Guard l(x_contractMap);
CompiledContract* res = m_contractMap.value(_name);
if (res == nullptr)
BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Contract not found: " + _name.toStdString()));
return *res;
}
cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})"); void CodeModel::releaseContracts()
{
for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); ++c)
c.value()->deleteLater();
m_contractMap.clear();
}
void CodeModel::runCompilationJob(int _jobId)
{
if (_jobId != m_backgroundJobId)
return; //obsolete job
// run compilation ContractMap result;
solidity::CompilerStack cs(true);
try try
{ {
cs.addSource("", source); cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})");
{
Guard l(x_pendingContracts);
for (auto const& c: m_pendingContracts)
cs.addSource(c.first.toStdString(), c.second.toStdString());
}
cs.compile(false); cs.compile(false);
codeHighlighter->processAST(cs.getAST());
result.reset(new CompilationResult(cs)); {
qDebug() << QString(QApplication::tr("compilation succeeded")); Guard pl(x_pendingContracts);
Guard l(x_contractMap);
for (std::string n: cs.getContractNames())
{
if (c_predefinedContracts.count(n) != 0)
continue;
QString name = QString::fromStdString(n);
auto sourceIter = m_pendingContracts.find(name);
QString source = sourceIter != m_pendingContracts.end() ? sourceIter->second : QString();
CompiledContract* contract = new CompiledContract(cs, name, source);
QQmlEngine::setObjectOwnership(contract, QQmlEngine::CppOwnership);
result[name] = contract;
CompiledContract* prevContract = m_contractMap.value(name);
if (prevContract != nullptr && prevContract->contractInterface() != result[name]->contractInterface())
emit contractInterfaceChanged(name);
}
releaseContracts();
m_contractMap.swap(result);
emit codeChanged();
emit compilationComplete();
}
} }
catch (dev::Exception const& _exception) catch (dev::Exception const& _exception)
{ {
std::ostringstream error; std::ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs);
result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); solidity::Location const* location = boost::get_error_info<solidity::errinfo_sourceLocation>(_exception);
codeHighlighter->processError(_exception); QString message = QString::fromStdString(error.str());
qDebug() << QString(QApplication::tr("compilation failed:") + " " + result->compilerMessage()); CompiledContract* contract = nullptr;
if (location && location->sourceName.get() && (contract = contractByDocumentId(QString::fromStdString(*location->sourceName))))
message = message.replace(QString::fromStdString(*location->sourceName), contract->contract()->name()); //substitute the location to match our contract names
compilationError(message);
} }
result->m_codeHighlighter = codeHighlighter;
result->m_codeHash = qHash(_code);
emit compilationCompleteInternal(result.release());
}
void CodeModel::onCompilationComplete(CompilationResult* _newResult)
{
m_compiling = false; m_compiling = false;
bool contractChanged = m_result->contractInterface() != _newResult->contractInterface();
m_result.reset(_newResult);
emit compilationComplete();
emit stateChanged(); emit stateChanged();
if (m_result->successful())
{
emit codeChanged();
if (contractChanged)
emit contractInterfaceChanged();
}
} }
bool CodeModel::hasContract() const bool CodeModel::hasContract() const
{ {
return m_result->successful(); Guard l(x_contractMap);
} return m_contractMap.size() != 0;
void CodeModel::updateFormatting(QTextDocument* _document)
{
m_result->codeHighlighter()->updateFormatting(_document, *m_codeHighlighterSettings);
} }
dev::bytes const& CodeModel::getStdContractCode(const QString& _contractName, const QString& _url) dev::bytes const& CodeModel::getStdContractCode(const QString& _contractName, const QString& _url)

76
mix/CodeModel.h

@ -27,7 +27,9 @@
#include <map> #include <map>
#include <QObject> #include <QObject>
#include <QThread> #include <QThread>
#include <QHash>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
class QTextDocument; class QTextDocument;
@ -56,59 +58,50 @@ public:
BackgroundWorker(CodeModel* _model): QObject(), m_model(_model) {} BackgroundWorker(CodeModel* _model): QObject(), m_model(_model) {}
public slots: public slots:
void queueCodeChange(int _jobId, QString const& _content); void queueCodeChange(int _jobId);
private: private:
CodeModel* m_model; CodeModel* m_model;
}; };
///Compilation result model. Contains all the compiled contract data required by UI ///Compilation result model. Contains all the compiled contract data required by UI
class CompilationResult: public QObject class CompiledContract: public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QContractDefinition* contract READ contract) Q_PROPERTY(QContractDefinition* contract READ contract)
Q_PROPERTY(QString compilerMessage READ compilerMessage CONSTANT)
Q_PROPERTY(bool successful READ successful CONSTANT)
Q_PROPERTY(QString contractInterface READ contractInterface CONSTANT) Q_PROPERTY(QString contractInterface READ contractInterface CONSTANT)
Q_PROPERTY(QString codeHex READ codeHex CONSTANT) Q_PROPERTY(QString codeHex READ codeHex CONSTANT)
Q_PROPERTY(QString documentId MEMBER m_documentId CONSTANT)
public: public:
/// Empty compilation result constructor
CompilationResult();
/// Successful compilation result constructor /// Successful compilation result constructor
CompilationResult(solidity::CompilerStack const& _compiler); CompiledContract(solidity::CompilerStack const& _compiler, QString const& _contractName, QString const& _source);
/// Failed compilation result constructor
CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage);
/// @returns contract definition for QML property /// @returns contract definition for QML property
QContractDefinition* contract() { return m_contract.get(); } QContractDefinition* contract() const { return m_contract.get(); }
/// @returns contract definition /// @returns contract definition
std::shared_ptr<QContractDefinition> sharedContract() { return m_contract; } std::shared_ptr<QContractDefinition> sharedContract() const { return m_contract; }
/// Indicates if the compilation was successful
bool successful() const { return m_successful; }
/// @returns compiler error message in case of unsuccessful compilation
QString compilerMessage() const { return m_compilerMessage; }
/// @returns contract bytecode /// @returns contract bytecode
dev::bytes const& bytes() const { return m_bytes; } dev::bytes const& bytes() const { return m_bytes; }
/// @returns contract bytecode as hex string /// @returns contract bytecode as hex string
QString codeHex() const; QString codeHex() const;
/// @returns contract definition in JSON format /// @returns contract definition in JSON format
QString contractInterface() const { return m_contractInterface; } QString contractInterface() const { return m_contractInterface; }
/// Get code highlighter
std::shared_ptr<CodeHighlighter> codeHighlighter() { return m_codeHighlighter; }
private: private:
bool m_successful; uint m_sourceHash;
uint m_codeHash;
std::shared_ptr<QContractDefinition> m_contract; std::shared_ptr<QContractDefinition> m_contract;
QString m_compilerMessage; ///< @todo: use some structure here QString m_compilerMessage; ///< @todo: use some structure here
dev::bytes m_bytes; dev::bytes m_bytes;
QString m_contractInterface; QString m_contractInterface;
std::shared_ptr<CodeHighlighter> m_codeHighlighter; QString m_documentId;
friend class CodeModel; friend class CodeModel;
}; };
/// Background code compiler
using ContractMap = QHash<QString, CompiledContract*>;
/// Code compilation model. Compiles contracts in background an provides compiled contract data
class CodeModel: public QObject class CodeModel: public QObject
{ {
Q_OBJECT Q_OBJECT
@ -117,56 +110,59 @@ public:
CodeModel(QObject* _parent); CodeModel(QObject* _parent);
~CodeModel(); ~CodeModel();
/// @returns latest compilation result Q_PROPERTY(QVariantMap contracts READ contracts NOTIFY codeChanged)
CompilationResult* code() { return m_result.get(); }
/// @returns latest compilation resul
CompilationResult const* code() const { return m_result.get(); }
Q_PROPERTY(CompilationResult* code READ code NOTIFY codeChanged)
Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged) Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged)
Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged) Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged)
/// @returns latest compilation results for contracts
QVariantMap contracts() const;
/// @returns compilation status /// @returns compilation status
bool isCompiling() const { return m_compiling; } bool isCompiling() const { return m_compiling; }
/// @returns true if contract has at least one function /// @returns true there is a contract which has at least one function
bool hasContract() const; bool hasContract() const;
/// Apply text document formatting. @todo Move this to editor module
void updateFormatting(QTextDocument* _document);
/// Get contract code by url. Contract is compiled on first access and cached /// Get contract code by url. Contract is compiled on first access and cached
dev::bytes const& getStdContractCode(QString const& _contractName, QString const& _url); dev::bytes const& getStdContractCode(QString const& _contractName, QString const& _url);
/// Get contract by name
CompiledContract const& contract(QString _name) const;
/// Find a contract by document id
/// @returns CompiledContract object or null if not found
Q_INVOKABLE CompiledContract* contractByDocumentId(QString _documentId) const;
signals: signals:
/// Emited on compilation state change /// Emited on compilation state change
void stateChanged(); void stateChanged();
/// Emitted on compilation complete /// Emitted on compilation complete
void compilationComplete(); void compilationComplete();
/// Emitted on compilation error
void compilationError(QString _error);
/// Internal signal used to transfer compilation job to background thread /// Internal signal used to transfer compilation job to background thread
void scheduleCompilationJob(int _jobId, QString const& _content); void scheduleCompilationJob(int _jobId);
/// Emitted if there are any changes in the code model /// Emitted if there are any changes in the code model
void codeChanged(); void codeChanged();
/// Emitted if there are any changes in the contract interface /// Emitted if there are any changes in the contract interface
void contractInterfaceChanged(); void contractInterfaceChanged(QString _documentId);
/// Emitted on compilation complete. Internal
void compilationCompleteInternal(CompilationResult* _newResult);
private slots:
void onCompilationComplete(CompilationResult* _newResult);
public slots: public slots:
/// Update code model on source code change /// Update code model on source code change
void registerCodeChange(QString const& _code); void registerCodeChange(QString const& _documentId, QString const& _code);
/// Reset code model for a new project
void reset(QVariantMap const& _documents);
private: private:
void runCompilationJob(int _jobId, QString const& _content); void runCompilationJob(int _jobId);
void stop(); void stop();
void releaseContracts();
std::atomic<bool> m_compiling; std::atomic<bool> m_compiling;
std::unique_ptr<CompilationResult> m_result; mutable dev::Mutex x_contractMap;
ContractMap m_contractMap;
std::unique_ptr<CodeHighlighterSettings> m_codeHighlighterSettings; std::unique_ptr<CodeHighlighterSettings> m_codeHighlighterSettings;
QThread m_backgroundThread; QThread m_backgroundThread;
BackgroundWorker m_backgroundWorker; BackgroundWorker m_backgroundWorker;
int m_backgroundJobId = 0; //protects from starting obsolete compilation job int m_backgroundJobId = 0; //protects from starting obsolete compilation job
std::map<QString, dev::bytes> m_compiledContracts; //by name std::map<QString, dev::bytes> m_compiledContracts; //by name
dev::Mutex x_pendingContracts;
std::map<QString, QString> m_pendingContracts; //name to source
friend class BackgroundWorker; friend class BackgroundWorker;
}; };

2
mix/ContractCallDataEncoder.cpp

@ -56,7 +56,7 @@ QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDecla
QList<QVariableDefinition*> r; QList<QVariableDefinition*> r;
for (int k = 0; k <_returnParameters.length(); k++) for (int k = 0; k <_returnParameters.length(); k++)
{ {
QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k); QVariableDeclaration* dec = static_cast<QVariableDeclaration*>(_returnParameters.at(k));
QVariableDefinition* def = nullptr; QVariableDefinition* def = nullptr;
if (dec->type().contains("int")) if (dec->type().contains("int"))
def = new QIntType(dec, QString()); def = new QIntType(dec, QString());

18
mix/MixClient.cpp

@ -117,8 +117,8 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
unsigned dataIndex = 0; unsigned dataIndex = 0;
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt)
{ {
VM& vm = *(VM*)voidVM; VM& vm = *static_cast<VM*>(voidVM);
ExtVM const& ext = *(ExtVM const*)voidExt; ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
if (lastCode == nullptr || lastCode != &ext.code) if (lastCode == nullptr || lastCode != &ext.code)
{ {
auto const& iter = codeIndexes.find(&ext.code); auto const& iter = codeIndexes.find(&ext.code);
@ -463,6 +463,20 @@ eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const
return BlockInfo(); return BlockInfo();
} }
unsigned MixClient::transactionCount(h256 _blockHash) const
{
auto bl = bc().block(_blockHash);
RLP b(bl);
return b[1].itemCount();
}
unsigned MixClient::uncleCount(h256 _blockHash) const
{
auto bl = bc().block(_blockHash);
RLP b(bl);
return b[2].itemCount();
}
unsigned MixClient::number() const unsigned MixClient::number() const
{ {
return bc().number(); return bc().number();

2
mix/MixClient.h

@ -71,6 +71,8 @@ public:
eth::BlockDetails blockDetails(h256 _hash) const override; eth::BlockDetails blockDetails(h256 _hash) const override;
eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; eth::Transaction transaction(h256 _blockHash, unsigned _i) const override;
eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override;
unsigned transactionCount(h256 _blockHash) const override;
unsigned uncleCount(h256 _blockHash) const override;
unsigned number() const override; unsigned number() const override;
eth::Transactions pending() const override; eth::Transactions pending() const override;
eth::StateDiff diff(unsigned _txi, h256 _block) const override; eth::StateDiff diff(unsigned _txi, h256 _block) const override;

2
mix/QContractDefinition.cpp

@ -42,7 +42,7 @@ QContractDefinition::QContractDefinition(dev::solidity::ContractDefinition const
m_functions.append(new QFunctionDefinition(it.second));} m_functions.append(new QFunctionDefinition(it.second));}
QFunctionDefinition* QContractDefinition::getFunction(dev::FixedHash<4> _hash) QFunctionDefinition const* QContractDefinition::getFunction(dev::FixedHash<4> _hash) const
{ {
for (auto const& f: m_functions) for (auto const& f: m_functions)
if (f->hash() == _hash) if (f->hash() == _hash)

2
mix/QContractDefinition.h

@ -47,7 +47,7 @@ public:
QFunctionDefinition* constructor() const { return m_constructor; } QFunctionDefinition* constructor() const { return m_constructor; }
QList<QFunctionDefinition*> const& functionsList() const { return m_functions; } QList<QFunctionDefinition*> const& functionsList() const { return m_functions; }
/// Find function by hash, returns nullptr if not found /// Find function by hash, returns nullptr if not found
QFunctionDefinition* getFunction(dev::FixedHash<4> _hash); QFunctionDefinition const* getFunction(dev::FixedHash<4> _hash) const;
private: private:
QList<QFunctionDefinition*> m_functions; QList<QFunctionDefinition*> m_functions;
QFunctionDefinition* m_constructor; QFunctionDefinition* m_constructor;

4
mix/QVariableDefinition.h

@ -135,8 +135,8 @@ class QBoolType: public QVariableDefinition
Q_OBJECT Q_OBJECT
public: public:
QBoolType() {} QBoolType(): m_boolValue(false) {}
QBoolType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {} QBoolType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value), m_boolValue(false) {}
dev::bytes encodeValue() override; dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override; void decodeValue(dev::bytes const& _rawValue) override;
/// @returns the boolean value for the current definition. /// @returns the boolean value for the current definition.

11
mix/StatusPane.cpp

@ -36,7 +36,6 @@ using namespace dev::mix;
StatusPane::StatusPane(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::HeaderView) StatusPane::StatusPane(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::HeaderView)
{ {
connect(_context->codeModel(), &CodeModel::compilationComplete, this, &StatusPane::update);
_context->appEngine()->rootContext()->setContextProperty("statusPane", this); _context->appEngine()->rootContext()->setContextProperty("statusPane", this);
} }
@ -54,13 +53,3 @@ void StatusPane::start() const
{ {
} }
CompilationResult* StatusPane::result() const
{
return m_ctx->codeModel()->code();
}
void StatusPane::update()
{
QObject* ctrl = m_view->findChild<QObject*>("statusPane", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(ctrl, "updateStatus");
}

4
mix/StatusPane.h

@ -20,7 +20,6 @@
#pragma once #pragma once
#include "Extension.h" #include "Extension.h"
#include "CodeModel.h"
namespace dev namespace dev
{ {
@ -33,7 +32,6 @@ namespace mix
class StatusPane: public Extension class StatusPane: public Extension
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(CompilationResult* result READ result CONSTANT)
public: public:
StatusPane(AppContext* _appContext); StatusPane(AppContext* _appContext);
@ -41,10 +39,8 @@ public:
void start() const override; void start() const override;
QString title() const override; QString title() const override;
QString contentUrl() const override; QString contentUrl() const override;
CompilationResult* result() const;
public slots: public slots:
void update();
}; };
} }

4
mix/main.cpp

@ -36,6 +36,10 @@ int main(int _argc, char* _argv[])
//https://bugs.launchpad.net/ubuntu/+source/appmenu-qt5/+bug/1323853 //https://bugs.launchpad.net/ubuntu/+source/appmenu-qt5/+bug/1323853
putenv((char*)"QT_QPA_PLATFORMTHEME="); putenv((char*)"QT_QPA_PLATFORMTHEME=");
putenv((char*)"QSG_RENDER_LOOP=threaded"); putenv((char*)"QSG_RENDER_LOOP=threaded");
#endif
#if (defined(_WIN32) || defined(_WIN64))
if (!getenv("OPENSSL_CONF"))
putenv((char*)"OPENSSL_CONF=c:\\");
#endif #endif
try try
{ {

2
mix/qml/CodeEditorView.qml

@ -43,7 +43,7 @@ Item {
editor.onEditorTextChanged.connect(function() { editor.onEditorTextChanged.connect(function() {
documentEdit(document.documentId); documentEdit(document.documentId);
if (document.isContract) if (document.isContract)
codeModel.registerCodeChange(editor.getText()); codeModel.registerCodeChange(document.documentId, editor.getText());
}); });
editor.setText(data, document.syntaxMode); editor.setText(data, document.syntaxMode);
} }

9
mix/qml/Debugger.qml

@ -25,7 +25,7 @@ Rectangle {
function update(data, giveFocus) function update(data, giveFocus)
{ {
if (statusPane && statusPane.result.successful) if (statusPane && codeModel.hasContract)
{ {
Debugger.init(data); Debugger.init(data);
debugScrollArea.visible = true; debugScrollArea.visible = true;
@ -131,7 +131,14 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.minimumHeight: 60 Layout.minimumHeight: 60
height: 250 height: 250
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: machineStates.sideMargin
anchors.rightMargin: machineStates.sideMargin
anchors.topMargin: machineStates.sideMargin
} }
ScrollView ScrollView
{ {
property int sideMargin: 10 property int sideMargin: 10

6
mix/qml/DefaultLabel.qml

@ -4,12 +4,6 @@ import "."
Label { Label {
text: text text: text
font.family: regularFont.name
font.pointSize: Style.generic.size.titlePointSize
SourceSansProLight
{
id: regularFont
}
} }

7
mix/qml/DefaultTextField.qml

@ -3,11 +3,4 @@ import QtQuick.Controls 1.1
TextField { TextField {
id: titleField id: titleField
focus: true
font.family: regularFont.name
SourceSansProRegular
{
id: regularFont;
}
} }

8
mix/qml/Ether.qml

@ -49,10 +49,6 @@ RowLayout {
id: etherValueEdit; id: etherValueEdit;
} }
SourceSansProBold {
id: regularFont;
}
ComboBox ComboBox
{ {
id: units id: units
@ -87,15 +83,11 @@ RowLayout {
ListElement { text: "Kwei"; } ListElement { text: "Kwei"; }
ListElement { text: "wei"; } ListElement { text: "wei"; }
} }
style: ComboBoxStyle {
font: regularFont.name
}
} }
Text Text
{ {
visible: displayFormattedValue visible: displayFormattedValue
id: formattedValue id: formattedValue
font.family: regularFont.name
} }
} }

2
mix/qml/MainContent.qml

@ -34,7 +34,7 @@ Rectangle {
onCompilationComplete: { onCompilationComplete: {
if (firstCompile) { if (firstCompile) {
firstCompile = false; firstCompile = false;
if (codeModel.code.successful && runOnProjectLoad) if (runOnProjectLoad)
startQuickDebugging(); startQuickDebugging();
} }
} }

21
mix/qml/ProjectList.qml

@ -101,14 +101,19 @@ Item {
Connections { Connections {
target: codeModel target: codeModel
onCompilationComplete: { onCompilationComplete: {
if (modelData === "Contracts") if (modelData === "Contracts") {
{ var ci = 0;
var ctr = projectModel.listModel.get(0); for (var si = 0; si < projectModel.listModel.count; si++) {
if (codeModel.code.contract.name !== ctr.name) var document = projectModel.listModel.get(si);
{ if (document.isContract) {
ctr.name = codeModel.code.contract.name; var compiledDoc = codeModel.contractByDocumentId(document.documentId);
projectModel.listModel.set(0, ctr); if (compiledDoc && compiledDoc.documentId === document.documentId && compiledDoc.contract.name !== document.name) {
sectionModel.set(0, ctr); document.name = compiledDoc.contract.name;
projectModel.listModel.set(si, document);
sectionModel.set(ci, document);
}
ci++;
}
} }
} }
} }

2
mix/qml/ProjectModel.qml

@ -45,7 +45,7 @@ Item {
function newHtmlFile() { ProjectModelCode.newHtmlFile(); } function newHtmlFile() { ProjectModelCode.newHtmlFile(); }
function newJsFile() { ProjectModelCode.newJsFile(); } function newJsFile() { ProjectModelCode.newJsFile(); }
function newCssFile() { ProjectModelCode.newCssFile(); } function newCssFile() { ProjectModelCode.newCssFile(); }
//function newContract() { ProjectModelCode.newContract(); } function newContract() { ProjectModelCode.newContract(); }
function openDocument(documentId) { ProjectModelCode.openDocument(documentId); } function openDocument(documentId) { ProjectModelCode.openDocument(documentId); }
function openNextDocument() { ProjectModelCode.openNextDocument(); } function openNextDocument() { ProjectModelCode.openNextDocument(); }
function openPrevDocument() { ProjectModelCode.openPrevDocument(); } function openPrevDocument() { ProjectModelCode.openPrevDocument(); }

2
mix/qml/StateDialog.qml

@ -12,7 +12,7 @@ Window {
id: modalStateDialog id: modalStateDialog
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
width: 450 width: 520
height: 480 height: 480
title: qsTr("Edit State") title: qsTr("Edit State")
visible: false visible: false

27
mix/qml/StateListModel.qml

@ -22,12 +22,12 @@ Item {
function fromPlainTransactionItem(t) { function fromPlainTransactionItem(t) {
var r = { var r = {
contractId: t.contractId,
functionId: t.functionId, functionId: t.functionId,
url: t.url, url: t.url,
value: QEtherHelper.createEther(t.value.value, t.value.unit), value: QEtherHelper.createEther(t.value.value, t.value.unit),
gas: QEtherHelper.createBigInt(t.gas.value), //t.gas,//QEtherHelper.createEther(t.gas.value, t.gas.unit), gas: QEtherHelper.createBigInt(t.gas.value), //t.gas,//QEtherHelper.createEther(t.gas.value, t.gas.unit),
gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit), gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit),
executeConstructor: t.executeConstructor,
stdContract: t.stdContract, stdContract: t.stdContract,
parameters: {} parameters: {}
}; };
@ -47,6 +47,10 @@ Item {
varComponent = Qt.createComponent("qrc:/qml/QHashType.qml"); varComponent = Qt.createComponent("qrc:/qml/QHashType.qml");
else if (type.indexOf("bool") !== -1) else if (type.indexOf("bool") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml"); varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml");
else {
console.log("Unknown parameter type: " + type);
continue;
}
var param = varComponent.createObject(stateListModel); var param = varComponent.createObject(stateListModel);
var dec = Qt.createComponent("qrc:/qml/QVariableDeclaration.qml"); var dec = Qt.createComponent("qrc:/qml/QVariableDeclaration.qml");
@ -78,12 +82,12 @@ Item {
function toPlainTransactionItem(t) { function toPlainTransactionItem(t) {
var r = { var r = {
contractId: t.contractId,
functionId: t.functionId, functionId: t.functionId,
url: t.url, url: t.url,
value: { value: t.value.value, unit: t.value.unit }, value: { value: t.value.value, unit: t.value.unit },
gas: { value: t.gas.value() }, gas: { value: t.gas.value() },
gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit }, gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit },
executeConstructor: t.executeConstructor,
stdContract: t.stdContract, stdContract: t.stdContract,
parameters: {} parameters: {}
}; };
@ -159,7 +163,6 @@ Item {
value: QEtherHelper.createEther("100", QEther.Wei), value: QEtherHelper.createEther("100", QEther.Wei),
gas: QEtherHelper.createBigInt("125000"), gas: QEtherHelper.createBigInt("125000"),
gasPrice: QEtherHelper.createEther("10000000000000", QEther.Wei), gasPrice: QEtherHelper.createEther("10000000000000", QEther.Wei),
executeConstructor: false,
stdContract: false stdContract: false
}; };
} }
@ -178,16 +181,19 @@ Item {
var contractTransaction = defaultTransactionItem(); var contractTransaction = defaultTransactionItem();
var contractItem = contractLibrary.model.get(i); var contractItem = contractLibrary.model.get(i);
contractTransaction.url = contractItem.url; contractTransaction.url = contractItem.url;
contractTransaction.contractId = contractItem.name;
contractTransaction.functionId = contractItem.name; contractTransaction.functionId = contractItem.name;
contractTransaction.stdContract = true; contractTransaction.stdContract = true;
item.transactions.push(contractTransaction); item.transactions.push(contractTransaction);
}; };
//add constructor //add constructors, //TODO: order by dependencies
var ctorTr = defaultTransactionItem(); for(var c in codeModel.contracts) {
ctorTr.executeConstructor = true; var ctorTr = defaultTransactionItem();
ctorTr.functionId = qsTr("Constructor"); ctorTr.functionId = c;
item.transactions.push(ctorTr); ctorTr.contractId = c;
item.transactions.push(ctorTr);
}
return item; return item;
} }
@ -201,7 +207,7 @@ Item {
} }
function debugDefaultState() { function debugDefaultState() {
if (defaultStateIndex >= 0) if (defaultStateIndex >= 0 && defaultStateIndex < stateList.length)
runState(defaultStateIndex); runState(defaultStateIndex);
} }
@ -219,6 +225,9 @@ Item {
defaultStateIndex = 0; defaultStateIndex = 0;
defaultStateChanged(); defaultStateChanged();
} }
else if (defaultStateIndex > index)
defaultStateIndex--;
save(); save();
} }

14
mix/qml/StatusPane.qml

@ -8,9 +8,9 @@ Rectangle {
id: statusHeader id: statusHeader
objectName: "statusPane" objectName: "statusPane"
function updateStatus() function updateStatus(message)
{ {
if (statusPane.result.successful) if (!message)
{ {
status.state = ""; status.state = "";
status.text = qsTr("Compile without errors."); status.text = qsTr("Compile without errors.");
@ -20,12 +20,12 @@ Rectangle {
else else
{ {
status.state = "error"; status.state = "error";
var errorInfo = ErrorLocationFormater.extractErrorInfo(statusPane.result.compilerMessage, true); var errorInfo = ErrorLocationFormater.extractErrorInfo(message, true);
status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail; status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail;
logslink.visible = true; logslink.visible = true;
debugImg.state = ""; debugImg.state = "";
} }
debugRunActionIcon.enabled = statusPane.result.successful; debugRunActionIcon.enabled = codeModel.hasContract;
} }
function infoMessage(text) function infoMessage(text)
@ -35,7 +35,6 @@ Rectangle {
logslink.visible = false; logslink.visible = false;
} }
Connections { Connections {
target:clientModel target:clientModel
onRunStarted: infoMessage(qsTr("Running transactions...")); onRunStarted: infoMessage(qsTr("Running transactions..."));
@ -49,6 +48,11 @@ Rectangle {
onDeploymentError: infoMessage(error); onDeploymentError: infoMessage(error);
onDeploymentComplete: infoMessage(qsTr("Deployment complete")); onDeploymentComplete: infoMessage(qsTr("Deployment complete"));
} }
Connections {
target: codeModel
onCompilationComplete: updateStatus();
onCompilationError: updateStatus(_error);
}
color: "transparent" color: "transparent"
anchors.fill: parent anchors.fill: parent

117
mix/qml/TransactionDialog.qml

@ -10,7 +10,7 @@ import "."
Window { Window {
id: modalTransactionDialog id: modalTransactionDialog
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
width: 450 width: 520
height: (paramsModel.count > 0 ? 500 : 300) height: (paramsModel.count > 0 ? 500 : 300)
visible: false visible: false
color: StateDialogStyle.generic.backgroundColor color: StateDialogStyle.generic.backgroundColor
@ -20,9 +20,9 @@ Window {
property alias gas: gasValueEdit.gasValue; property alias gas: gasValueEdit.gasValue;
property alias gasPrice: gasPriceField.value; property alias gasPrice: gasPriceField.value;
property alias transactionValue: valueField.value; property alias transactionValue: valueField.value;
property string contractId: contractComboBox.currentValue();
property alias functionId: functionComboBox.currentText; property alias functionId: functionComboBox.currentText;
property var itemParams; property var itemParams;
property bool isConstructorTransaction;
property bool useTransactionDefaultValue: false property bool useTransactionDefaultValue: false
property var qType; property var qType;
@ -39,32 +39,47 @@ Window {
gasValueEdit.gasValue = item.gas; gasValueEdit.gasValue = item.gas;
gasPriceField.value = item.gasPrice; gasPriceField.value = item.gasPrice;
valueField.value = item.value; valueField.value = item.value;
var contractId = item.contractId;
var functionId = item.functionId; var functionId = item.functionId;
isConstructorTransaction = item.executeConstructor; rowFunction.visible = true;
rowFunction.visible = !item.executeConstructor;
itemParams = item.parameters !== undefined ? item.parameters : {}; itemParams = item.parameters !== undefined ? item.parameters : {};
functionsModel.clear();
contractsModel.clear();
var contractIndex = -1;
var contracts = codeModel.contracts;
for (var c in contracts) {
contractsModel.append({ cid: c, text: contracts[c].contract.name });
if (contracts[c].contract.name === contractId)
contractIndex = contractsModel.count - 1;
}
if (contractIndex == -1 && contractsModel.count > 0)
contractIndex = 0; //@todo suggest unused contract
contractComboBox.currentIndex = contractIndex;
loadFunctions(contractComboBox.currentValue());
var functionIndex = -1; var functionIndex = -1;
var functions = codeModel.code.contract.functions; for (var f = 0; f < functionsModel.count; f++)
for (var f = 0; f < functions.length; f++) { if (functionsModel.get(f).text === item.functionId)
functionsModel.append({ text: functions[f].name });
if (functions[f].name === item.functionId)
functionIndex = f; functionIndex = f;
}
if (functionIndex == -1 && functionsModel.count > 0) if (functionIndex == -1 && functionsModel.count > 0)
functionIndex = 0; //@todo suggest unused function functionIndex = 0; //@todo suggest unused function
functionComboBox.currentIndex = functionIndex; functionComboBox.currentIndex = functionIndex;
paramsModel.clear(); paramsModel.clear();
if (!item.executeConstructor) if (functionId !== contractComboBox.currentValue())
loadParameters(); loadParameters();
else else {
{ var contract = codeModel.contracts[contractId];
var parameters = codeModel.code.contract.constructor.parameters; if (contract) {
for (var p = 0; p < parameters.length; p++) var parameters = contract.contract.constructor.parameters;
loadParameter(parameters[p]); for (var p = 0; p < parameters.length; p++)
loadParameter(parameters[p]);
}
} }
modalTransactionDialog.setX((Screen.width - width) / 2); modalTransactionDialog.setX((Screen.width - width) / 2);
modalTransactionDialog.setY((Screen.height - height) / 2); modalTransactionDialog.setY((Screen.height - height) / 2);
@ -73,6 +88,21 @@ Window {
valueField.focus = true; valueField.focus = true;
} }
function loadFunctions(contractId)
{
functionsModel.clear();
var contract = codeModel.contracts[contractId];
if (contract) {
var functions = codeModel.contracts[contractId].contract.functions;
for (var f = 0; f < functions.length; f++) {
functionsModel.append({ text: functions[f].name });
}
}
//append constructor
functionsModel.append({ text: contractId });
}
function loadParameter(parameter) function loadParameter(parameter)
{ {
var type = parameter.type; var type = parameter.type;
@ -104,10 +134,15 @@ Window {
if (!paramsModel) if (!paramsModel)
return; return;
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
var func = codeModel.code.contract.functions[functionComboBox.currentIndex]; var contract = codeModel.contracts[contractComboBox.currentValue()];
var parameters = func.parameters; if (contract) {
for (var p = 0; p < parameters.length; p++) var func = contract.contract.functions[functionComboBox.currentIndex];
loadParameter(parameters[p]); if (func) {
var parameters = func.parameters;
for (var p = 0; p < parameters.length; p++)
loadParameter(parameters[p]);
}
}
} }
} }
@ -140,24 +175,21 @@ Window {
if (!useTransactionDefaultValue) if (!useTransactionDefaultValue)
{ {
item = { item = {
contractId: transactionDialog.contractId,
functionId: transactionDialog.functionId, functionId: transactionDialog.functionId,
gas: transactionDialog.gas, gas: transactionDialog.gas,
gasPrice: transactionDialog.gasPrice, gasPrice: transactionDialog.gasPrice,
value: transactionDialog.transactionValue, value: transactionDialog.transactionValue,
parameters: {}, parameters: {},
executeConstructor: isConstructorTransaction
}; };
} }
else else
{ {
item = TransactionHelper.defaultTransaction(); item = TransactionHelper.defaultTransaction();
item.contractId = transactionDialog.contractId;
item.functionId = transactionDialog.functionId; item.functionId = transactionDialog.functionId;
item.executeConstructor = isConstructorTransaction;
} }
if (isConstructorTransaction)
item.functionId = qsTr("Constructor");
var orderedQType = []; var orderedQType = [];
for (var p = 0; p < transactionDialog.transactionParams.count; p++) { for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
var parameter = transactionDialog.transactionParams.get(p); var parameter = transactionDialog.transactionParams.get(p);
@ -174,15 +206,37 @@ Window {
anchors.fill: parent anchors.fill: parent
anchors.margins: 10 anchors.margins: 10
SourceSansProLight
{
id: lightFont
}
ColumnLayout { ColumnLayout {
id: dialogContent id: dialogContent
anchors.top: parent.top anchors.top: parent.top
spacing: 10 spacing: 10
RowLayout
{
id: rowContract
Layout.fillWidth: true
height: 150
DefaultLabel {
Layout.preferredWidth: 75
text: qsTr("Contract")
}
ComboBox {
id: contractComboBox
function currentValue() {
return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : "";
}
Layout.preferredWidth: 350
currentIndex: -1
textRole: "text"
editable: false
model: ListModel {
id: contractsModel
}
onCurrentIndexChanged: {
loadFunctions(currentValue());
}
}
}
RowLayout RowLayout
{ {
id: rowFunction id: rowFunction
@ -204,9 +258,6 @@ Window {
onCurrentIndexChanged: { onCurrentIndexChanged: {
loadParameters(); loadParameters();
} }
style: ComboBoxStyle {
font: lightFont.name
}
} }
} }

32
mix/qml/WebPreview.qml

@ -24,12 +24,23 @@ Item {
} }
function reload() { function reload() {
updateContract(); if (initialized) {
webView.runJavaScript("reloadPage()"); updateContract();
webView.runJavaScript("reloadPage()");
}
} }
function updateContract() { function updateContract() {
webView.runJavaScript("updateContract(\"" + codeModel.code.contract.name + "\", \"" + clientModel.contractAddress + "\", " + codeModel.code.contractInterface + ")"); var contracts = {};
for (var c in codeModel.contracts) {
var contract = codeModel.contracts[c];
contracts[c] = {
name: contract.contract.name,
address: clientModel.contractAddresses[contract.contract.name],
interface: JSON.parse(contract.contractInterface),
};
}
webView.runJavaScript("updateContracts(" + JSON.stringify(contracts) + ")");
} }
function reloadOnSave() { function reloadOnSave() {
@ -62,7 +73,6 @@ Item {
Connections { Connections {
target: clientModel target: clientModel
onContractAddressChanged: reload();
onRunComplete: reload(); onRunComplete: reload();
} }
@ -162,11 +172,6 @@ Item {
spacing: 0 spacing: 0
Rectangle Rectangle
{ {
SourceSansProLight
{
id: regularFont
}
anchors.leftMargin: 4 anchors.leftMargin: 4
color: WebPreviewStyle.general.headerBackgroundColor color: WebPreviewStyle.general.headerBackgroundColor
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
@ -188,9 +193,7 @@ Item {
currentIndex: -1 currentIndex: -1
onCurrentIndexChanged: changePage() onCurrentIndexChanged: changePage()
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
style: ComboBoxStyle { height: 21
font: regularFont.name
}
} }
Action { Action {
@ -205,12 +208,13 @@ Item {
iconSource: "qrc:/qml/img/available_updates.png" iconSource: "qrc:/qml/img/available_updates.png"
action: buttonReloadAction action: buttonReloadAction
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 26 width: 21
height: 26 height: 21
} }
CheckBox { CheckBox {
id: autoReloadOnSave id: autoReloadOnSave
checked: true checked: true
height: 21
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
style: CheckBoxStyle { style: CheckBoxStyle {
label: DefaultLabel { label: DefaultLabel {

16
mix/qml/html/WebContainer.html

@ -15,16 +15,18 @@ reloadPage = function() {
preview.contentWindow.location.reload(); preview.contentWindow.location.reload();
}; };
updateContract = function(name, address, contractFace) { updateContracts = function(contracts) {
if (window.web3) { if (window.web3) {
window.web3.provider.polls = []; window.web3.provider.polls = [];
var contract = window.web3.eth.contract(address, contractFace);
window.contracts = {}; window.contracts = {};
window.contracts[name] = { for (var c in contracts) {
address: address, var contract = window.web3.eth.contract(contracts[c].address, contracts[c].interface);
interface: contractFace, window.contracts[c] = {
contract: contract, address: c.address,
}; interface: c.interface,
contract: contract,
};
}
} }
}; };

77
mix/qml/js/ProjectModel.js

@ -20,6 +20,9 @@
* Ethereum IDE client. * Ethereum IDE client.
*/ */
var htmlTemplate = "<html>\n<head>\n<script>\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>";
var contractTemplate = "contract Contract {\n}\n";
function saveAll() { function saveAll() {
saveProject(); saveProject();
} }
@ -76,6 +79,16 @@ function loadProject(path) {
projectSettings.lastProjectPath = path; projectSettings.lastProjectPath = path;
projectLoading(projectData); projectLoading(projectData);
projectLoaded() projectLoaded()
//TODO: move this to codemodel
var contractSources = {};
for (var d = 0; d < listModel.count; d++) {
var doc = listModel.get(d);
if (doc.isContract)
contractSources[doc.documentId] = fileIo.readFile(doc.path);
}
codeModel.reset(contractSources);
} }
function addFile(fileName) { function addFile(fileName) {
@ -92,7 +105,7 @@ function addFile(fileName) {
contract: false, contract: false,
path: p, path: p,
fileName: fileName, fileName: fileName,
name: isContract ? "Contract" : fileName, name: fileName,
documentId: fileName, documentId: fileName,
syntaxMode: syntaxMode, syntaxMode: syntaxMode,
isText: isContract || isHtml || isCss || isJs, isText: isContract || isHtml || isCss || isJs,
@ -150,7 +163,7 @@ function openPrevDocument() {
} }
function doCloseProject() { function doCloseProject() {
console.log("closing project"); console.log("Closing project");
projectListModel.clear(); projectListModel.clear();
projectPath = ""; projectPath = "";
currentDocumentId = ""; currentDocumentId = "";
@ -167,14 +180,14 @@ function doCreateProject(title, path) {
var projectFile = dirPath + projectFileName; var projectFile = dirPath + projectFileName;
var indexFile = "index.html"; var indexFile = "index.html";
var contractsFile = "contracts.sol"; var contractsFile = "contract.sol";
var projectData = { var projectData = {
title: title, title: title,
files: [ contractsFile, indexFile ] files: [ contractsFile, indexFile ]
}; };
//TODO: copy from template //TODO: copy from template
fileIo.writeFile(dirPath + indexFile, "<html>\n<head>\n<script>\nvar web3 = parent.web3;\nvar theContract = parent.contract;\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>"); fileIo.writeFile(dirPath + indexFile, htmlTemplate);
fileIo.writeFile(dirPath + contractsFile, "contract Contract {\n}\n"); fileIo.writeFile(dirPath + contractsFile, contractTemplate);
newProject(projectData); newProject(projectData);
var json = JSON.stringify(projectData, null, "\t"); var json = JSON.stringify(projectData, null, "\t");
fileIo.writeFile(projectFile, json); fileIo.writeFile(projectFile, json);
@ -222,7 +235,7 @@ function removeDocument(documentId) {
} }
function newHtmlFile() { function newHtmlFile() {
createAndAddFile("page", "html", "<html>\n</html>"); createAndAddFile("page", "html", htmlTemplate);
} }
function newCssFile() { function newCssFile() {
@ -233,6 +246,11 @@ function newJsFile() {
createAndAddFile("script", "js", "function foo() {\n}\n"); createAndAddFile("script", "js", "function foo() {\n}\n");
} }
function newContract() {
createAndAddFile("contract", "sol", contractTemplate);
}
function createAndAddFile(name, extension, content) { function createAndAddFile(name, extension, content) {
var fileName = generateFileName(name, extension); var fileName = generateFileName(name, extension);
var filePath = projectPath + fileName; var filePath = projectPath + fileName;
@ -267,15 +285,21 @@ function deployProject(force) {
var jsonRpcUrl = "http://localhost:8080"; var jsonRpcUrl = "http://localhost:8080";
console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); console.log("Deploying " + deploymentId + " to " + jsonRpcUrl);
deploymentStarted(); deploymentStarted();
var code = codeModel.codeHex
var rpcRequest = JSON.stringify({ var requests = [];
jsonrpc: "2.0", var requestNames = [];
method: "eth_transact", for (var c in codeModel.contracts) { //TODO: order based on dependencies
params: [ { var code = codeModel.contracts[c].codeHex;
"code": code requests.push({
} ], jsonrpc: "2.0",
id: jsonRpcRequestId++ method: "eth_transact",
}); params: [ { "code": code } ],
id: jsonRpcRequestId++
});
requestNames.push(c);
}
var rpcRequest = JSON.stringify(requests);;
var httpRequest = new XMLHttpRequest() var httpRequest = new XMLHttpRequest()
httpRequest.open("POST", jsonRpcUrl, true); httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json"); httpRequest.setRequestHeader("Content-type", "application/json");
@ -285,9 +309,12 @@ function deployProject(force) {
if (httpRequest.readyState === XMLHttpRequest.DONE) { if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) { if (httpRequest.status === 200) {
var rpcResponse = JSON.parse(httpRequest.responseText); var rpcResponse = JSON.parse(httpRequest.responseText);
var address = rpcResponse.result; if (rpcResponse.length === requestNames.length) {
console.log("Created contract, address: " + address); var contractAddresses = {};
finalizeDeployment(deploymentId, address); for (var r = 0; r < rpcResponse.lenght; r++)
contractAddresses[requestNames[r]] = rpcResponse.result;
finalizeDeployment(deploymentId, contractAddresses);
}
} else { } else {
var errorText = qsTr("Deployment error: RPC server HTTP status ") + httpRequest.status; var errorText = qsTr("Deployment error: RPC server HTTP status ") + httpRequest.status;
console.log(errorText); console.log(errorText);
@ -298,7 +325,7 @@ function deployProject(force) {
httpRequest.send(rpcRequest); httpRequest.send(rpcRequest);
} }
function finalizeDeployment(deploymentId, address) { function finalizeDeployment(deploymentId, addresses) {
//create a dir for frontend files and copy them //create a dir for frontend files and copy them
var deploymentDir = projectPath + deploymentId + "/"; var deploymentDir = projectPath + deploymentId + "/";
fileIo.makeDir(deploymentDir); fileIo.makeDir(deploymentDir);
@ -326,16 +353,18 @@ function finalizeDeployment(deploymentId, address) {
fileIo.copyFile(doc.path, deploymentDir + doc.fileName); fileIo.copyFile(doc.path, deploymentDir + doc.fileName);
} }
//write deployment js //write deployment js
var contractAccessor = "contracts[\"" + codeModel.code.contract.name + "\"]";
var deploymentJs = var deploymentJs =
"// Autogenerated by Mix\n" + "// Autogenerated by Mix\n" +
"web3 = require(\"web3\");\n" + "web3 = require(\"web3\");\n" +
"contracts = {};\n" + "contracts = {};\n";
contractAccessor + " = {\n" + for (var c in codeModel.contracts) {
"\tinterface: " + codeModel.code.contractInterface + ",\n" + var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]";
"\taddress: \"" + address + "\"\n" + deploymentJs += contractAccessor + " = {\n" +
"\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" +
"\taddress: \"" + addresses[c] + "\"\n" +
"};\n" + "};\n" +
contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n"; contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n";
}
fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs);
//copy scripts //copy scripts
fileIo.copyFile("qrc:///js/bignumber.min.js", deploymentDir + "bignumber.min.js"); fileIo.copyFile("qrc:///js/bignumber.min.js", deploymentDir + "bignumber.min.js");

1
mix/qml/js/TransactionHelper.js

@ -7,7 +7,6 @@ function defaultTransaction()
functionId: "", functionId: "",
gas: createBigInt("125000"), gas: createBigInt("125000"),
gasPrice: createEther("100000", QEther.Wei), gasPrice: createEther("100000", QEther.Wei),
executeConstructor: false,
parameters: {} parameters: {}
}; };
} }

4
mix/qml/main.qml

@ -30,7 +30,7 @@ ApplicationWindow {
MenuItem { action: addNewHtmlFileAction } MenuItem { action: addNewHtmlFileAction }
MenuItem { action: addNewCssFileAction } MenuItem { action: addNewCssFileAction }
MenuSeparator {} MenuSeparator {}
//MenuItem { action: addNewContractAction } MenuItem { action: addNewContractAction }
MenuItem { action: closeProjectAction } MenuItem { action: closeProjectAction }
MenuSeparator {} MenuSeparator {}
MenuItem { action: exitAppAction } MenuItem { action: exitAppAction }
@ -95,7 +95,7 @@ ApplicationWindow {
text: qsTr("Mine") text: qsTr("Mine")
shortcut: "Ctrl+M" shortcut: "Ctrl+M"
onTriggered: clientModel.mine(); onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running &&!clientModel.mining enabled: codeModel.hasContract && !clientModel.running && !clientModel.mining
} }
StateList { StateList {

2
neth/CMakeLists.txt

@ -2,9 +2,9 @@ cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(..)
set(EXECUTABLE neth) set(EXECUTABLE neth)

2
sc/CMakeLists.txt

@ -2,7 +2,7 @@ cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..) include_directories(BEFORE ..)
set(EXECUTABLE sc) set(EXECUTABLE sc)

2
solc/CMakeLists.txt

@ -3,8 +3,8 @@ set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
set(EXECUTABLE solc) set(EXECUTABLE solc)

2
test/CMakeLists.txt

@ -4,8 +4,8 @@ aux_source_directory(. SRC_LIST)
list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp") list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp")
list(REMOVE_ITEM SRC_LIST "./checkRandomTest.cpp") list(REMOVE_ITEM SRC_LIST "./checkRandomTest.cpp")
include_directories(..)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})

1513
test/ManyFunctions.sol

File diff suppressed because it is too large

24
test/ManyFunctionsGenerator.py

@ -0,0 +1,24 @@
n = 100
splitNumBegin = 128 - (n / 2)
i = 1
template = """
function right{0}(uint seed) returns (uint) {{
var r = nextRand(seed);
if (r >= 2**{2})
return right{1}(r);
return left{1}(r);
}}
function left{0}(uint seed) returns (uint) {{
var r = nextRand(nextRand(seed));
if (r >= 2**{2})
return left{1}(r);
return right{1}(r);
}}
"""
for i in range(1, n):
print template.format(i, i + 1, i + splitNumBegin)

10
test/SolidityCompiler.cpp

@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 69; unsigned boilerplateSize = 70;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x0, // initialize local variable x
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
@ -114,8 +114,8 @@ BOOST_AUTO_TEST_CASE(ifStatement)
" function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 56; unsigned shift = 57;
unsigned boilerplateSize = 69; unsigned boilerplateSize = 70;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), byte(Instruction::DUP1),
@ -155,8 +155,8 @@ BOOST_AUTO_TEST_CASE(loops)
" function f() { while(true){1;break;2;continue;3;return;4;} }" " function f() { while(true){1;break;2;continue;3;return;4;} }"
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 56; unsigned shift = 57;
unsigned boilerplateSize = 69; unsigned boilerplateSize = 70;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,

49
test/SolidityEndToEndTest.cpp

@ -2283,9 +2283,9 @@ BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory)
} }
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
bytes calldata = bytes(61, 0x22) + bytes(12, 0x12); bytes calldata1 = bytes(61, 0x22) + bytes(12, 0x12);
sendMessage(calldata, false); sendMessage(calldata1, false);
BOOST_CHECK(m_output == encodeArgs(dev::sha3(bytes{'a', 'b', 'c'} + calldata))); BOOST_CHECK(m_output == encodeArgs(dev::sha3(bytes{'a', 'b', 'c'} + calldata1)));
} }
BOOST_AUTO_TEST_CASE(call_forward_bytes) BOOST_AUTO_TEST_CASE(call_forward_bytes)
@ -2534,6 +2534,49 @@ BOOST_AUTO_TEST_CASE(constructing_enums_from_ints)
BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); BOOST_CHECK(callContractFunction("test()") == encodeArgs(1));
} }
BOOST_AUTO_TEST_CASE(external_function)
{
char const* sourceCode = R"(
contract c {
function f(uint a) returns (uint) { return a; }
function test(uint a, uint b) external returns (uint r_a, uint r_b) {
r_a = f(a + 7);
r_b = b;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test(uint256,uint256)", 2, 3) == encodeArgs(2+7, 3));
}
BOOST_AUTO_TEST_CASE(bytes_in_arguments)
{
char const* sourceCode = R"(
contract c {
uint result;
function f(uint a, uint b) { result += a + b; }
function g(uint a) { result *= a; }
function test(uint a, bytes data1, bytes data2, uint b) external returns (uint r_a, uint r, uint r_b, uint l) {
r_a = a;
this.call(data1);
this.call(data2);
r = result;
r_b = b;
l = data1.length;
}
}
)";
compileAndRun(sourceCode);
string innercalldata1 = asString(FixedHash<4>(dev::sha3("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9));
bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13);
string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3));
bytes calldata = encodeArgs(
u256(innercalldata1.length()), u256(innercalldata2.length()),
12, innercalldata1, innercalldata2, 13);
BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata)
== encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

80
test/SolidityNameAndTypeResolution.cpp

@ -1083,6 +1083,86 @@ BOOST_AUTO_TEST_CASE(enum_duplicate_values)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError); BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
} }
BOOST_AUTO_TEST_CASE(private_visibility)
{
char const* sourceCode = R"(
contract base {
function f() private {}
}
contract derived is base {
function g() { f(); }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError);
}
BOOST_AUTO_TEST_CASE(private_visibility_via_explicit_base_access)
{
char const* sourceCode = R"(
contract base {
function f() private {}
}
contract derived is base {
function g() { base.f(); }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_visibility)
{
char const* sourceCode = R"(
contract c {
function f() external {}
function g() { f(); }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError);
}
BOOST_AUTO_TEST_CASE(external_base_visibility)
{
char const* sourceCode = R"(
contract base {
function f() external {}
}
contract derived is base {
function g() { base.f(); }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_argument_assign)
{
char const* sourceCode = R"(
contract c {
function f(uint a) external { a = 1; }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_argument_increment)
{
char const* sourceCode = R"(
contract c {
function f(uint a) external { a++; }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_argument_delete)
{
char const* sourceCode = R"(
contract c {
function f(uint a) external { delete a; }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

18
test/SolidityParser.cpp

@ -735,6 +735,24 @@ BOOST_AUTO_TEST_CASE(malformed_enum_declaration)
BOOST_CHECK_THROW(parseText(text), ParserError); BOOST_CHECK_THROW(parseText(text), ParserError);
} }
BOOST_AUTO_TEST_CASE(external_function)
{
char const* text = R"(
contract c {
function x() external {}
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
}
BOOST_AUTO_TEST_CASE(external_variable)
{
char const* text = R"(
contract c {
uint external x;
})";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

43
test/TestHelper.cpp

@ -504,6 +504,49 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
} }
} }
RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj)
{
//Construct Rlp of the given transaction
RLPStream rlpStream;
rlpStream.appendList(_tObj.size());
if (_tObj.count("nonce"))
rlpStream << bigint(_tObj["nonce"].get_str());
if (_tObj.count("gasPrice"))
rlpStream << bigint(_tObj["gasPrice"].get_str());
if (_tObj.count("gasLimit"))
rlpStream << bigint(_tObj["gasLimit"].get_str());
if (_tObj.count("to"))
{
if (_tObj["to"].get_str().empty())
rlpStream << "";
else
rlpStream << importByteArray(_tObj["to"].get_str());
}
if (_tObj.count("value"))
rlpStream << bigint(_tObj["value"].get_str());
if (_tObj.count("data"))
rlpStream << importData(_tObj);
if (_tObj.count("v"))
rlpStream << bigint(_tObj["v"].get_str());
if (_tObj.count("r"))
rlpStream << bigint(_tObj["r"].get_str());
if (_tObj.count("s"))
rlpStream << bigint(_tObj["s"].get_str());
if (_tObj.count("extrafield"))
rlpStream << bigint(_tObj["extrafield"].get_str());
return rlpStream;
}
void processCommandLineOptions() void processCommandLineOptions()
{ {

3
test/TestHelper.h

@ -45,7 +45,7 @@ namespace test
class ImportTest class ImportTest
{ {
public: public:
ImportTest() = default; ImportTest(json_spirit::mObject& _o) : m_TestObject(_o) {}
ImportTest(json_spirit::mObject& _o, bool isFiller); ImportTest(json_spirit::mObject& _o, bool isFiller);
// imports // imports
@ -79,6 +79,7 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e
void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests); void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests);
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);
RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj);
void processCommandLineOptions(); void processCommandLineOptions();
eth::LastHashes lastHashes(u256 _currentBlockNumber); eth::LastHashes lastHashes(u256 _currentBlockNumber);

687
test/blInvalidHeaderTestFiller.json

@ -0,0 +1,687 @@
{
"log1_wrongBlockNumber" : {
"blockHeader" : {
"number" : "2"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"log1_wrongBloom" : {
"blockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongCoinbase" : {
"blockHeader" : {
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongDifficulty" : {
"blockHeader" : {
"difficulty" : "10000"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"DifferentExtraData" : {
"blockHeader" : {
"extraData" : "42"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongGasLimit" : {
"blockHeader" : {
"gasLimit" : "100000"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongGasUsed" : {
"blockHeader" : {
"gasUsed" : "0"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongNumber" : {
"blockHeader" : {
"number" : "0"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongParentHash" : {
"blockHeader" : {
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongReceiptTrie" : {
"blockHeader" : {
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongStateRoot" : {
"blockHeader" : {
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongTimestamp" : {
"blockHeader" : {
"timestamp" : "0x54c98c80"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongTransactionsTrie" : {
"blockHeader" : {
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"wrongUncleHash" : {
"blockHeader" : {
"uncleHash" : "0x0dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
}
}

381
test/blValidBlockTestFiller.json

@ -0,0 +1,381 @@
{
"diffTooLowToChange" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "1023",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
"diff1024" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "1024",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
"gasPrice0" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "0",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
"gasLimitTooHigh" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "1000000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "0",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
"SimpleTx" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "500",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10"
}
],
"uncleHeaders" : [
]
},
"txOrder" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "500",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "7000000000"
},
{
"data" : "",
"gasLimit" : "500",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "8000000000"
}
],
"uncleHeaders" : [
]
},
"txEqualValue" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "500",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
},
{
"data" : "",
"gasLimit" : "500",
"gasPrice" : "9",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
]
},
"log1_correct" : {
"genesisBlockHeader" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "10000",
"extraData" : "42",
"gasLimit" : "100000",
"gasUsed" : "0",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "0",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000000",
"nonce" : "0",
"code" : "",
"storage": {}
},
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "100",
"nonce" : "0",
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }",
"storage": {}
}
},
"transactions" : [
{
"data" : "",
"gasLimit" : "5000",
"gasPrice" : "10",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "5000000000"
}
],
"uncleHeaders" : [
],
"firstBlockTest" : {
"block" : {
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "023101",
"extraData" : "42",
"gasLimit" : "0x0dddb6",
"gasUsed" : "100",
"nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d",
"number" : "62",
"parentHash" : "0xefb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5",
"receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a",
"timestamp" : "0x54c98c81",
"transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
},
"pre" : {
},
"transactions" : [
{
"data" : "0x60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b56",
"gasLimit" : "0x0f3e6f",
"gasPrice" : "0x09184e72a000",
"nonce" : "0",
"r" : "0xd4287e915ebac7a8af390560fa53c8f0b7f13802ba0393d7afa5823c2560ca89",
"s" : "0xae75db31a34f7e386ad459646de98ec3a1c88cc91b11620b4ffd86871f579942",
"to" : "",
"v" : "0x1b",
"value" : ""
}
],
}
}
}

509
test/block.cpp

@ -0,0 +1,509 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file block.cpp
* @author Christoph Jentzsch <cj@ethdev.com>
* @date 2015
* block test functions.
*/
#include <libdevcrypto/FileSystem.h>
#include <libethereum/CanonBlockChain.h>
#include "TestHelper.h"
using namespace std;
using namespace json_spirit;
using namespace dev;
using namespace dev::eth;
namespace dev { namespace test {
bytes createBlockRLPFromFields(mObject& _tObj)
{
RLPStream rlpStream;
rlpStream.appendList(_tObj.size());
if (_tObj.count("parentHash"))
rlpStream << importByteArray(_tObj["parentHash"].get_str());
if (_tObj.count("uncleHash"))
rlpStream << importByteArray(_tObj["uncleHash"].get_str());
if (_tObj.count("coinbase"))
rlpStream << importByteArray(_tObj["coinbase"].get_str());
if (_tObj.count("stateRoot"))
rlpStream << importByteArray(_tObj["stateRoot"].get_str());
if (_tObj.count("transactionsTrie"))
rlpStream << importByteArray(_tObj["transactionsTrie"].get_str());
if (_tObj.count("receiptTrie"))
rlpStream << importByteArray(_tObj["receiptTrie"].get_str());
if (_tObj.count("bloom"))
rlpStream << importByteArray(_tObj["bloom"].get_str());
if (_tObj.count("difficulty"))
rlpStream << bigint(_tObj["difficulty"].get_str());
if (_tObj.count("number"))
rlpStream << bigint(_tObj["number"].get_str());
if (_tObj.count("gasLimit"))
rlpStream << bigint(_tObj["gasLimit"].get_str());
if (_tObj.count("gasUsed"))
rlpStream << bigint(_tObj["gasUsed"].get_str());
if (_tObj.count("timestamp"))
rlpStream << bigint(_tObj["timestamp"].get_str());
if (_tObj.count("extraData"))
rlpStream << importByteArray(_tObj["extraData"].get_str());
if (_tObj.count("nonce"))
rlpStream << importByteArray(_tObj["nonce"].get_str());
return rlpStream.out();
}
void doBlockTests(json_spirit::mValue& _v, bool _fillin)
{
for (auto& i: _v.get_obj())
{
cerr << i.first << endl;
mObject& o = i.second.get_obj();
BOOST_REQUIRE(o.count("genesisBlockHeader"));
BlockInfo blockFromFields;
try
{
// construct genesis block
const bytes c_blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj());
const RLP c_bRLP(c_blockRLP);
blockFromFields.populateFromHeader(c_bRLP, false);
}
catch (Exception const& _e)
{
cnote << "block population did throw an exception: " << diagnostic_information(_e);
BOOST_ERROR("Failed block population with Exception: " << _e.what());
continue;
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed block population with Exception: " << _e.what());
continue;
}
catch(...)
{
cnote << "block population did throw an unknown exception\n";
continue;
}
BOOST_REQUIRE(o.count("pre"));
ImportTest importer(o["pre"].get_obj());
State state(Address(), OverlayDB(), BaseState::Empty);
importer.importState(o["pre"].get_obj(), state);
state.commit();
if (_fillin)
blockFromFields.stateRoot = state.rootHash();
else
BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == state.rootHash(), "root hash does not match");
if (_fillin)
{
// find new valid nonce
ProofOfWork pow;
MineInfo ret;
while (!ProofOfWork::verify(blockFromFields.headerHash(WithoutNonce), blockFromFields.nonce, blockFromFields.difficulty))
tie(ret, blockFromFields.nonce) = pow.mine(blockFromFields.headerHash(WithoutNonce), blockFromFields.difficulty, 1000, true, true);
//update genesis block in json file
o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot);
o["genesisBlockHeader"].get_obj()["nonce"] = toString(blockFromFields.nonce);
}
// create new "genesis" block
RLPStream rlpStream;
blockFromFields.streamRLP(rlpStream, WithNonce);
RLPStream block(3);
block.appendRaw(rlpStream.out());
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
blockFromFields.verifyInternals(&block.out());
// construct blockchain
BlockChain bc(block.out(), string(), true);
if (_fillin)
{
BOOST_REQUIRE(o.count("transactions"));
TransactionQueue txs;
for (auto const& txObj: o["transactions"].get_array())
{
mObject tx = txObj.get_obj();
importer.importTransaction(tx);
if (!txs.attemptImport(importer.m_transaction.rlp()))
cnote << "failed importing transaction\n";
}
try
{
state.sync(bc);
state.sync(bc,txs);
state.commitToMine(bc);
MineInfo info;
for (info.completed = false; !info.completed; info = state.mine()) {}
state.completeMine();
}
catch (Exception const& _e)
{
cnote << "state sync or mining did throw an exception: " << diagnostic_information(_e);
return;
}
catch (std::exception const& _e)
{
cnote << "state sync or mining did throw an exception: " << _e.what();
return;
}
// write valid txs
mArray txArray;
Transactions txList;
for (auto const& txi: txs.transactions())
{
Transaction tx(txi.second, CheckSignature::Sender);
txList.push_back(tx);
mObject txObject;
txObject["nonce"] = toString(tx.nonce());
txObject["data"] = toHex(tx.data());
txObject["gasLimit"] = toString(tx.gas());
txObject["gasPrice"] = toString(tx.gasPrice());
txObject["r"] = "0x" + toString(tx.signature().r);
txObject["s"] = "0x" + toString(tx.signature().s);
txObject["v"] = to_string(tx.signature().v + 27);
txObject["to"] = toString(tx.receiveAddress());
txObject["value"] = toString(tx.value());
txArray.push_back(txObject);
}
o["transactions"] = txArray;
o["rlp"] = "0x" + toHex(state.blockData());
BlockInfo current_BlockHeader = state.info();
// overwrite blockheader with (possible wrong) data from "blockheader" in filler;
if (o.count("blockHeader"))
{
if (o["blockHeader"].get_obj().size() != 14)
{
BlockInfo tmp = current_BlockHeader;
if (o["blockHeader"].get_obj().count("parentHash"))
tmp.parentHash = h256(o["blockHeader"].get_obj()["parentHash"].get_str());
if (o["blockHeader"].get_obj().count("uncleHash"))
tmp.sha3Uncles = h256(o["blockHeader"].get_obj()["uncleHash"].get_str());
if (o["blockHeader"].get_obj().count("coinbase"))
tmp.coinbaseAddress = Address(o["blockHeader"].get_obj()["coinbase"].get_str());
if (o["blockHeader"].get_obj().count("stateRoot"))
tmp.stateRoot = h256(o["blockHeader"].get_obj()["stateRoot"].get_str());
if (o["blockHeader"].get_obj().count("transactionsTrie"))
tmp.transactionsRoot = h256(o["blockHeader"].get_obj()["transactionsTrie"].get_str());
if (o["blockHeader"].get_obj().count("receiptTrie"))
tmp.receiptsRoot = h256(o["blockHeader"].get_obj()["receiptTrie"].get_str());
if (o["blockHeader"].get_obj().count("bloom"))
tmp.logBloom = LogBloom(o["blockHeader"].get_obj()["bloom"].get_str());
if (o["blockHeader"].get_obj().count("difficulty"))
tmp.difficulty = toInt(o["blockHeader"].get_obj()["difficulty"]);
if (o["blockHeader"].get_obj().count("number"))
tmp.number = toInt(o["blockHeader"].get_obj()["number"]);
if (o["blockHeader"].get_obj().count("gasLimit"))
tmp.gasLimit = toInt(o["blockHeader"].get_obj()["gasLimit"]);
if (o["blockHeader"].get_obj().count("gasUsed"))
tmp.gasUsed = toInt(o["blockHeader"].get_obj()["gasUsed"]);
if (o["blockHeader"].get_obj().count("timestamp"))
tmp.timestamp = toInt(o["blockHeader"].get_obj()["timestamp"]);
if (o["blockHeader"].get_obj().count("extraData"))
tmp.extraData = importByteArray(o["blockHeader"].get_obj()["extraData"].get_str());
// find new valid nonce
if (tmp != current_BlockHeader)
{
current_BlockHeader = tmp;
cout << "new header!\n";
ProofOfWork pow;
MineInfo ret;
while (!ProofOfWork::verify(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.nonce, current_BlockHeader.difficulty))
tie(ret, current_BlockHeader.nonce) = pow.mine(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.difficulty, 10000, true, true);
}
}
else
{
// take the blockheader as is
const bytes c_blockRLP = createBlockRLPFromFields(o["blockHeader"].get_obj());
const RLP c_bRLP(c_blockRLP);
current_BlockHeader.populateFromHeader(c_bRLP, false);
}
}
// write block header
mObject oBlockHeader;
oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash);
oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles);
oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress);
oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot);
oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot);
oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot);
oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom);
oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty);
oBlockHeader["number"] = toString(current_BlockHeader.number);
oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit);
oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed);
oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp);
oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData);
oBlockHeader["nonce"] = toString(current_BlockHeader.nonce);
o["blockHeader"] = oBlockHeader;
// write uncle list
mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles.
o["uncleHeaders"] = aUncleList;
//txs:
RLPStream txStream;
txStream.appendList(txList.size());
for (unsigned i = 0; i < txList.size(); ++i)
{
RLPStream txrlp;
txList[i].streamRLP(txrlp);
txStream.appendRaw(txrlp.out());
}
RLPStream rlpStream2;
current_BlockHeader.streamRLP(rlpStream2, WithNonce);
RLPStream block2(3);
block2.appendRaw(rlpStream2.out());
block2.appendRaw(txStream.out());
block2.appendRaw(RLPEmptyList);
o["rlp"] = "0x" + toHex(block2.out());
if (sha3(RLP(state.blockData())[0].data()) != sha3(RLP(block2.out())[0].data()))
cnote << "block header mismatch\n";
if (sha3(RLP(state.blockData())[1].data()) != sha3(RLP(block2.out())[1].data()))
cnote << "txs mismatch\n";
if (sha3(RLP(state.blockData())[2].data()) != sha3(RLP(block2.out())[2].data()))
cnote << "uncle list mismatch\n";
try
{
ImportTest importerTmp(o["pre"].get_obj());
State stateTmp(Address(), OverlayDB(), BaseState::Empty);
importerTmp.importState(o["pre"].get_obj(), stateTmp);
stateTmp.commit();
BlockChain bcTmp(block.out(), getDataDir() + "/tmpBlockChain.bc", true);
stateTmp.sync(bcTmp);
bc.import(block2.out(), stateTmp.db());
stateTmp.sync(bcTmp);
}
// if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given
catch (...)
{
cnote << "block is invalid!\n";
o.erase(o.find("blockHeader"));
o.erase(o.find("uncleHeaders"));
o.erase(o.find("transactions"));
}
}
else
{
bytes blockRLP;
try
{
state.sync(bc);
blockRLP = importByteArray(o["rlp"].get_str());
bc.import(blockRLP, state.db());
state.sync(bc);
}
// if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given
catch (Exception const& _e)
{
cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e);
BOOST_CHECK(o.count("blockHeader") == 0);
BOOST_CHECK(o.count("transactions") == 0);
BOOST_CHECK(o.count("uncleHeaders") == 0);
continue;
}
catch (std::exception const& _e)
{
cnote << "state sync or block import did throw an exception: " << _e.what();
BOOST_CHECK(o.count("blockHeader") == 0);
BOOST_CHECK(o.count("transactions") == 0);
BOOST_CHECK(o.count("uncleHeaders") == 0);
continue;
}
catch(...)
{
cnote << "state sync or block import did throw an exception\n";
BOOST_CHECK(o.count("blockHeader") == 0);
BOOST_CHECK(o.count("transactions") == 0);
BOOST_CHECK(o.count("uncleHeaders") == 0);
continue;
}
BOOST_REQUIRE(o.count("blockHeader"));
mObject tObj = o["blockHeader"].get_obj();
BlockInfo blockHeaderFromFields;
const bytes c_rlpBytesBlockHeader = createBlockRLPFromFields(tObj);
const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader);
blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, false);
BlockInfo blockFromRlp = bc.info();
//Check the fields restored from RLP to original fields
BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!");
BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!");
//Check transaction list
Transactions txsFromField;
for (auto const& txObj: o["transactions"].get_array())
{
mObject tx = txObj.get_obj();
BOOST_REQUIRE(tx.count("nonce"));
BOOST_REQUIRE(tx.count("gasPrice"));
BOOST_REQUIRE(tx.count("gasLimit"));
BOOST_REQUIRE(tx.count("to"));
BOOST_REQUIRE(tx.count("value"));
BOOST_REQUIRE(tx.count("v"));
BOOST_REQUIRE(tx.count("r"));
BOOST_REQUIRE(tx.count("s"));
BOOST_REQUIRE(tx.count("data"));
try
{
Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender);
txsFromField.push_back(t);
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e));
}
catch (exception const& _e)
{
cnote << _e.what();
}
}
Transactions txsFromRlp;
RLP root(blockRLP);
for (auto const& tr: root[1])
{
Transaction tx(tr.data(), CheckSignature::Sender);
txsFromRlp.push_back(tx);
}
BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match");
for (size_t i = 0; i < txsFromField.size(); ++i)
{
BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match");
BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions in rlp and in transaction field do not match");
}
// check uncle list
BOOST_CHECK_MESSAGE((o["uncleList"].type() == json_spirit::null_type ? 0 : o["uncleList"].get_array().size()) == 0, "Uncle list is not empty, but the genesis block can not have uncles");
}
}
}
} }// Namespace Close
BOOST_AUTO_TEST_SUITE(BlockTests)
BOOST_AUTO_TEST_CASE(blValidBlockTest)
{
dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_CASE(blInvalidHeaderTest)
{
dev::test::executeTests("blInvalidHeaderTest", "/BlockTests", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_CASE(userDefinedFileBl)
{
dev::test::userDefinedTest("--bltest", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_SUITE_END()

4
test/stSystemOperationsTestFiller.json

@ -81,13 +81,13 @@
"pre" : { "pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
"nonce" : 0, "nonce" : "0",
"code" : "0x444242424245434253f0", "code" : "0x444242424245434253f0",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
"nonce" : 0, "nonce" : "0",
"code" : "", "code" : "",
"storage": {} "storage": {}
} }

47
test/transaction.cpp

@ -21,6 +21,7 @@
*/ */
#include "TestHelper.h" #include "TestHelper.h"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
using namespace dev; using namespace dev;
@ -28,50 +29,6 @@ using namespace dev::eth;
namespace dev { namespace test { namespace dev { namespace test {
RLPStream createRLPStreamFromTransactionFields(mObject& _tObj)
{
//Construct Rlp of the given transaction
RLPStream rlpStream;
rlpStream.appendList(_tObj.size());
if (_tObj.count("nonce") > 0)
rlpStream << bigint(_tObj["nonce"].get_str());
if (_tObj.count("gasPrice") > 0)
rlpStream << bigint(_tObj["gasPrice"].get_str());
if (_tObj.count("gasLimit") > 0)
rlpStream << bigint(_tObj["gasLimit"].get_str());
if (_tObj.count("to") > 0)
{
if (_tObj["to"].get_str().empty())
rlpStream << "";
else
rlpStream << importByteArray(_tObj["to"].get_str());
}
if (_tObj.count("value") > 0)
rlpStream << bigint(_tObj["value"].get_str());
if (_tObj.count("data") > 0)
rlpStream << importData(_tObj);
if (_tObj.count("v") > 0)
rlpStream << bigint(_tObj["v"].get_str());
if (_tObj.count("r") > 0)
rlpStream << bigint(_tObj["r"].get_str());
if (_tObj.count("s") > 0)
rlpStream << bigint(_tObj["s"].get_str());
if (_tObj.count("extrafield") > 0)
rlpStream << bigint(_tObj["extrafield"].get_str());
return rlpStream;
}
void doTransactionTests(json_spirit::mValue& _v, bool _fillin) void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{ {
for (auto& i: _v.get_obj()) for (auto& i: _v.get_obj())
@ -115,7 +72,6 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
Address addressReaded = Address(o["sender"].get_str()); Address addressReaded = Address(o["sender"].get_str());
BOOST_CHECK_MESSAGE(txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!"); BOOST_CHECK_MESSAGE(txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!");
} }
else else
{ {
@ -141,6 +97,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
} }
}//for }//for
}//doTransactionTests }//doTransactionTests
} }// Namespace Close } }// Namespace Close

29
test/vmPerformanceTestFiller.json

File diff suppressed because one or more lines are too long

50
test/webthreestubclient.h

@ -183,6 +183,46 @@ class WebThreeStubClient : public jsonrpc::Client
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
double eth_transactionCountByHash(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_transactionCountByHash",p);
if (result.isDouble())
return result.asDouble();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
double eth_transactionCountByNumber(int param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_transactionCountByNumber",p);
if (result.isDouble())
return result.asDouble();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
double eth_uncleCountByHash(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_uncleCountByHash",p);
if (result.isDouble())
return result.asDouble();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
double eth_uncleCountByNumber(int param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_uncleCountByNumber",p);
if (result.isDouble())
return result.asDouble();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
std::string eth_codeAt(const std::string& param1) throw (jsonrpc::JsonRpcException) std::string eth_codeAt(const std::string& param1) throw (jsonrpc::JsonRpcException)
{ {
Json::Value p; Json::Value p;
@ -535,6 +575,16 @@ class WebThreeStubClient : public jsonrpc::Client
else else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
} }
Json::Value shh_getMessages(int param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("shh_getMessages",p);
if (result.isArray())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
}; };
#endif //JSONRPC_CPP_STUB_WEBTHREESTUBCLIENT_H_ #endif //JSONRPC_CPP_STUB_WEBTHREESTUBCLIENT_H_

2
third/CMakeLists.txt

@ -10,8 +10,8 @@ endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(..)
qt5_wrap_ui(ui_Main.h Main.ui) qt5_wrap_ui(ui_Main.h Main.ui)

Loading…
Cancel
Save