Merge pull request #1341 from chriseth/sol_packedStorage

Packed storage for arrays.
This commit is contained in:
chriseth 2015-03-20 12:54:36 +01:00
commit ff06ea3aaf
3 changed files with 163 additions and 1 deletions

View File

@ -3088,6 +3088,123 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_dynamic)
BOOST_CHECK(callContractFunction("test()") == encodeArgs(9, 4));
}
BOOST_AUTO_TEST_CASE(array_copy_different_packing)
{
char const* sourceCode = R"(
contract c {
bytes8[] data1; // 4 per slot
bytes10[] data2; // 3 per slot
function test() returns (bytes10 a, bytes10 b, bytes10 c, bytes10 d, bytes10 e) {
data1.length = 9;
for (uint i = 0; i < data1.length; ++i)
data1[i] = bytes8(i);
data2 = data1;
a = data2[1];
b = data2[2];
c = data2[3];
d = data2[4];
e = data2[5];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(
asString(fromHex("0000000000000001")),
asString(fromHex("0000000000000002")),
asString(fromHex("0000000000000003")),
asString(fromHex("0000000000000004")),
asString(fromHex("0000000000000005"))
));
}
BOOST_AUTO_TEST_CASE(array_copy_target_simple)
{
char const* sourceCode = R"(
contract c {
bytes8[9] data1; // 4 per slot
bytes17[10] data2; // 1 per slot, no offset counter
function test() returns (bytes17 a, bytes17 b, bytes17 c, bytes17 d, bytes17 e) {
for (uint i = 0; i < data1.length; ++i)
data1[i] = bytes8(i);
data2[8] = data2[9] = 2;
data2 = data1;
a = data2[1];
b = data2[2];
c = data2[3];
d = data2[4];
e = data2[9];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(
asString(fromHex("0000000000000001")),
asString(fromHex("0000000000000002")),
asString(fromHex("0000000000000003")),
asString(fromHex("0000000000000004")),
asString(fromHex("0000000000000000"))
));
}
BOOST_AUTO_TEST_CASE(array_copy_target_leftover)
{
// test that leftover elements in the last slot of target are correctly cleared during assignment
char const* sourceCode = R"(
contract c {
byte[10] data1;
bytes2[32] data2;
function test() returns (uint check, uint res1, uint res2) {
uint i;
for (i = 0; i < data2.length; ++i)
data2[i] = 0xffff;
check = uint(data2[31]) * 0x10000 | uint(data2[14]);
for (i = 0; i < data1.length; ++i)
data1[i] = byte(uint8(1 + i));
data2 = data1;
for (i = 0; i < 16; ++i)
res1 |= uint(data2[i]) * 0x10000**i;
for (i = 0; i < 16; ++i)
res2 |= uint(data2[16 + i]) * 0x10000**i;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(
u256("0xffffffff"),
asString(fromHex("0000000000000000""000000000a000900""0800070006000500""0400030002000100")),
asString(fromHex("0000000000000000""0000000000000000""0000000000000000""0000000000000000"))
));
}
BOOST_AUTO_TEST_CASE(array_copy_target_leftover2)
{
// since the copy always copies whole slots, we have to make sure that the source size maxes
// out a whole slot and at the same time there are still elements left in the target at that point
char const* sourceCode = R"(
contract c {
bytes8[4] data1; // fits into one slot
bytes10[6] data2; // 4 elements need two slots
function test() returns (bytes10 r1, bytes10 r2, bytes10 r3) {
data1[0] = 1;
data1[1] = 2;
data1[2] = 3;
data1[3] = 4;
for (uint i = 0; i < data2.length; ++i)
data2[i] = bytes10(0xffff00 | (1 + i));
data2 = data1;
r1 = data2[3];
r2 = data2[4];
r3 = data2[5];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(
asString(fromHex("0000000000000004")),
asString(fromHex("0000000000000000")),
asString(fromHex("0000000000000000"))
));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct)
{
char const* sourceCode = R"(
@ -3214,7 +3331,7 @@ BOOST_AUTO_TEST_CASE(array_copy_nested_array)
char const* sourceCode = R"(
contract c {
uint[4][] a;
uint[5][] b;
uint[10][] b;
uint[][] c;
function test(uint[2][] d) external returns (uint) {
a = d;
@ -3480,6 +3597,30 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_delete)
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(packed_storage_structs_with_bytes0)
{
char const* sourceCode = R"(
contract C {
struct str { uint8 a; bytes0 b; uint8 c; }
uint8 a;
bytes0 x;
uint8 b;
str data;
function test() returns (bool) {
a = 2;
b = 3;
data.a = 4;
data.c = 5;
delete x;
delete data.b;
return a == 2 && b == 3 && data.a == 4 && data.c == 5;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(true));
}
BOOST_AUTO_TEST_SUITE_END()
}

View File

@ -1446,6 +1446,16 @@ BOOST_AUTO_TEST_CASE(local_const_variable)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError);
}
BOOST_AUTO_TEST_CASE(bytes0_array)
{
char const* text = R"(
contract Foo {
bytes0[] illegalArray;
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_SUITE_END()
}

View File

@ -75,6 +75,17 @@ BOOST_AUTO_TEST_CASE(storage_layout_mapping)
BOOST_CHECK(*members.getMemberStorageOffset("final") == make_pair(u256(3), unsigned(0)));
}
BOOST_AUTO_TEST_CASE(storage_layout_arrays)
{
BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared<FixedBytesType>(1), 32).getStorageSize() == 1);
BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared<FixedBytesType>(1), 33).getStorageSize() == 2);
BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared<FixedBytesType>(2), 31).getStorageSize() == 2);
BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared<FixedBytesType>(7), 8).getStorageSize() == 2);
BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared<FixedBytesType>(7), 9).getStorageSize() == 3);
BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared<FixedBytesType>(31), 9).getStorageSize() == 9);
BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared<FixedBytesType>(32), 9).getStorageSize() == 9);
}
BOOST_AUTO_TEST_SUITE_END()
}