Browse Source

Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

cl-refactor
Gav Wood 10 years ago
parent
commit
3cb8edb031
  1. 3
      CMakeLists.txt
  2. 12
      alethzero/MainWin.cpp
  3. 7
      eth/main.cpp
  4. 22
      libethash-cl/ethash_cl_miner.cpp
  5. 5
      libethash-cl/ethash_cl_miner.h
  6. 1
      libethcore/KeyManager.cpp
  7. 25
      libsolidity/AST.cpp
  8. 22
      libsolidity/ArrayUtils.cpp
  9. 4
      libsolidity/ArrayUtils.h
  10. 16
      libsolidity/CompilerUtils.cpp
  11. 26
      libsolidity/ExpressionCompiler.cpp
  12. 54
      libsolidity/LValue.cpp
  13. 29
      libsolidity/Types.cpp
  14. 7
      libsolidity/Types.h
  15. 69
      libwhisper/WhisperDB.cpp
  16. 55
      libwhisper/WhisperDB.h
  17. 2
      test/TestHelper.cpp
  18. 30
      test/libethcore/keymanager.cpp
  19. 70
      test/libethereum/BlockchainTestsFiller/bcRPC_API_TestFiller.json
  20. 36
      test/libp2p/peer.cpp
  21. 16
      test/libsolidity/SolidityEndToEndTest.cpp
  22. 24
      test/libsolidity/SolidityNameAndTypeResolution.cpp
  23. 122
      test/libwhisper/whisperDB.cpp

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

12
alethzero/MainWin.cpp

@ -638,18 +638,22 @@ pair<Address, bytes> 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<Address>(ethereum()->call(g_newNameReg, abiIn("addr(bytes32)", ::toString32(_n))).output);
Address a = abiOut<Address>(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<Address, bytes> 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);

7
eth/main.cpp

@ -910,7 +910,12 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> 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;

22
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<CL_DEVICE_ADDRESS_BITS>();
// 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<chrono::milliseconds>(d).count() << " ms, >> " << _msPerBatch << " ms." << endl;
m_globalWorkSize = max<unsigned>(128, m_globalWorkSize + s_workgroupSize);
// Divide the step by 2 when adjustment way change
if (m_wayWorkSizeAdjust > -1)
m_stepWorkSizeAdjust = max<unsigned>(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<chrono::milliseconds>(d).count() << " ms, >> " << s_msPerBatch << " ms." << endl;
m_globalWorkSize = max<unsigned>(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<chrono::milliseconds>(d).count() << " ms, << " << _msPerBatch << " ms." << endl;
m_globalWorkSize = min<unsigned>(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<unsigned>(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<chrono::milliseconds>(d).count() << " ms, << " << s_msPerBatch << " ms." << endl;
m_globalWorkSize = min<unsigned>(pow(2, m_deviceBits) - 1, m_globalWorkSize + m_stepWorkSizeAdjust);
// Global work size should never be less than the workgroup size
m_globalWorkSize = max<unsigned>(s_workgroupSize, m_globalWorkSize);
// cerr << "New global work size" << m_globalWorkSize << endl;

5
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

1
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

25
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<ContractDefinition const*>
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)
{

22
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<ArrayType const&>(*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<ArrayType const&>(*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

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

16
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: <source ref> (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: <source ref> <source byte offset>
m_context << eth::Instruction::POP;
// stack: <source ref>
m_context << typeOnStack.memorySize();
allocateMemory();
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;

26
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<u256, unsigned> 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<MappingType const&>(baseType).getKeyType();
m_context << u256(0); // memory position
@ -812,10 +809,6 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(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: <base_ref> [<length>] <index>
ArrayUtils(m_context).accessIndex(arrayType);
@ -942,24 +935,27 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
}
else
{
IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
bool const c_isSigned = type.isSigned();
bool isSigned = false;
if (auto type = dynamic_cast<IntegerType const*>(&_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."));

54
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<ArrayType const&>(m_dataType),
dynamic_cast<ArrayType const&>(_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<StructType const&>(m_dataType);
auto const& sourceType = dynamic_cast<StructType const&>(_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<u256, unsigned> 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<u256, unsigned> 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

29
libsolidity/Types.cpp

@ -210,6 +210,8 @@ TypePointer Type::forLiteral(Literal const& _literal)
case Token::FalseLiteral:
return make_shared<BoolType>();
case Token::Number:
if (!IntegerConstantType::isValidLiteral(_literal))
return TypePointer();
return make_shared<IntegerConstantType>(_literal);
case Token::StringLiteral:
return make_shared<StringLiteralType>(_literal);
@ -321,6 +323,19 @@ const MemberList IntegerType::AddressMemberList({
{"send", make_shared<FunctionType>(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();

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

69
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 <http://www.gnu.org/licenses/>.
*/
/** @file WhisperDB.cpp
* @author Vladislav Gluhovsky <vlad@ethdev.com>
* @date July 2015
*/
#include "WhisperDB.h"
#include <boost/filesystem.hpp>
#include <libdevcore/FileSystem.h>
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()));
}

55
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 <http://www.gnu.org/licenses/>.
*/
/** @file WhisperDB.h
* @author Vladislav Gluhovsky <vlad@ethdev.com>
* @date July 2015
*/
#pragma once
#include <libdevcore/db.h>
#include <libdevcore/FixedHash.h>
#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<leveldb::DB> m_db;
};
}
}

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

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

70
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",

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

16
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"

24
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()
}

122
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 <http://www.gnu.org/licenses/>.
*/
/** @file whisperMessage.cpp
* @author Vladislav Gluhovsky <vlad@ethdev.com>
* @date July 2015
*/
#include <thread>
#include <boost/test/unit_test.hpp>
#include <libwhisper/WhisperDB.h>
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()
Loading…
Cancel
Save