Browse Source

Merge branch 'develop' into netFix

cl-refactor
subtly 10 years ago
parent
commit
b58c78385a
  1. 39
      libethereum/BlockChain.cpp
  2. 1
      libethereum/TransactionQueue.cpp
  3. 11
      libsolidity/AST.cpp
  4. 22
      libsolidity/ExpressionCompiler.cpp
  5. 13
      libsolidity/LValue.cpp
  6. 32
      libsolidity/Types.cpp
  7. 4
      libsolidity/Types.h
  8. 70
      test/libsolidity/SolidityEndToEndTest.cpp
  9. 26
      test/libsolidity/SolidityNameAndTypeResolution.cpp
  10. 31
      test/libsolidity/SolidityWallet.cpp

39
libethereum/BlockChain.cpp

@ -96,6 +96,15 @@ ldb::Slice dev::eth::toSlice(h256 const& _h, unsigned _sub)
#endif
}
namespace dev
{
class WriteBatchNoter: public ldb::WriteBatch::Handler
{
virtual void Put(ldb::Slice const& _key, ldb::Slice const& _value) { cnote << "Put" << toHex(bytesConstRef(_key)) << "=>" << toHex(bytesConstRef(_value)); }
virtual void Delete(ldb::Slice const& _key) { cnote << "Delete" << toHex(bytesConstRef(_key)); }
};
}
#if ETH_DEBUG&&0
static const chrono::system_clock::duration c_collectionDuration = chrono::seconds(15);
static const unsigned c_collectionQueueSize = 2;
@ -638,8 +647,25 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
clog(BlockChainChat) << " Imported but not best (oTD:" << details(last).totalDifficulty << " > TD:" << td << ")";
}
m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch);
ldb::Status o = m_blocksDB->Write(m_writeOptions, &blocksBatch);
if (!o.ok())
{
cwarn << "Error writing to blockchain database: " << o.ToString();
WriteBatchNoter n;
blocksBatch.Iterate(&n);
cwarn << "Fail writing to blockchain database. Bombing out.";
exit(-1);
}
o = m_extrasDB->Write(m_writeOptions, &extrasBatch);
if (!o.ok())
{
cwarn << "Error writing to extras database: " << o.ToString();
WriteBatchNoter n;
extrasBatch.Iterate(&n);
cwarn << "Fail writing to extras database. Bombing out.";
exit(-1);
}
#if ETH_PARANOIA || !ETH_TRUE
if (isKnown(_block.info.hash()) && !details(_block.info.hash()))
@ -667,7 +693,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
{
m_lastBlockHash = newLastBlockHash;
m_lastBlockNumber = newLastBlockNumber;
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&m_lastBlockHash, 32));
o = m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&m_lastBlockHash, 32));
if (!o.ok())
{
cwarn << "Error writing to extras database: " << o.ToString();
cout << "Put" << toHex(bytesConstRef(ldb::Slice("best"))) << "=>" << toHex(bytesConstRef(ldb::Slice((char const*)&m_lastBlockHash, 32)));
cwarn << "Fail writing to extras database. Bombing out.";
exit(-1);
}
}
#if ETH_PARANOIA || !ETH_TRUE

1
libethereum/TransactionQueue.cpp

@ -220,6 +220,7 @@ bool TransactionQueue::remove_WITH_LOCK(h256 const& _txHash)
unsigned TransactionQueue::waiting(Address const& _a) const
{
ReadGuard l(m_lock);
auto it = m_senders.equal_range(_a);
unsigned ret = 0;
for (auto i = it.first; i != it.second; ++i, ++ret) {}

11
libsolidity/AST.cpp

@ -535,7 +535,16 @@ void VariableDeclaration::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Variable cannot have void type."));
m_type = type->mobileType();
}
if (m_isStateVariable && getVisibility() >= Visibility::Public && !FunctionType(*this).externalType())
solAssert(!!m_type, "");
if (!m_isStateVariable)
{
if (m_type->dataStoredIn(DataLocation::Memory) || m_type->dataStoredIn(DataLocation::CallData))
if (!m_type->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(createTypeError(
"Type " + m_type->toString() + " is only valid in storage."
));
}
else if (getVisibility() >= Visibility::Public && !FunctionType(*this).externalType())
BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for public state variables."));
}

22
libsolidity/ExpressionCompiler.cpp

@ -679,10 +679,24 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case Type::Category::Struct:
{
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
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);
switch (type.location())
{
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);
break;
}
case DataLocation::Memory:
{
solAssert(false, "Member access for memory structs not yet implemented.");
break;
}
default:
solAssert(false, "Illegal data location for struct.");
}
break;
}
case Type::Category::Enum:

13
libsolidity/LValue.cpp

