diff --git a/alethzero/DappHost.cpp b/alethzero/DappHost.cpp index fd73c1b17..3b0661ad1 100644 --- a/alethzero/DappHost.cpp +++ b/alethzero/DappHost.cpp @@ -28,7 +28,11 @@ using namespace dev; DappHost::DappHost(int _port, int _threads): - m_port(_port), m_threads(_threads), m_running(false), m_daemon(nullptr) + m_port(_port), + m_url(QString("http://localhost:%1/").arg(m_port)), + m_threads(_threads), + m_running(false), + m_daemon(nullptr) { startListening(); } @@ -135,5 +139,10 @@ QUrl DappHost::hostDapp(Dapp&& _dapp) for (ManifestEntry const& entry: m_dapp.manifest.entries) m_entriesByPath[QString::fromStdString(entry.path)] = &entry; - return QUrl(QString("http://localhost:%1/").arg(m_port)); + return m_url; +} + +bool DappHost::servesUrl(QUrl const& _url) const +{ + return m_url == _url || m_url.isParentOf(_url); } diff --git a/alethzero/DappHost.h b/alethzero/DappHost.h index 985bd34d9..50dff741d 100644 --- a/alethzero/DappHost.h +++ b/alethzero/DappHost.h @@ -40,6 +40,9 @@ public: /// Load and host a dapp. Previsous dapp in discarded. Synchronous QUrl hostDapp(Dapp&& _dapp); + /// @returns true if the given url is served from this DappHost. + bool servesUrl(QUrl const& _url) const; + private: void startListening(); void stopListening(); @@ -48,7 +51,8 @@ private: void sendResponse(std::string const& _url, MHD_Connection* _connection); static int callback(void* _cls, MHD_Connection* _connection, char const* _url, char const* _method, char const* _version, char const* _uploadData, size_t* _uploadDataSize, void** _conCls); - int m_port; + int const m_port; + QUrl const m_url; int m_threads; bool m_running; MHD_Daemon* m_daemon; diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 60c07fd8d..e48b58283 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -232,6 +232,11 @@ Main::Main(QWidget *parent) : { ui->tabWidget->setTabText(0, ui->webView->title()); }); + connect(ui->webView, &QWebEngineView::urlChanged, [=](QUrl const& _url) + { + if (!m_dappHost->servesUrl(_url)) + ui->urlEdit->setText(_url.toString()); + }); m_dappHost.reset(new DappHost(8081)); m_dappLoader = new DappLoader(this, web3(), getNameReg()); @@ -638,18 +643,22 @@ pair Main::fromString(std::string const& _n) const if (_n == "(Create Contract)") return make_pair(Address(), bytes()); + std::string n = _n; + if (n.find("0x") == 0) + n.erase(0, 2); + auto g_newNameReg = getNameReg(); if (g_newNameReg) { - Address a = abiOut
(ethereum()->call(g_newNameReg, abiIn("addr(bytes32)", ::toString32(_n))).output); + Address a = abiOut
(ethereum()->call(g_newNameReg, abiIn("addr(bytes32)", ::toString32(n))).output); if (a) return make_pair(a, bytes()); } - if (_n.size() == 40) + if (n.size() == 40) { try { - return make_pair(Address(fromHex(_n, WhenError::Throw)), bytes()); + return make_pair(Address(fromHex(n, WhenError::Throw)), bytes()); } catch (BadHexCharacter& _e) { @@ -665,7 +674,7 @@ pair Main::fromString(std::string const& _n) const } else try { - return ICAP::decoded(_n).address([&](Address const& a, bytes const& b) -> bytes + return ICAP::decoded(n).address([&](Address const& a, bytes const& b) -> bytes { return ethereum()->call(a, b).output; }, g_newNameReg); diff --git a/eth/main.cpp b/eth/main.cpp index bd8fbc743..5b38f2779 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -910,7 +910,12 @@ void interactiveMode(eth::Client* c, std::shared_ptr gasP f << endl << " STACK" << endl; for (auto i: vm->stack()) f << (h256)i << endl; - f << " MEMORY" << endl << dev::memDump(vm->memory()); + std::string memDump = ( + (vm->memory().size() > 1000) ? + " mem size greater than 1000 bytes " : + dev::memDump(vm->memory()) + ); + f << " MEMORY" << endl << memDump; f << " STORAGE" << endl; for (auto const& i: ext->state().storage(ext->myAddress)) f << showbase << hex << i.first << ": " << i.second << endl; diff --git a/extdep/getstuff.bat b/extdep/getstuff.bat index 3c0b42f95..a718650b7 100644 --- a/extdep/getstuff.bat +++ b/extdep/getstuff.bat @@ -11,6 +11,7 @@ call :download curl 7.4.2 call :download jsoncpp 1.6.2 call :download json-rpc-cpp 0.5.0 call :download leveldb 1.2 +call :download llvm 3.7svn call :download microhttpd 0.9.2 call :download qt 5.4.1 call :download miniupnpc 1.9 diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 50fb273b6..f5fcacb75 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -327,6 +327,8 @@ bool ethash_cl_miner::init( m_globalWorkSize = ((m_globalWorkSize / s_workgroupSize) + 1) * s_workgroupSize; // remember the device's address bits m_deviceBits = device.getInfo(); + // make sure first step of global work size adjustment is large enough + m_stepWorkSizeAdjust = pow(2, m_deviceBits / 2 + 1); // patch source code // note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled @@ -532,14 +534,26 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook { if (d > chrono::milliseconds(s_msPerBatch * 10 / 9)) { - // cerr << "Batch of " << m_globalWorkSize << " took " << chrono::duration_cast(d).count() << " ms, >> " << _msPerBatch << " ms." << endl; - m_globalWorkSize = max(128, m_globalWorkSize + s_workgroupSize); + // Divide the step by 2 when adjustment way change + if (m_wayWorkSizeAdjust > -1) + m_stepWorkSizeAdjust = max(1, m_stepWorkSizeAdjust / 2); + m_wayWorkSizeAdjust = -1; + // cerr << "m_stepWorkSizeAdjust: " << m_stepWorkSizeAdjust << ", m_wayWorkSizeAdjust: " << m_wayWorkSizeAdjust << endl; + + // cerr << "Batch of " << m_globalWorkSize << " took " << chrono::duration_cast(d).count() << " ms, >> " << s_msPerBatch << " ms." << endl; + m_globalWorkSize = max(128, m_globalWorkSize - m_stepWorkSizeAdjust); // cerr << "New global work size" << m_globalWorkSize << endl; } else if (d < chrono::milliseconds(s_msPerBatch * 9 / 10)) { - // cerr << "Batch of " << m_globalWorkSize << " took " << chrono::duration_cast(d).count() << " ms, << " << _msPerBatch << " ms." << endl; - m_globalWorkSize = min(pow(2, m_deviceBits) - 1, m_globalWorkSize - s_workgroupSize); + // Divide the step by 2 when adjustment way change + if (m_wayWorkSizeAdjust < 1) + m_stepWorkSizeAdjust = max(1, m_stepWorkSizeAdjust / 2); + m_wayWorkSizeAdjust = 1; + // cerr << "m_stepWorkSizeAdjust: " << m_stepWorkSizeAdjust << ", m_wayWorkSizeAdjust: " << m_wayWorkSizeAdjust << endl; + + // cerr << "Batch of " << m_globalWorkSize << " took " << chrono::duration_cast(d).count() << " ms, << " << s_msPerBatch << " ms." << endl; + m_globalWorkSize = min(pow(2, m_deviceBits) - 1, m_globalWorkSize + m_stepWorkSizeAdjust); // Global work size should never be less than the workgroup size m_globalWorkSize = max(s_workgroupSize, m_globalWorkSize); // cerr << "New global work size" << m_globalWorkSize << endl; diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 3ea2fba4a..c51c38fb6 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -90,6 +90,11 @@ private: bool m_openclOnePointOne; unsigned m_deviceBits; + /// The step used in the work size adjustment + unsigned int m_stepWorkSizeAdjust; + /// The Work Size way of adjustment, > 0 when previously increased, < 0 when previously decreased + int m_wayWorkSizeAdjust = 0; + /// The local work size for the search static unsigned s_workgroupSize; /// The initial global work size for the searches diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp index 602c60b4a..26cf451d0 100644 --- a/libethcore/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -213,6 +213,7 @@ void KeyManager::kill(Address const& _a) m_addrLookup.erase(_a); m_keyInfo.erase(id); m_store.kill(id); + write(m_keysFile); } Addresses KeyManager::accounts() const diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index d9a54a1ee..768ed223f 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -597,9 +597,19 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Most of the time these two will be equal - only when we're doing a chain revert will they not be if (common != last) + { + // Erase the number-lookup cache for the segment of the chain that we're reverting (if any). + unsigned n = number(route.front()); + DEV_WRITE_GUARDED(x_blockHashes) + for (auto i = route.begin(); i != route.end() && *i != common; ++i, --n) + m_blockHashes.erase(h256(u256(n))); + DEV_WRITE_GUARDED(x_transactionAddresses) + m_transactionAddresses.clear(); // TODO: could perhaps delete them individually? + // If we are reverting previous blocks, we need to clear their blooms (in particular, to // rebuild any higher level blooms that they contributed to). clearBlockBlooms(number(common) + 1, number(last) + 1); + } // Go through ret backwards until hash != last.parent and update m_transactionAddresses, m_blockHashes for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i) @@ -630,7 +640,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } } // Collate transaction hashes and remember who they were. - h256s newTransactionAddresses; + //h256s newTransactionAddresses; { bytes blockBytes; RLP blockRLP(*i == _block.info.hash() ? _block.block : &(blockBytes = block(*i))); diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 161a7d35a..0cca63a80 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -426,7 +426,14 @@ void InheritanceSpecifier::checkTypeRequirements() solAssert(base, "Base contract not available."); TypePointers parameterTypes = ContractType(*base).getConstructorType()->getParameterTypes(); if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); + BOOST_THROW_EXCEPTION(createTypeError( + "Wrong argument count for constructor call: " + + toString(m_arguments.size()) + + " arguments given but expected " + + toString(parameterTypes.size()) + + "." + )); + for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError( @@ -629,7 +636,13 @@ void ModifierInvocation::checkTypeRequirements(vector if (!parameters) BOOST_THROW_EXCEPTION(createTypeError("Referenced declaration is neither modifier nor base class.")); if (parameters->size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation.")); + BOOST_THROW_EXCEPTION(createTypeError( + "Wrong argument count for modifier invocation: " + + toString(m_arguments.size()) + + " arguments given but expected " + + toString(parameters->size()) + + "." + )); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*(*parameters)[i]->getType())) BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError( @@ -834,7 +847,13 @@ void FunctionCall::checkTypeRequirements(TypePointers const*) // function parameters TypePointers const& parameterTypes = functionType->getParameterTypes(); if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); + BOOST_THROW_EXCEPTION(createTypeError( + "Wrong argument count for function call: " + + toString(m_arguments.size()) + + " arguments given but expected " + + toString(parameterTypes.size()) + + "." + )); if (isPositionalCall) { diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index f13b28173..48ee5a052 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -37,7 +37,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // this copies source to target and also clears target if it was larger // need to leave "target_ref target_byte_off" on the stack at the end - // stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top) + // stack layout: [source_ref] [source length] target_ref (top) solAssert(_targetType.location() == DataLocation::Storage, ""); IntegerType uint256(256); @@ -53,16 +53,11 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons bool haveByteOffsetTarget = !directCopy && targetBaseType->getStorageBytes() <= 16; unsigned byteOffsetSize = (haveByteOffsetSource ? 1 : 0) + (haveByteOffsetTarget ? 1 : 0); - // stack: source_ref [source_byte_off] [source_length] target_ref target_byte_off + // stack: source_ref [source_length] target_ref // store target_ref - // arrays always start at zero byte offset, pop offset - m_context << eth::Instruction::POP; for (unsigned i = _sourceType.getSizeOnStack(); i > 0; --i) m_context << eth::swapInstruction(i); - // stack: target_ref source_ref [source_byte_off] [source_length] - if (sourceIsStorage) - // arrays always start at zero byte offset, pop offset - m_context << eth::Instruction::POP; + // stack: target_ref source_ref [source_length] // stack: target_ref source_ref [source_length] // retrieve source length if (_sourceType.location() != DataLocation::CallData || !_sourceType.isDynamicallySized()) @@ -90,7 +85,6 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons m_context << eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP; - m_context << u256(0); return; } // compute hashes (data positions) @@ -136,13 +130,11 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons solAssert(byteOffsetSize == 0, "Byte offset for array as base type."); auto const& sourceBaseArrayType = dynamic_cast(*sourceBaseType); m_context << eth::Instruction::DUP3; - if (sourceIsStorage) - m_context << u256(0); - else if (sourceBaseArrayType.location() == DataLocation::Memory) + if (sourceBaseArrayType.location() == DataLocation::Memory) m_context << eth::Instruction::MLOAD; - m_context << eth::dupInstruction(sourceIsStorage ? 4 : 3) << u256(0); + m_context << eth::Instruction::DUP3; copyArrayToStorage(dynamic_cast(*targetBaseType), sourceBaseArrayType); - m_context << eth::Instruction::POP << eth::Instruction::POP; + m_context << eth::Instruction::POP; } else if (directCopy) { @@ -235,7 +227,6 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // stack: target_ref target_data_end target_data_pos_updated clearStorageLoop(*targetBaseType); m_context << eth::Instruction::POP; - m_context << u256(0); } void ArrayUtils::copyArrayToMemory(const ArrayType& _sourceType, bool _padToWordBoundaries) const @@ -365,7 +356,6 @@ void ArrayUtils::copyArrayToMemory(const ArrayType& _sourceType, bool _padToWord u256 storageSize = _sourceType.getBaseType()->getStorageSize(); solAssert(storageSize > 1 || (storageSize == 1 && storageBytes > 0), ""); - m_context << eth::Instruction::POP; // remove offset, arrays always start new slot retrieveLength(_sourceType); // stack here: memory_offset storage_offset length // jump to end if length is zero diff --git a/libsolidity/ArrayUtils.h b/libsolidity/ArrayUtils.h index c047fdcc0..80ffc008a 100644 --- a/libsolidity/ArrayUtils.h +++ b/libsolidity/ArrayUtils.h @@ -41,8 +41,8 @@ public: /// Copies an array to an array in storage. The arrays can be of different types only if /// their storage representation is the same. - /// Stack pre: source_reference [source_byte_offset/source_length] target_reference target_byte_offset - /// Stack post: target_reference target_byte_offset + /// Stack pre: source_reference [source_length] target_reference + /// Stack post: target_reference void copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const; /// Copies the data part of an array (which cannot be dynamically nested) from anywhere /// to a given position in memory. diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 297e6aa09..e62f59e23 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -229,7 +229,7 @@ void CompilerUtils::encodeToMemory( if (arrayType.location() == DataLocation::CallData) m_context << eth::Instruction::DUP2; // length is on stack else if (arrayType.location() == DataLocation::Storage) - m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD; + m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; else { solAssert(arrayType.location() == DataLocation::Memory, ""); @@ -416,13 +416,6 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp { // stack: (variably sized) unsigned stackSize = typeOnStack.getSizeOnStack(); - bool fromStorage = (typeOnStack.location() == DataLocation::Storage); - if (fromStorage) - { - stackSize--; - // remove storage offset, as requested by ArrayUtils::retrieveLength - m_context << eth::Instruction::POP; - } ArrayUtils(m_context).retrieveLength(typeOnStack); // allocate memory @@ -446,8 +439,6 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp { solAssert(typeOnStack.getBaseType()->isValueType(), ""); copyToStackTop(2 + stackSize, stackSize); - if (fromStorage) - m_context << u256(0); // add byte offset again ArrayUtils(m_context).copyArrayToMemory(typeOnStack); } else @@ -462,6 +453,8 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp copyToStackTop(3 + stackSize, stackSize); copyToStackTop(2 + stackSize, 1); ArrayUtils(m_context).accessIndex(typeOnStack, false); + if (typeOnStack.location() == DataLocation::Storage) + StorageItem(m_context, *typeOnStack.getBaseType()).retrieveValue(SourceLocation(), true); convertType(*typeOnStack.getBaseType(), *targetType.getBaseType(), _cleanupNeeded); storeInMemoryDynamic(*targetType.getBaseType(), true); m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD; @@ -512,8 +505,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp if (typeOnStack.location() != DataLocation::Memory) { solAssert(typeOnStack.location() == DataLocation::Storage, ""); - // stack: - m_context << eth::Instruction::POP; + // stack: m_context << typeOnStack.memorySize(); allocateMemory(); m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 058358187..6a2e185c5 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -714,7 +714,6 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) { case DataLocation::Storage: { - m_context << eth::Instruction::POP; // structs always align to new slot pair const& offsets = type.getStorageOffsetsOfMember(member); m_context << offsets.first << eth::Instruction::ADD << u256(offsets.second); setLValueToStorageItem(_memberAccess); @@ -792,8 +791,6 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) Type const& baseType = *_indexAccess.getBaseExpression().getType(); if (baseType.getCategory() == Type::Category::Mapping) { - // storage byte offset is ignored for mappings, it should be zero. - m_context << eth::Instruction::POP; // stack: storage_base_ref Type const& keyType = *dynamic_cast(baseType).getKeyType(); m_context << u256(0); // memory position @@ -812,10 +809,6 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) ArrayType const& arrayType = dynamic_cast(baseType); solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); - // remove storage byte offset - if (arrayType.location() == DataLocation::Storage) - m_context << eth::Instruction::POP; - _indexAccess.getIndexExpression()->accept(*this); // stack layout: [] ArrayUtils(m_context).accessIndex(arrayType); @@ -942,24 +935,27 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type } else { - IntegerType const& type = dynamic_cast(_type); - bool const c_isSigned = type.isSigned(); + bool isSigned = false; + if (auto type = dynamic_cast(&_type)) + isSigned = type->isSigned(); switch (_operator) { case Token::GreaterThanOrEqual: - m_context << (c_isSigned ? eth::Instruction::SLT : eth::Instruction::LT) - << eth::Instruction::ISZERO; + m_context << + (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) << + eth::Instruction::ISZERO; break; case Token::LessThanOrEqual: - m_context << (c_isSigned ? eth::Instruction::SGT : eth::Instruction::GT) - << eth::Instruction::ISZERO; + m_context << + (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) << + eth::Instruction::ISZERO; break; case Token::GreaterThan: - m_context << (c_isSigned ? eth::Instruction::SGT : eth::Instruction::GT); + m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); break; case Token::LessThan: - m_context << (c_isSigned ? eth::Instruction::SLT : eth::Instruction::LT); + m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); diff --git a/libsolidity/LValue.cpp b/libsolidity/LValue.cpp index 82701ea95..c754bbfca 100644 --- a/libsolidity/LValue.cpp +++ b/libsolidity/LValue.cpp @@ -152,7 +152,14 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const { // stack: storage_key storage_offset if (!m_dataType.isValueType()) - return; // no distinction between value and reference for non-value types + { + solAssert(m_dataType.getSizeOnStack() == 1, "Invalid storage ref size."); + if (_remove) + m_context << eth::Instruction::POP; // remove byte offset + else + m_context << eth::Instruction::DUP2; + return; + } if (!_remove) CompilerUtils(m_context).copyToStackTop(sizeOnStack(), sizeOnStack()); if (m_dataType.getStorageBytes() == 32) @@ -236,16 +243,18 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc "Wrong type conversation for assignment."); if (m_dataType.getCategory() == Type::Category::Array) { + m_context << eth::Instruction::POP; // remove byte offset ArrayUtils(m_context).copyArrayToStorage( dynamic_cast(m_dataType), dynamic_cast(_sourceType)); if (_move) - utils.popStackElement(m_dataType); + m_context << eth::Instruction::POP; } else if (m_dataType.getCategory() == Type::Category::Struct) { - // stack layout: source_ref [source_offset] target_ref target_offset - // note that we have structs, so offsets should be zero and are ignored + // stack layout: source_ref target_ref target_offset + // note that we have structs, so offset should be zero and are ignored + m_context << eth::Instruction::POP; auto const& structType = dynamic_cast(m_dataType); auto const& sourceType = dynamic_cast(_sourceType); solAssert( @@ -262,44 +271,37 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc TypePointer sourceMemberType = sourceType.getMemberType(member.name); if (sourceType.location() == DataLocation::Storage) { - // stack layout: source_ref source_offset target_ref target_offset + // stack layout: source_ref target_ref pair const& offsets = sourceType.getStorageOffsetsOfMember(member.name); - m_context << offsets.first << eth::Instruction::DUP5 << eth::Instruction::ADD; + m_context << offsets.first << eth::Instruction::DUP3 << eth::Instruction::ADD; m_context << u256(offsets.second); - // stack: source_ref source_off target_ref target_off source_member_ref source_member_off + // stack: source_ref target_ref source_member_ref source_member_off StorageItem(m_context, *sourceMemberType).retrieveValue(_location, true); - // stack: source_ref source_off target_ref target_off source_value... + // stack: source_ref target_ref source_value... } else { solAssert(sourceType.location() == DataLocation::Memory, ""); - // stack layout: source_ref target_ref target_offset + // stack layout: source_ref target_ref TypePointer sourceMemberType = sourceType.getMemberType(member.name); m_context << sourceType.memoryOffsetOfMember(member.name); - m_context << eth::Instruction::DUP4 << eth::Instruction::ADD; + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; MemoryItem(m_context, *sourceMemberType).retrieveValue(_location, true); - // stack layout: source_ref target_ref target_offset source_value... + // stack layout: source_ref target_ref source_value... } unsigned stackSize = sourceMemberType->getSizeOnStack(); pair const& offsets = structType.getStorageOffsetsOfMember(member.name); - m_context << eth::dupInstruction(2 + stackSize) << offsets.first << eth::Instruction::ADD; + m_context << eth::dupInstruction(1 + stackSize) << offsets.first << eth::Instruction::ADD; m_context << u256(offsets.second); - // stack: source_ref [source_off] target_ref target_off source_value... target_member_ref target_member_byte_off + // stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true); } - // stack layout: source_ref [source_offset] target_ref target_offset - unsigned sourceStackSize = sourceType.getSizeOnStack(); + // stack layout: source_ref target_ref + solAssert(sourceType.getSizeOnStack() == 1, "Unexpected source size."); if (_move) - utils.popStackSlots(2 + sourceType.getSizeOnStack()); - else if (sourceType.getSizeOnStack() >= 1) - { - // remove the source ref - solAssert(sourceStackSize <= 2, "Invalid stack size."); - m_context << eth::swapInstruction(sourceStackSize); - if (sourceStackSize == 2) - m_context << eth::Instruction::POP; - m_context << eth::Instruction::SWAP2 << eth::Instruction::POP; - } + utils.popStackSlots(2); + else + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; } else BOOST_THROW_EXCEPTION( @@ -429,8 +431,6 @@ StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, const m_arrayType(_arrayType) { solAssert(m_arrayType.isDynamicallySized(), ""); - // storage byte offset must be zero - m_context << eth::Instruction::POP; } void StorageArrayLength::retrieveValue(SourceLocation const&, bool _remove) const diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 3ea9caa7d..91ef16b50 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -210,6 +210,8 @@ TypePointer Type::forLiteral(Literal const& _literal) case Token::FalseLiteral: return make_shared(); case Token::Number: + if (!IntegerConstantType::isValidLiteral(_literal)) + return TypePointer(); return make_shared(_literal); case Token::StringLiteral: return make_shared(_literal); @@ -321,6 +323,19 @@ const MemberList IntegerType::AddressMemberList({ {"send", make_shared(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)} }); +bool IntegerConstantType::isValidLiteral(const Literal& _literal) +{ + try + { + bigint x(_literal.getValue()); + } + catch (...) + { + return false; + } + return true; +} + IntegerConstantType::IntegerConstantType(Literal const& _literal) { m_value = bigint(_literal.getValue()); @@ -823,11 +838,9 @@ unsigned ArrayType::getSizeOnStack() const if (m_location == DataLocation::CallData) // offset [length] (stack top) return 1 + (isDynamicallySized() ? 1 : 0); - else if (m_location == DataLocation::Storage) - // storage_key storage_offset - return 2; else - // offset + // storage slot or memory offset + // byte offset inside storage value is omitted return 1; } @@ -1035,14 +1048,6 @@ bool StructType::canLiveOutsideStorage() const return true; } -unsigned StructType::getSizeOnStack() const -{ - if (location() == DataLocation::Storage) - return 2; // slot and offset - else - return 1; -} - string StructType::toString(bool _short) const { string ret = "struct " + m_struct.getName(); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index e17a262c6..8bdfc5e69 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -286,6 +286,9 @@ class IntegerConstantType: public Type public: virtual Category getCategory() const override { return Category::IntegerConstant; } + /// @returns true if the literal is a valid integer. + static bool isValidLiteral(Literal const& _literal); + explicit IntegerConstantType(Literal const& _literal); explicit IntegerConstantType(bigint _value): m_value(_value) {} @@ -298,7 +301,6 @@ public: virtual bool canBeStored() const override { return false; } virtual bool canLiveOutsideStorage() const override { return false; } - virtual unsigned getSizeOnStack() const override { return 1; } virtual std::string toString(bool _short) const override; virtual u256 literalValue(Literal const* _literal) const override; @@ -580,7 +582,6 @@ public: u256 memorySize() const; virtual u256 getStorageSize() const override; virtual bool canLiveOutsideStorage() const override; - virtual unsigned getSizeOnStack() const override; virtual std::string toString(bool _short) const override; virtual MemberList const& getMembers() const override; @@ -616,7 +617,6 @@ public: { return externalType()->getCalldataEncodedSize(_padded); } - virtual unsigned getSizeOnStack() const override { return 1; } virtual unsigned getStorageBytes() const override; virtual bool canLiveOutsideStorage() const override { return true; } virtual std::string toString(bool _short) const override; @@ -812,7 +812,6 @@ public: virtual bool operator==(Type const& _other) const override; virtual std::string toString(bool _short) const override; - virtual unsigned getSizeOnStack() const override { return 2; } virtual bool canLiveOutsideStorage() const override { return false; } TypePointer const& getKeyType() const { return m_keyType; } diff --git a/libwhisper/WhisperDB.cpp b/libwhisper/WhisperDB.cpp new file mode 100644 index 000000000..fd2eef060 --- /dev/null +++ b/libwhisper/WhisperDB.cpp @@ -0,0 +1,69 @@ +/* + 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 . +*/ +/** @file WhisperDB.cpp +* @author Vladislav Gluhovsky +* @date July 2015 + */ + +#include "WhisperDB.h" +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::shh; + +WhisperDB::WhisperDB() +{ + string path = dev::getDataDir("shh"); + boost::filesystem::create_directories(path); + leveldb::Options op; + op.create_if_missing = true; + op.max_open_files = 256; + leveldb::DB* p = nullptr; + leveldb::Status status = leveldb::DB::Open(op, path + "/messages", &p); + m_db.reset(p); + if (!status.ok()) + BOOST_THROW_EXCEPTION(FailedToOpenLevelDB(status.ToString())); +} + +string WhisperDB::lookup(dev::h256 const& _key) const +{ + string ret; + leveldb::Slice slice((char const*)_key.data(), _key.size); + leveldb::Status status = m_db->Get(m_readOptions, slice, &ret); + if (!status.ok() && !status.IsNotFound()) + BOOST_THROW_EXCEPTION(FailedLookupInLevelDB(status.ToString())); + + return ret; +} + +void WhisperDB::insert(dev::h256 const& _key, string const& _value) +{ + leveldb::Slice slice((char const*)_key.data(), _key.size); + leveldb::Status status = m_db->Put(m_writeOptions, slice, _value); + if (!status.ok()) + BOOST_THROW_EXCEPTION(FailedInsertInLevelDB(status.ToString())); +} + +void WhisperDB::kill(dev::h256 const& _key) +{ + leveldb::Slice slice((char const*)_key.data(), _key.size); + leveldb::Status status = m_db->Delete(m_writeOptions, slice); + if (!status.ok()) + BOOST_THROW_EXCEPTION(FailedDeleteInLevelDB(status.ToString())); +} diff --git a/libwhisper/WhisperDB.h b/libwhisper/WhisperDB.h new file mode 100644 index 000000000..0cb97e244 --- /dev/null +++ b/libwhisper/WhisperDB.h @@ -0,0 +1,55 @@ +/* + 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 . +*/ +/** @file WhisperDB.h +* @author Vladislav Gluhovsky +* @date July 2015 + */ + +#pragma once + +#include +#include +#include "Common.h" + +namespace dev +{ +namespace shh +{ + +struct FailedToOpenLevelDB: virtual Exception { FailedToOpenLevelDB(std::string const& _message): Exception(_message) {} }; +struct FailedInsertInLevelDB: virtual Exception { FailedInsertInLevelDB(std::string const& _message): Exception(_message) {} }; +struct FailedLookupInLevelDB: virtual Exception { FailedLookupInLevelDB(std::string const& _message): Exception(_message) {} }; +struct FailedDeleteInLevelDB: virtual Exception { FailedDeleteInLevelDB(std::string const& _message): Exception(_message) {} }; + +class WhisperDB +{ + public: + WhisperDB(); + ~WhisperDB() {} + + std::string lookup(dev::h256 const& _key) const; + void insert(dev::h256 const& _key, std::string const& _value); + void kill(dev::h256 const& _key); + +private: + leveldb::ReadOptions m_readOptions; + leveldb::WriteOptions m_writeOptions; + std::unique_ptr m_db; +}; + +} +} \ No newline at end of file diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 9a1b16935..f49ed1e09 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -479,7 +479,7 @@ bytes importCode(json_spirit::mObject& _o) { bytes code; if (_o["code"].type() == json_spirit::str_type) - if (_o["code"].get_str().find_first_of("0x") != 0) + if (_o["code"].get_str().find("0x") != 0) code = compileLLL(_o["code"].get_str(), false); else code = fromHex(_o["code"].get_str().substr(2)); @@ -767,6 +767,8 @@ Options::Options() wallet = true; else if (arg == "--nonetwork") nonetwork = true; + else if (arg == "--network") + nonetwork = false; else if (arg == "--nodag") nodag = true; else if (arg == "--all") diff --git a/test/TestHelper.h b/test/TestHelper.h index 4ac59e917..420278838 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -224,7 +224,7 @@ public: bool inputLimits = false; bool bigData = false; bool wallet = false; - bool nonetwork = false; + bool nonetwork = true; bool nodag = true; /// @} diff --git a/test/libdevcore/rlp.cpp b/test/libdevcore/rlp.cpp index 74e422b05..016b183e2 100644 --- a/test/libdevcore/rlp.cpp +++ b/test/libdevcore/rlp.cpp @@ -71,6 +71,7 @@ namespace dev { bytes payloadToDecode = fromHex(o["out"].get_str()); RLP payload(payloadToDecode); + ostringstream() << payload; if (payload.isEmpty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Decoded Empty RLP!")); o["in"] = "VALID"; @@ -128,6 +129,7 @@ namespace dev { bytes payloadToDecode = fromHex(o["out"].get_str()); RLP payload(payloadToDecode); + ostringstream() << payload; if (rlpType == RlpType::Test) dev::test::checkRLPAgainstJson(inputData, payload); diff --git a/test/libethcore/keymanager.cpp b/test/libethcore/keymanager.cpp index 44ee9ae51..808f060fc 100644 --- a/test/libethcore/keymanager.cpp +++ b/test/libethcore/keymanager.cpp @@ -107,11 +107,10 @@ BOOST_AUTO_TEST_CASE(KeyManagerHints) BOOST_AUTO_TEST_CASE(KeyManagerAccounts) { - KeyManager km; string password = "hardPassword"; TransientDirectory tmpDir; - km.setKeysFile(tmpDir.path()+ "keysFile.json"); + KeyManager km(tmpDir.path()+ "keysFile.json", tmpDir.path()); BOOST_CHECK_NO_THROW(km.create(password)); BOOST_CHECK(km.accounts().empty()); @@ -121,4 +120,31 @@ BOOST_AUTO_TEST_CASE(KeyManagerAccounts) km.kill(a); } +BOOST_AUTO_TEST_CASE(KeyManagerKill) +{ + string password = "hardPassword"; + TransientDirectory tmpDir; + KeyPair kp = KeyPair::create(); + + { + KeyManager km(tmpDir.path() + "keysFile.json", tmpDir.path()); + BOOST_CHECK_NO_THROW(km.create(password)); + BOOST_CHECK(km.accounts().empty()); + BOOST_CHECK(km.load(password)); + BOOST_CHECK(km.import(kp.secret(), "test")); + } + { + KeyManager km(tmpDir.path() + "keysFile.json", tmpDir.path()); + BOOST_CHECK(km.load(password)); + Addresses addresses = km.accounts(); + BOOST_CHECK(addresses.size() == 1 && addresses[0] == kp.address()); + km.kill(addresses[0]); + } + { + KeyManager km(tmpDir.path() + "keysFile.json", tmpDir.path()); + BOOST_CHECK(km.load(password)); + BOOST_CHECK(km.accounts().empty()); + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/BlockchainTestsFiller/bcRPC_API_TestFiller.json b/test/libethereum/BlockchainTestsFiller/bcRPC_API_TestFiller.json index b31f1fa48..2b867e4ae 100644 --- a/test/libethereum/BlockchainTestsFiller/bcRPC_API_TestFiller.json +++ b/test/libethereum/BlockchainTestsFiller/bcRPC_API_TestFiller.json @@ -27,6 +27,7 @@ }, "blocks" : [ { + "blocknumber" : "1", "transactions" : [ { "data" : "create contract: 6295ee1b4f6dd65047762f924ecd367c17eabf8f", @@ -42,7 +43,8 @@ "uncleHeaders" : [ ] }, - { + { + "blocknumber" : "2", "transactions" : [ { "data" : "getBool", @@ -59,6 +61,7 @@ ] }, { + "blocknumber" : "3", "transactions" : [ { "data" : "getInt8", @@ -75,6 +78,7 @@ ] }, { + "blocknumber" : "4", "transactions" : [ { "data" : "getUint8", @@ -127,6 +131,7 @@ ] }, { + "blocknumber" : "5", "transactions" : [ { "data" : "getInt256", @@ -143,6 +148,7 @@ ] }, { + "blocknumber" : "6", "transactions" : [ { "data" : "getUint256", @@ -159,6 +165,7 @@ ] }, { + "blocknumber" : "7", "transactions" : [ { "data" : "getAddress", @@ -175,6 +182,7 @@ ] }, { + "blocknumber" : "8", "transactions" : [ { "data" : "getBytes32", @@ -191,6 +199,7 @@ ] }, { + "blocknumber" : "9", "transactions" : [ { "data" : "setBool", @@ -207,6 +216,7 @@ ] }, { + "blocknumber" : "10", "transactions" : [ { "data" : "setBool", @@ -223,6 +233,7 @@ ] }, { + "blocknumber" : "11", "transactions" : [ { "data" : "setInt8", @@ -239,6 +250,7 @@ ] }, { + "blocknumber" : "12", "transactions" : [ { "data" : "setUint8", @@ -255,6 +267,7 @@ ] }, { + "blocknumber" : "13", "transactions" : [ { "data" : "setInt256", @@ -271,6 +284,7 @@ ] }, { + "blocknumber" : "14", "transactions" : [ { "data" : "setUint256", @@ -287,6 +301,7 @@ ] }, { + "blocknumber" : "15", "transactions" : [ { "data" : "setAddress", @@ -303,6 +318,7 @@ ] }, { + "blocknumber" : "16", "transactions" : [ { "data" : "setBytes32", @@ -319,6 +335,7 @@ ] }, { + "blocknumber" : "17", "transactions" : [ { "data" : "getInt8", @@ -335,6 +352,7 @@ ] }, { + "blocknumber" : "18", "transactions" : [ { "data" : "getUint8", @@ -351,6 +369,7 @@ ] }, { + "blocknumber" : "19", "transactions" : [ { "data" : "getInt256", @@ -367,6 +386,7 @@ ] }, { + "blocknumber" : "20", "transactions" : [ { "data" : "getUint256", @@ -383,6 +403,7 @@ ] }, { + "blocknumber" : "21", "transactions" : [ { "data" : "getAddress", @@ -399,6 +420,7 @@ ] }, { + "blocknumber" : "22", "transactions" : [ { "data" : "getBytes32", @@ -415,6 +437,7 @@ ] }, { + "blocknumber" : "23", "transactions" : [ { "data" : "log0", @@ -431,6 +454,7 @@ ] }, { + "blocknumber" : "24", "transactions" : [ { "data" : "log0a", @@ -447,6 +471,7 @@ ] }, { + "blocknumber" : "25", "transactions" : [ { "data" : "log1", @@ -463,6 +488,7 @@ ] }, { + "blocknumber" : "26", "transactions" : [ { "data" : "log1a", @@ -479,6 +505,43 @@ ] }, { + "blocknumber" : "27", + "reverted": true, + "transactions" : [ + { + "data" : "log1", + "data" : "0x4e7ad367", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "26", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "28", + "reverted": true, + "transactions" : [ + { + "data" : "log1a", + "data" : "0x4e7ad367", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "27", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "blocknumber" : "27", "transactions" : [ { "data" : "log2", @@ -495,6 +558,7 @@ ] }, { + "blocknumber" : "28", "transactions" : [ { "data" : "log2a", @@ -511,6 +575,7 @@ ] }, { + "blocknumber" : "29", "transactions" : [ { "data" : "log3", @@ -527,6 +592,7 @@ ] }, { + "blocknumber" : "30", "transactions" : [ { "data" : "log3a", @@ -543,6 +609,7 @@ ] }, { + "blocknumber" : "31", "transactions" : [ { "data" : "log4", @@ -559,6 +626,7 @@ ] }, { + "blocknumber" : "32", "transactions" : [ { "data" : "log4a", diff --git a/test/libp2p/peer.cpp b/test/libp2p/peer.cpp index e84e86027..5417450b4 100644 --- a/test/libp2p/peer.cpp +++ b/test/libp2p/peer.cpp @@ -43,28 +43,32 @@ BOOST_AUTO_TEST_CASE(host) if (test::Options::get().nonetwork) return; - VerbosityHolder sentinel(10); - + VerbosityHolder setTemporaryLevel(10); NetworkPreferences host1prefs("127.0.0.1", 30301, false); - NetworkPreferences host2prefs("127.0.0.1", 30302, false); - + NetworkPreferences host2prefs("127.0.0.1", 30302, false); Host host1("Test", host1prefs); - host1.start(); - Host host2("Test", host2prefs); - auto node2 = host2.id(); + host1.start(); host2.start(); - - while (!host2.haveNetwork()) - this_thread::sleep_for(chrono::milliseconds(20)); + auto node2 = host2.id(); + int const step = 10; + + for (int i = 0; i < 3000 && (!host1.isStarted() || !host2.isStarted()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); + + BOOST_REQUIRE(host1.isStarted() && host2.isStarted()); host1.addNode(node2, NodeIPEndpoint(bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort)); - this_thread::sleep_for(chrono::seconds(3)); - - auto host1peerCount = host1.peerCount(); - auto host2peerCount = host2.peerCount(); - BOOST_REQUIRE_EQUAL(host1peerCount, 1); - BOOST_REQUIRE_EQUAL(host2peerCount, 1); + for (int i = 0; i < 3000 && (!host1.haveNetwork() || !host2.haveNetwork()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); + + BOOST_REQUIRE(host1.haveNetwork() && host2.haveNetwork()); + + for (int i = 0; i < 3000 && (!host1.peerCount() || !host2.peerCount()); i += step) + this_thread::sleep_for(chrono::milliseconds(step)); + + BOOST_REQUIRE_EQUAL(host1.peerCount(), 1); + BOOST_REQUIRE_EQUAL(host2.peerCount(), 1); } BOOST_AUTO_TEST_CASE(networkConfig) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index ad2175461..9f806347e 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -585,6 +585,22 @@ BOOST_AUTO_TEST_CASE(inc_dec_operators) BOOST_CHECK(callContractFunction("f()") == encodeArgs(0x53866)); } +BOOST_AUTO_TEST_CASE(bytes_comparison) +{ + char const* sourceCode = R"( + contract test { + function f() returns (bool) { + bytes2 a = "a"; + bytes2 x = "aa"; + bytes2 b = "b"; + return a < x && x < b; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(true)); +} + BOOST_AUTO_TEST_CASE(state_smoke_test) { char const* sourceCode = "contract test {\n" diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 1e40ee4f6..0f5e4800f 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2110,6 +2110,30 @@ BOOST_AUTO_TEST_CASE(literal_strings) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(invalid_integer_literal_fraction) +{ + char const* text = R"( + contract Foo { + function f() { + var x = 1.20; + } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(invalid_integer_literal_exp) +{ + char const* text = R"( + contract Foo { + function f() { + var x = 1e2; + } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libwhisper/whisperDB.cpp b/test/libwhisper/whisperDB.cpp new file mode 100644 index 000000000..552820621 --- /dev/null +++ b/test/libwhisper/whisperDB.cpp @@ -0,0 +1,122 @@ +/* +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 . +*/ +/** @file whisperMessage.cpp +* @author Vladislav Gluhovsky +* @date July 2015 +*/ + +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::shh; + +BOOST_AUTO_TEST_SUITE(whisperDB) + +BOOST_AUTO_TEST_CASE(basic) +{ + VerbosityHolder setTemporaryLevel(10); + cnote << "Testing Whisper DB..."; + + string s; + string const text1 = "lorem"; + string const text2 = "ipsum"; + h256 h1(0xBEEF); + h256 h2(0xC0FFEE); + WhisperDB db; + + db.kill(h1); + db.kill(h2); + + s = db.lookup(h1); + BOOST_REQUIRE(s.empty()); + + db.insert(h1, text2); + s = db.lookup(h2); + BOOST_REQUIRE(s.empty()); + s = db.lookup(h1); + BOOST_REQUIRE(!s.compare(text2)); + + db.insert(h1, text1); + s = db.lookup(h2); + BOOST_REQUIRE(s.empty()); + s = db.lookup(h1); + BOOST_REQUIRE(!s.compare(text1)); + + db.insert(h2, text2); + s = db.lookup(h2); + BOOST_REQUIRE(!s.compare(text2)); + s = db.lookup(h1); + BOOST_REQUIRE(!s.compare(text1)); + + db.kill(h1); + db.kill(h2); + + s = db.lookup(h2); + BOOST_REQUIRE(s.empty()); + s = db.lookup(h1); + BOOST_REQUIRE(s.empty()); +} + +BOOST_AUTO_TEST_CASE(persistence) +{ + VerbosityHolder setTemporaryLevel(10); + cnote << "Testing persistence of Whisper DB..."; + + string s; + string const text1 = "sator"; + string const text2 = "arepo"; + h256 const h1(0x12345678); + h256 const h2(0xBADD00DE); + + { + WhisperDB db; + db.kill(h1); + db.kill(h2); + s = db.lookup(h1); + BOOST_REQUIRE(s.empty()); + db.insert(h1, text2); + s = db.lookup(h2); + BOOST_REQUIRE(s.empty()); + s = db.lookup(h1); + BOOST_REQUIRE(!s.compare(text2)); + } + + this_thread::sleep_for(chrono::milliseconds(20)); + + { + WhisperDB db; + db.insert(h1, text1); + db.insert(h2, text2); + } + + this_thread::sleep_for(chrono::milliseconds(20)); + + { + WhisperDB db; + s = db.lookup(h2); + BOOST_REQUIRE(!s.compare(text2)); + s = db.lookup(h1); + BOOST_REQUIRE(!s.compare(text1)); + db.kill(h1); + db.kill(h2); + } +} + +BOOST_AUTO_TEST_SUITE_END()