diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6cd9e338f..271f3ed65 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -363,6 +363,9 @@ else()
endif()
if (EVMJIT)
+ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" AND NOT DEFINED LLVM_DIR)
+ set(LLVM_DIR "${CMAKE_SOURCE_DIR}/extdep/install/windows/x64/share/llvm/cmake")
+ endif()
set(EVMJIT_CPP TRUE) # include CPP-JIT connector
add_subdirectory(evmjit)
endif()
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 60c07fd8d..dd3d5bbd3 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -638,18 +638,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 +669,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 24520d8c4..67058a473 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/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp
index 942819ba8..644568a1b 100644
--- a/libethash-cl/ethash_cl_miner.cpp
+++ b/libethash-cl/ethash_cl_miner.cpp
@@ -317,6 +317,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
@@ -522,14 +524,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 fb28dc04b..73ba674a3 100644
--- a/libethash-cl/ethash_cl_miner.h
+++ b/libethash-cl/ethash_cl_miner.h
@@ -89,6 +89,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/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..2ed1ed4d0 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));
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()