@ -69,17 +69,8 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo
void StackVariable::setToZero(SourceLocation const& _location, bool) const
{
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset);
if (stackDiff > 16)
BOOST_THROW_EXCEPTION(
CompilerError() <<
errinfo_sourceLocation(_location) <<
errinfo_comment("Stack too deep, try removing local variables.")
);
solAssert(stackDiff >= m_size - 1, "");
for (unsigned i = 0; i < m_size; ++i)
m_context << u256(0) << eth::swapInstruction(stackDiff + 1 - i)
<< eth::Instruction::POP;
CompilerUtils(m_context).pushZeroValue(m_dataType);
storeValue(m_dataType, _location, true);
}
MemoryItem::MemoryItem(CompilerContext& _compilerContext, Type const& _type, bool _padded):

32
libsolidity/Types.cpp

@ -671,6 +671,26 @@ TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const
return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer();
}
TypePointer ReferenceType::unaryOperatorResult(Token::Value _operator) const
{
if (_operator != Token::Delete)
return TypePointer();
// delete can be used on everything except calldata references or storage pointers
// (storage references are ok)
switch (location())
{
case DataLocation::CallData:
return TypePointer();
case DataLocation::Memory:
return make_shared<VoidType>();
case DataLocation::Storage:
return m_isPointer ? TypePointer() : make_shared<VoidType>();
default:
solAssert(false, "");
}
return TypePointer();
}
TypePointer ReferenceType::copyForLocationIfReference(DataLocation _location, TypePointer const& _type)
{
if (auto type = dynamic_cast<ReferenceType const*>(_type.get()))
@ -738,13 +758,6 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
}
}
TypePointer ArrayType::unaryOperatorResult(Token::Value _operator) const
{
if (_operator == Token::Delete)
return make_shared<VoidType>();
return TypePointer();
}
bool ArrayType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
@ -962,11 +975,6 @@ bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const
return this->m_struct == convertTo.m_struct;
}
TypePointer StructType::unaryOperatorResult(Token::Value _operator) const
{
return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer();
}
bool StructType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())

4
libsolidity/Types.h

@ -376,6 +376,7 @@ public:
explicit ReferenceType(DataLocation _location): m_location(_location) {}
DataLocation location() const { return m_location; }
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual unsigned memoryHeadSize() const override { return 32; }
/// @returns a copy of this type with location (recursively) changed to @a _location,
@ -444,11 +445,11 @@ public:
{}
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override;
virtual bool isDynamicallySized() const override { return m_hasDynamicLength; }
virtual u256 getStorageSize() const override;
virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
virtual unsigned getSizeOnStack() const override;
virtual std::string toString(bool _short) const override;
virtual MemberList const& getMembers() const override
@ -545,7 +546,6 @@ public:
//@todo only storage until we have non-storage structs
ReferenceType(DataLocation::Storage), m_struct(_struct) {}
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override;
virtual u256 getStorageSize() const override;

70
test/libsolidity/SolidityEndToEndTest.cpp

