diff --git a/test/libsolidity/SolidityFixedFeeRegistrar.cpp b/test/libsolidity/SolidityFixedFeeRegistrar.cpp
new file mode 100644
index 000000000..26373499a
--- /dev/null
+++ b/test/libsolidity/SolidityFixedFeeRegistrar.cpp
@@ -0,0 +1,237 @@
+/*
+ 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 .
+*/
+/**
+ * @author Christian
+ * @date 2015
+ * Tests for a fixed fee registrar contract.
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+static char const* registrarCode = R"DELIMITER(
+//sol FixedFeeRegistrar
+// Simple global registrar with fixed-fee reservations.
+// @authors:
+// Gav Wood
+
+contract Registrar {
+ event Changed(string indexed name);
+
+ function owner(string _name) constant returns (address o_owner);
+ function addr(string _name) constant returns (address o_address);
+ function subRegistrar(string _name) constant returns (address o_subRegistrar);
+ function content(string _name) constant returns (bytes32 o_content);
+}
+
+contract FixedFeeRegistrar is Registrar {
+ struct Record {
+ address addr;
+ address subRegistrar;
+ bytes32 content;
+ address owner;
+ }
+
+ modifier onlyrecordowner(string _name) { if (m_record(_name).owner == msg.sender) _ }
+
+ function reserve(string _name) {
+ Record rec = m_record(_name);
+ if (rec.owner == 0 && msg.value >= c_fee) {
+ rec.owner = msg.sender;
+ Changed(_name);
+ }
+ }
+ function disown(string _name, address _refund) onlyrecordowner(_name) {
+ delete m_recordData[uint(sha3(_name)) / 8];
+ _refund.send(c_fee);
+ Changed(_name);
+ }
+ function transfer(string _name, address _newOwner) onlyrecordowner(_name) {
+ m_record(_name).owner = _newOwner;
+ Changed(_name);
+ }
+ function setAddr(string _name, address _a) onlyrecordowner(_name) {
+ m_record(_name).addr = _a;
+ Changed(_name);
+ }
+ function setSubRegistrar(string _name, address _registrar) onlyrecordowner(_name) {
+ m_record(_name).subRegistrar = _registrar;
+ Changed(_name);
+ }
+ function setContent(string _name, bytes32 _content) onlyrecordowner(_name) {
+ m_record(_name).content = _content;
+ Changed(_name);
+ }
+
+ function record(string _name) constant returns (address o_addr, address o_subRegistrar, bytes32 o_content, address o_owner) {
+ Record rec = m_record(_name);
+ o_addr = rec.addr;
+ o_subRegistrar = rec.subRegistrar;
+ o_content = rec.content;
+ o_owner = rec.owner;
+ }
+ function addr(string _name) constant returns (address) { return m_record(_name).addr; }
+ function subRegistrar(string _name) constant returns (address) { return m_record(_name).subRegistrar; }
+ function content(string _name) constant returns (bytes32) { return m_record(_name).content; }
+ function owner(string _name) constant returns (address) { return m_record(_name).owner; }
+
+ Record[2**253] m_recordData;
+ function m_record(string _name) constant internal returns (Record storage o_record) {
+ return m_recordData[uint(sha3(_name)) / 8];
+ }
+ uint constant c_fee = 69 ether;
+}
+)DELIMITER";
+
+static unique_ptr s_compiledRegistrar;
+
+class RegistrarTestFramework: public ExecutionFramework
+{
+protected:
+ void deployRegistrar()
+ {
+ if (!s_compiledRegistrar)
+ {
+ m_optimize = true;
+ m_compiler.reset(false, m_addStandardSources);
+ m_compiler.addSource("", registrarCode);
+ ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed");
+ s_compiledRegistrar.reset(new bytes(m_compiler.getBytecode("FixedFeeRegistrar")));
+ }
+ sendMessage(*s_compiledRegistrar, true);
+ BOOST_REQUIRE(!m_output.empty());
+ }
+ u256 const m_fee = u256("69000000000000000000");
+};
+
+/// This is a test suite that tests optimised code!
+BOOST_FIXTURE_TEST_SUITE(SolidityFixedFeeRegistrar, RegistrarTestFramework)
+
+BOOST_AUTO_TEST_CASE(creation)
+{
+ deployRegistrar();
+}
+
+BOOST_AUTO_TEST_CASE(reserve)
+{
+ // Test that reserving works and fee is taken into account.
+ deployRegistrar();
+ string name[] = {"abc", "def", "ghi"};
+ m_sender = Address(0x123);
+ BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name[0])) == encodeArgs());
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[0])) == encodeArgs(h256(0x123)));
+ BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee + 1, encodeDyn(name[1])) == encodeArgs());
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[1])) == encodeArgs(h256(0x123)));
+ BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee - 1, encodeDyn(name[2])) == encodeArgs());
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[2])) == encodeArgs(h256(0)));
+}
+
+BOOST_AUTO_TEST_CASE(double_reserve)
+{
+ // Test that it is not possible to re-reserve from a different address.
+ deployRegistrar();
+ string name = "abc";
+ m_sender = Address(0x123);
+ BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(0x123)));
+
+ m_sender = Address(0x124);
+ BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(0x123)));
+}
+
+BOOST_AUTO_TEST_CASE(properties)
+{
+ // Test setting and retrieving the various properties works.
+ deployRegistrar();
+ string names[] = {"abc", "def", "ghi"};
+ size_t addr = 0x9872543;
+ for (string const& name: names)
+ {
+ addr++;
+ size_t sender = addr + 10007;
+ m_sender = Address(sender);
+ // setting by sender works
+ BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(sender)));
+ BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), u256(addr), u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(addr));
+ BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), addr + 20, u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(addr + 20));
+ BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), addr + 90, u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(addr + 90));
+ // but not by someone else
+ m_sender = Address(h256(addr + 10007 - 1));
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(sender));
+ BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), addr + 1, u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(addr));
+ BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), addr + 20 + 1, u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(addr + 20));
+ BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), addr + 90 + 1, u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(addr + 90));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(transfer)
+{
+ deployRegistrar();
+ string name = "abc";
+ m_sender = Address(0x123);
+ BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
+ BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), u256(123), u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("transfer(string,address)", u256(0x40), u256(555), u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(555)));
+ BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(u256(123)));
+}
+
+BOOST_AUTO_TEST_CASE(disown)
+{
+ deployRegistrar();
+ string name = "abc";
+ m_sender = Address(0x123);
+ BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
+ BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), u256(123), u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), u256(124), u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), u256(125), u256(name.length()), name) == encodeArgs());
+
+ BOOST_CHECK_EQUAL(m_state.balance(Address(0x124)), 0);
+ BOOST_CHECK(callContractFunction("disown(string,address)", u256(0x40), u256(0x124), name.size(), name) == encodeArgs());
+ BOOST_CHECK_EQUAL(m_state.balance(Address(0x124)), m_fee);
+
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(u256(0)));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+} // end namespaces
diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h
index 0e8637012..e4c4087f4 100644
--- a/test/libsolidity/solidityExecutionFramework.h
+++ b/test/libsolidity/solidityExecutionFramework.h
@@ -130,6 +130,7 @@ public:
static bytes encode(bool _value) { return encode(byte(_value)); }
static bytes encode(int _value) { return encode(u256(_value)); }
+ static bytes encode(size_t _value) { return encode(u256(_value)); }
static bytes encode(char const* _value) { return encode(std::string(_value)); }
static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; }
static bytes encode(u256 const& _value) { return toBigEndian(_value); }