@ -4493,7 +4493,7 @@ BOOST_AUTO_TEST_CASE(bytes_in_constructors_packer)
}
}
contract Main is Base {
function Main(bytes s, uint x) Base(x, s){}//f(s)) {}
function Main(bytes s, uint x) Base(x, f(s)) {}
function f(bytes s) returns (bytes) {
return s;
}
@ -4517,6 +4517,45 @@ BOOST_AUTO_TEST_CASE(bytes_in_constructors_packer)
);
}
BOOST_AUTO_TEST_CASE(arrays_in_constructors)
{
char const* sourceCode = R"(
contract Base {
uint public m_x;
address[] m_s;
function Base(uint x, address[] s) {
m_x = x;
m_s = s;
}
function part(uint i) returns (address) {
return m_s[i];
}
}
contract Main is Base {
function Main(address[] s, uint x) Base(x, f(s)) {}
function f(address[] s) returns (address[]) {
return s;
}
}
contract Creator {
function f(uint x, address[] s) returns (uint r, address ch) {
var c = new Main(s, x);
r = c.m_x();
ch = c.part(x);
}
}
)";
compileAndRun(sourceCode, 0, "Creator");
vector<u256> s1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
bytes dyn1 = encodeArgs(u256(s1.size()), s1);
u256 x = 7;
bytes args1 = encodeArgs(x, u256(0x40)) + dyn1;
BOOST_REQUIRE(
callContractFunction("f(uint256,address[])", asString(args1)) ==
encodeArgs(x, s1[unsigned(x)])
);
}
BOOST_AUTO_TEST_CASE(arrays_from_and_to_storage)
{
char const* sourceCode = R"(
@ -4691,6 +4730,35 @@ BOOST_AUTO_TEST_CASE(memory_types_initialisation)
BOOST_CHECK(callContractFunction("nestedStat()") == encodeArgs(vector<u256>(3 * 7)));
}
BOOST_AUTO_TEST_CASE(memory_arrays_delete)
{
char const* sourceCode = R"(
contract Test {
function del() returns (uint24[3][4]) {
uint24[3][4] memory x;
for (uint24 i = 0; i < x.length; i ++)
for (uint24 j = 0; j < x[i].length; j ++)
x[i][j] = i * 0x10 + j;
delete x[1];
delete x[3][2];
return x;
}
}
)";
compileAndRun(sourceCode, 0, "Test");
vector<u256> data(3 * 4);
for (unsigned i = 0; i < 4; i++)
for (unsigned j = 0; j < 3; j++)
{
u256 v = 0;
if (!(i == 1 || (i == 3 && j == 2)))
v = i * 0x10 + j;
data[i * 3 + j] = v;
}
BOOST_CHECK(callContractFunction("del()") == encodeArgs(data));
}
BOOST_AUTO_TEST_CASE(memory_arrays_index_access_write)
{
char const* sourceCode = R"(

26
test/libsolidity/SolidityNameAndTypeResolution.cpp

@ -1900,6 +1900,18 @@ BOOST_AUTO_TEST_CASE(storage_location_local_variables)
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
}
BOOST_AUTO_TEST_CASE(no_mappings_in_memory_array)
{
char const* sourceCode = R"(
contract C {
function f() {
mapping(uint=>uint)[] memory x;
}
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(assignment_mem_to_local_storage_variable)
{
char const* sourceCode = R"(
@ -1931,6 +1943,20 @@ BOOST_AUTO_TEST_CASE(storage_assign_to_different_local_variable)
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(no_delete_on_storage_pointers)
{
char const* sourceCode = R"(
contract C {
uint[] data;
function f() {
var x = data;
delete x;
}
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(assignment_mem_storage_variable_directly)
{
char const* sourceCode = R"(

31
test/libsolidity/SolidityWallet.cpp

@ -200,17 +200,17 @@ contract multiowned {
}
// the number of owners that must confirm the same operation before it is run.
uint m_required;
uint public m_required;
// pointer used to find a free slot in m_owners
uint m_numOwners;
uint public m_numOwners;
// list of owners
uint[256] m_owners;
uint[256] public m_owners;
uint constant c_maxOwners = 250;
// index on the list of owners to allow reverse lookup
mapping(uint => uint) m_ownerIndex;
mapping(uint => uint) public m_ownerIndex;
// the ongoing operations.
mapping(bytes32 => PendingState) m_pending;
bytes32[] m_pendingIndex;
mapping(bytes32 => PendingState) public m_pending;
bytes32[] public m_pendingIndex;
}
// inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable)
@ -251,9 +251,9 @@ contract daylimit is multiowned {
}
// determines today's index.
function today() private constant returns (uint) { return now / 1 days; }
uint m_spentToday;
uint m_dailyLimit;
uint m_lastDay;
uint public m_spentToday;
uint public m_dailyLimit;
uint public m_lastDay;
}
// interface contract for multisig proxy contracts; see below for docs.
contract multisig {
@ -275,11 +275,14 @@ contract Wallet is multisig, multiowned, daylimit {
uint value;
bytes data;
}
/*
// logged events:
// Funds has arrived into the wallet (record how much).
event Deposit(address from, uint value);
// Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going).
event SingleTransact(address owner, uint value, address to, bytes data);
// Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going).
event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data);*/
// constructor - just pass on the owner arra to the multiowned.
event Created();
function Wallet() {
@ -299,7 +302,7 @@ contract Wallet is multisig, multiowned, daylimit {
// If not, goes into multisig process. We provide a hash on return to allow the sender to provide
// shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value
// and _data arguments). They still get the option of using them if they want, anyways.
function execute(address _to, uint _value, bytes _data) onlyowner external returns (bytes32 _r) {
function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 _r) {
// first, take the opportunity to check that we're under the daily limit.
if (underLimit(_value)) {
SingleTransact(msg.sender, _value, _to, _data);
@ -332,8 +335,14 @@ contract Wallet is multisig, multiowned, daylimit {
delete m_txs[m_pendingIndex[i]];
super.clearPending();
}
// // internally confirm transaction with all of the info. returns true iff confirmed good and executed.
// function confirmVerbose(bytes32 _h, address _to, uint _value, bytes _data) private onlymanyowners(_h) returns (bool) {
// _to.call.value(_value)(_data);
// MultiTransact("out", msg.sender, _h, _value, _to);
// return true;
// }
// pending transactions we have at present.
mapping (bytes32 => Transaction) m_txs;
mapping (bytes32 => Transaction) public m_txs;
}
)DELIMITER";

Loading…
Cancel
Save