From c416286a1f88ed0eddb78d983068af1a75448e86 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 01/75] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. From 1562aa43ca163dde3cf9b6c49d7a6ebc0538a1d6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 02/75] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. From 046223bfaee3133703bdf8c6a03b5c5d8f50a7c3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 03/75] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. From 92b59b44fd08175eae97e1eb2f88d9cf4421a9d5 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 27 Jul 2015 12:32:13 +0200 Subject: [PATCH 04/75] refactoring of topic test From af17426942e09b557b890b3ff2f1a8074cacf077 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 27 Jul 2015 14:13:07 +0200 Subject: [PATCH 05/75] updated test topic advertising From 0e1c26cf7d19b0551431c5b7cb3564330c190ea5 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 27 Jul 2015 16:59:45 +0200 Subject: [PATCH 06/75] minor update From f8d262e635ab2979f32b1b3c0f5b32ad408b060f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 28 Jul 2015 08:35:42 +0200 Subject: [PATCH 07/75] add extcodecopy stack test From 4f83ec6842197b973d4ee3e4c2ba67c1e7cd8d4b Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 28 Jul 2015 09:00:17 +0200 Subject: [PATCH 08/75] add documentation From 060aaf7502d8c6edc96c56a470a59c4257dd34af Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 09:20:09 +0200 Subject: [PATCH 09/75] Secure datatypes now copyable only to similar datatypes. More restrictions on usage to prevent accidental data leakage. From fe0d04c29dc81502aac843f99ac6d00c745edc15 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 10/75] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. From 7758f9ec8a3d4b850f6b08155ee60f945bc6fdcd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 09:20:09 +0200 Subject: [PATCH 11/75] Secure datatypes now copyable only to similar datatypes. More restrictions on usage to prevent accidental data leakage. From 3ed133e5df9a6d3aeebdfc7be43df8c8d633e970 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Jul 2015 20:47:05 +0200 Subject: [PATCH 12/75] Introduce vector_ref::cleanse, code adapted from openSSL. Introduce secure_vector and bytesSec, make Secret auto-cleansing. From f90f3d23a1c1bf32d964d4027bb659abb50a95b5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 09:20:09 +0200 Subject: [PATCH 13/75] Secure datatypes now copyable only to similar datatypes. More restrictions on usage to prevent accidental data leakage. From c06522a385bb41ff3804726f128f34411e9f7cc9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 28 Jul 2015 14:11:53 +0200 Subject: [PATCH 14/75] Fix tests. From 29e85183cef67e1c8d0140f00d2bea0f41c13b06 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 28 Jul 2015 23:51:08 +0200 Subject: [PATCH 15/75] check nothing when creating raw blocks in blockchaintests --- TestHelper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TestHelper.cpp b/TestHelper.cpp index ab9a17495..a07378592 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(Ethash::BlockHeader& _bi) sealer->generateSeal(_bi); sealed.waitNot({}); sealer.reset(); - _bi = Ethash::BlockHeader(sealed, IgnoreSeal, h256{}, HeaderData); + _bi = Ethash::BlockHeader(sealed, CheckNothing, h256{}, HeaderData); } } @@ -843,7 +843,7 @@ dev::eth::Ethash::BlockHeader constructHeader( rlpStream << _parentHash << _sha3Uncles << _coinbaseAddress << _stateRoot << _transactionsRoot << _receiptsRoot << _logBloom << _difficulty << _number << _gasLimit << _gasUsed << _timestamp << _extraData << h256{} << Nonce{}; - return Ethash::BlockHeader(rlpStream.out(), IgnoreSeal, h256{}, HeaderData); + return Ethash::BlockHeader(rlpStream.out(), CheckNothing, h256{}, HeaderData); } void updateEthashSeal(dev::eth::Ethash::BlockHeader& _header, h256 const& _mixHash, dev::eth::Nonce const& _nonce) @@ -857,7 +857,7 @@ void updateEthashSeal(dev::eth::Ethash::BlockHeader& _header, h256 const& _mixHa header << sourceRlp[i]; header << _mixHash << _nonce; - _header = Ethash::BlockHeader(header.out(), IgnoreSeal, h256{}, HeaderData); + _header = Ethash::BlockHeader(header.out(), CheckNothing, h256{}, HeaderData); } namespace From 48cc04c3c74de1b50919aa2790f95fd208dc14a6 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 28 Jul 2015 23:51:48 +0200 Subject: [PATCH 16/75] disable bcBruncleTests for Frontier (will be readded later) From df69b920cfc25c75ca494264ae2641598a26f0cd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 29 Jul 2015 07:52:55 +0200 Subject: [PATCH 17/75] Use boost's guaranteed non-deterministic random number generator. If it compiles, it's safe. From 4e79ecd90f7452ee52a8b57170224e412d290309 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 29 Jul 2015 09:16:55 +0200 Subject: [PATCH 18/75] style fix. From a75158129f31cf523f9ce0596d3930be20647f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 29 Jul 2015 15:10:41 +0200 Subject: [PATCH 19/75] Fix EVM JIT stack limit checking. Tests inlcuded. From ad9c2ab5ce2dfa9e889d769d1b17ec685ca16ab0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 29 Jul 2015 11:34:37 +0200 Subject: [PATCH 20/75] Make Nonce use Secret. From b16d421a99cc8f1cfed9a91037b7c36b53e76d5c Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 29 Jul 2015 17:29:43 +0200 Subject: [PATCH 21/75] add timestamp tests From 0936956eb6be6203965bf6d20a505d030f5d8dea Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 29 Jul 2015 17:47:14 +0200 Subject: [PATCH 22/75] Add new js admin nodeInfo command Implementation to follow ... From eef65bf701f881fc786362f5a01a7e310811ba63 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 29 Jul 2015 18:33:04 +0200 Subject: [PATCH 23/75] Modify code to prepare for rebase From cf53d80b7d8cf4d4e9c17a86a5f5ca4ab9d7c22a Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 29 Jul 2015 19:30:28 +0200 Subject: [PATCH 24/75] adjust blockGasLimit in order to get same result for gasPricer test in olympic/frontier moder From 840a0108cce52831327388542b3b7b7ed76089a0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Jul 2015 19:31:25 +0200 Subject: [PATCH 25/75] Tests for FixedFeeRegistrar. --- libsolidity/SolidityFixedFeeRegistrar.cpp | 237 ++++++++++++++++++++++ libsolidity/solidityExecutionFramework.h | 1 + 2 files changed, 238 insertions(+) create mode 100644 libsolidity/SolidityFixedFeeRegistrar.cpp diff --git a/libsolidity/SolidityFixedFeeRegistrar.cpp b/libsolidity/SolidityFixedFeeRegistrar.cpp new file mode 100644 index 000000000..26373499a --- /dev/null +++ b/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/libsolidity/solidityExecutionFramework.h b/libsolidity/solidityExecutionFramework.h index 0e8637012..e4c4087f4 100644 --- a/libsolidity/solidityExecutionFramework.h +++ b/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); } From b2454fd2d5352aaaf50ea75e92a6d95384e743bf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 29 Jul 2015 21:47:06 +0200 Subject: [PATCH 26/75] Version bump. From 863f955006a2e1dfdece01d746c9060b58c9ef7d Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 30 Jul 2015 13:26:15 +0200 Subject: [PATCH 27/75] temp. remove bruncle test From 8418c80adc86c230c7077bc6e888a0a0c2a93984 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 30 Jul 2015 19:31:44 +0200 Subject: [PATCH 28/75] Disable network test by default. --- TestHelper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestHelper.h b/TestHelper.h index 735535492..48eb42c55 100644 --- a/TestHelper.h +++ b/TestHelper.h @@ -239,7 +239,7 @@ public: bool inputLimits = false; bool bigData = false; bool wallet = false; - bool nonetwork = false; + bool nonetwork = true; bool nodag = true; /// @} From 59da5baded9156f526e67ebb0bd685607b41fa8e Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 31 Jul 2015 18:28:27 +0200 Subject: [PATCH 29/75] bugfix From e1861aff8f34ed7fa64f6d410d0eb212012e0eac Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Tue, 28 Jul 2015 16:41:49 +0200 Subject: [PATCH 30/75] shh rpc test, initial version From b80bf1df73f252f2a65424f6df0e570ede879bd2 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Wed, 29 Jul 2015 14:16:28 +0200 Subject: [PATCH 31/75] tests updated From 72aae56358f8de3992184a3bc1f4d8c5d544af9e Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Wed, 29 Jul 2015 15:37:48 +0200 Subject: [PATCH 32/75] web3 test complete From 667f42a84155f0ba6a5189c1bb71e6ef539ab69e Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Wed, 29 Jul 2015 15:52:03 +0200 Subject: [PATCH 33/75] style fix From 2febde1f08a13ec869b833d2d72d7b313125234f Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Wed, 29 Jul 2015 23:33:14 +0200 Subject: [PATCH 34/75] small bugfix From 27962f6e633bae4babfa34677151a46e0fb50c8a Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 3 Aug 2015 12:53:56 +0200 Subject: [PATCH 35/75] adjust gasPricerTests to 50 shannon From a8ec9d5f133073cc60b3a8c237808f2c6d13ccfd Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 3 Aug 2015 17:48:18 +0200 Subject: [PATCH 36/75] use global constant for defsultGasPrice From 765f30368837e3e930d6a221d870a277278e5c3f Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 3 Aug 2015 18:09:39 +0200 Subject: [PATCH 37/75] strings as mapping keys. --- libsolidity/SolidityEndToEndTest.cpp | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/libsolidity/SolidityEndToEndTest.cpp b/libsolidity/SolidityEndToEndTest.cpp index d44545145..fc1d2eab8 100644 --- a/libsolidity/SolidityEndToEndTest.cpp +++ b/libsolidity/SolidityEndToEndTest.cpp @@ -5099,6 +5099,39 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0))); } +BOOST_AUTO_TEST_CASE(string_as_mapping_key) +{ + char const* sourceCode = R"( + contract Test { + mapping(string => uint) data; + function set(string _s, uint _v) { data[_s] = _v; } + function get(string _s) returns (uint) { return data[_s]; } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + vector strings{ + "Hello, World!", + "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111", + "", + "1" + }; + for (unsigned i = 0; i < strings.size(); i++) + BOOST_CHECK(callContractFunction( + "set(string,uint256)", + u256(0x40), + u256(7 + i), + u256(strings[i].size()), + strings[i] + ) == encodeArgs()); + for (unsigned i = 0; i < strings.size(); i++) + BOOST_CHECK(callContractFunction( + "get(string)", + u256(0x20), + u256(strings[i].size()), + strings[i] + ) == encodeArgs(u256(7 + i))); +} + BOOST_AUTO_TEST_SUITE_END() } From ad325d24259d0e7e10593e71e785d5cc79f9461a Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 3 Aug 2015 20:49:55 +0200 Subject: [PATCH 38/75] typo - trigger buildbot From 45e6d94078816984dfdf9a35293502dd3d482fec Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Aug 2015 11:06:57 +0200 Subject: [PATCH 39/75] Allow explicit conversions bytes <-> string. --- libsolidity/SolidityEndToEndTest.cpp | 25 +++++++++++++++++++ libsolidity/SolidityNameAndTypeResolution.cpp | 17 +++++++++++++ 2 files changed, 42 insertions(+) diff --git a/libsolidity/SolidityEndToEndTest.cpp b/libsolidity/SolidityEndToEndTest.cpp index fc1d2eab8..a10b47676 100644 --- a/libsolidity/SolidityEndToEndTest.cpp +++ b/libsolidity/SolidityEndToEndTest.cpp @@ -5099,6 +5099,31 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0))); } +BOOST_AUTO_TEST_CASE(string_bytes_conversion) +{ + char const* sourceCode = R"( + contract Test { + string s; + bytes b; + function f(string _s, uint n) returns (byte) { + b = bytes(_s); + s = string(b); + return bytes(s)[n]; + } + function l() returns (uint) { return bytes(s).length; } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + BOOST_CHECK(callContractFunction( + "f(string,uint256)", + u256(0x40), + u256(2), + u256(6), + string("abcdef") + ) == encodeArgs("c")); + BOOST_CHECK(callContractFunction("l()") == encodeArgs(u256(6))); +} + BOOST_AUTO_TEST_CASE(string_as_mapping_key) { char const* sourceCode = R"( diff --git a/libsolidity/SolidityNameAndTypeResolution.cpp b/libsolidity/SolidityNameAndTypeResolution.cpp index cfc43df91..6b116f251 100644 --- a/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2149,6 +2149,23 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(string_bytes_conversion) +{ + char const* text = R"( + contract Test { + string s; + bytes b; + function h(string _s) external { bytes(_s).length; } + function i(string _s) internal { bytes(_s).length; } + function j() internal { bytes(s).length; } + function k(bytes _b) external { string(_b); } + function l(bytes _b) internal { string(_b); } + function m() internal { string(b); } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + BOOST_AUTO_TEST_SUITE_END() } From f2088278aab0c703510814f0f4a59009942ec053 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Aug 2015 12:43:40 +0200 Subject: [PATCH 40/75] Break off contract tests. --- CMakeLists.txt | 1 + contracts/CMakeLists.txt | 5 +++++ .../FixedFeeRegistrar.cpp | 0 libsolidity/SolidityWallet.cpp => contracts/Wallet.cpp | 0 4 files changed, 6 insertions(+) create mode 100644 contracts/CMakeLists.txt rename libsolidity/SolidityFixedFeeRegistrar.cpp => contracts/FixedFeeRegistrar.cpp (100%) rename libsolidity/SolidityWallet.cpp => contracts/Wallet.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e24e3347..f74751126 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ endif() if (SOLIDITY) add_subdirectory(libsolidity) + add_subdirectory(contracts) endif () if (JSONRPC) add_subdirectory(libweb3jsonrpc) diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt new file mode 100644 index 000000000..3ceda13b0 --- /dev/null +++ b/contracts/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_policy(SET CMP0015 NEW) + +aux_source_directory(. SRCS) + +add_sources(${SRCS}) diff --git a/libsolidity/SolidityFixedFeeRegistrar.cpp b/contracts/FixedFeeRegistrar.cpp similarity index 100% rename from libsolidity/SolidityFixedFeeRegistrar.cpp rename to contracts/FixedFeeRegistrar.cpp diff --git a/libsolidity/SolidityWallet.cpp b/contracts/Wallet.cpp similarity index 100% rename from libsolidity/SolidityWallet.cpp rename to contracts/Wallet.cpp From cc32bf2264c57f2896cc7d6c1f2974e9be1a1e0c Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 5 Aug 2015 09:43:04 +0200 Subject: [PATCH 41/75] add difficutly tests From 8bc36e2484bbfb432b620406f45e5a6d471f1d12 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 5 Aug 2015 10:16:47 +0200 Subject: [PATCH 42/75] get block number for parent in difficulty test From af9dedf698813829f00c54323b81d207727caa46 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Aug 2015 10:37:09 +0200 Subject: [PATCH 43/75] Avoid doing the deadline timer test. From 29de3ac4bed4fd3dd3a9e8395dde97d7a5b0f916 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 5 Aug 2015 10:50:09 +0200 Subject: [PATCH 44/75] disable failing deadlinetimer test Test consistently failing on osx. From c42e9f3e490d528a18ea545c1f81feed03aeda0e Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 5 Aug 2015 14:32:17 +0100 Subject: [PATCH 45/75] Simplify/remove unused methods. --- TestUtils.cpp | 6 +----- TestUtils.h | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/TestUtils.cpp b/TestUtils.cpp index bd603a61f..60d5d6062 100644 --- a/TestUtils.cpp +++ b/TestUtils.cpp @@ -120,10 +120,6 @@ void ParallelClientBaseFixture::enumerateClients(std::function Date: Tue, 4 Aug 2015 16:31:27 +0200 Subject: [PATCH 46/75] Basic tests for auction registrar. --- contracts/AuctionRegistrar.cpp | 418 +++++++++++++++++++++++ contracts/FixedFeeRegistrar.cpp | 5 + libsolidity/solidityExecutionFramework.h | 64 ++++ 3 files changed, 487 insertions(+) create mode 100644 contracts/AuctionRegistrar.cpp diff --git a/contracts/AuctionRegistrar.cpp b/contracts/AuctionRegistrar.cpp new file mode 100644 index 000000000..3832e8e09 --- /dev/null +++ b/contracts/AuctionRegistrar.cpp @@ -0,0 +1,418 @@ +/* + 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 +#include + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +namespace +{ + +static char const* registrarCode = R"DELIMITER( +//sol + +contract NameRegister { + function addr(string _name) constant returns (address o_owner); + function name(address _owner) constant returns (string o_name); +} + +contract Registrar is NameRegister { + event Changed(string indexed name); + event PrimaryChanged(string indexed name, address indexed addr); + + 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); + + function name(address _owner) constant returns (string o_name); +} + +contract AuctionSystem { + event AuctionEnded(string indexed _name, address _winner); + event NewBid(string indexed _name, address _bidder, uint _value); + + /// Function that is called once an auction ends. + function onAuctionEnd(string _name) internal; + + function bid(string _name, address _bidder, uint _value) internal { + var auction = m_auctions[_name]; + if (auction.endDate > 0 && now > auction.endDate) + { + AuctionEnded(_name, auction.highestBidder); + onAuctionEnd(_name); + delete m_auctions[_name]; + return; + } + if (msg.value > auction.highestBid) + { + // new bid on auction + auction.secondHighestBid = auction.highestBid; + auction.sumOfBids += _value; + auction.highestBid = _value; + auction.highestBidder = _bidder; + auction.endDate = now + c_biddingTime; + + NewBid(_name, _bidder, _value); + } + } + + uint constant c_biddingTime = 7 days; + + struct Auction { + address highestBidder; + uint highestBid; + uint secondHighestBid; + uint sumOfBids; + uint endDate; + } + mapping(string => Auction) m_auctions; +} + +contract GlobalRegistrar is Registrar, AuctionSystem { + struct Record { + address owner; + address primary; + address subRegistrar; + bytes32 content; + uint renewalDate; + } + + uint constant c_renewalInterval = 1 years; + uint constant c_freeBytes = 12; + + function Registrar() { + // TODO: Populate with hall-of-fame. + } + + function() { + // prevent people from just sending funds to the registrar + __throw(); + } + + function onAuctionEnd(string _name) internal { + var auction = m_auctions[_name]; + var record = m_toRecord[_name]; + if (record.owner != 0) + record.owner.send(auction.sumOfBids - auction.highestBid / 100); + else + auction.highestBidder.send(auction.highestBid - auction.secondHighestBid); + record.renewalDate = now + c_renewalInterval; + record.owner = auction.highestBidder; + Changed(_name); + } + + function reserve(string _name) external { + if (bytes(_name).length == 0) + __throw(); + bool needAuction = requiresAuction(_name); + if (needAuction) + { + if (now < m_toRecord[_name].renewalDate) + __throw(); + bid(_name, msg.sender, msg.value); + } + else + { + Record record = m_toRecord[_name]; + if (record.owner != 0) + __throw(); + m_toRecord[_name].owner = msg.sender; + Changed(_name); + } + } + + function requiresAuction(string _name) internal returns (bool) { + return bytes(_name).length < c_freeBytes; + } + + modifier onlyrecordowner(string _name) { if (m_toRecord[_name].owner == msg.sender) _ } + + function transfer(string _name, address _newOwner) onlyrecordowner(_name) { + m_toRecord[_name].owner = _newOwner; + Changed(_name); + } + + function disown(string _name) onlyrecordowner(_name) { + if (stringsEqual(m_toName[m_toRecord[_name].primary], _name)) + { + PrimaryChanged(_name, m_toRecord[_name].primary); + m_toName[m_toRecord[_name].primary] = ""; + } + delete m_toRecord[_name]; + Changed(_name); + } + + function setAddress(string _name, address _a, bool _primary) onlyrecordowner(_name) { + m_toRecord[_name].primary = _a; + if (_primary) + { + PrimaryChanged(_name, _a); + m_toName[_a] = _name; + } + Changed(_name); + } + function setSubRegistrar(string _name, address _registrar) onlyrecordowner(_name) { + m_toRecord[_name].subRegistrar = _registrar; + Changed(_name); + } + function setContent(string _name, bytes32 _content) onlyrecordowner(_name) { + m_toRecord[_name].content = _content; + Changed(_name); + } + + function stringsEqual(string storage _a, string memory _b) internal returns (bool) { + bytes storage a = bytes(_a); + bytes memory b = bytes(_b); + if (a.length != b.length) + return false; + // @todo unroll this loop + for (uint i = 0; i < a.length; i ++) + if (a[i] != b[i]) + return false; + return true; + } + + function owner(string _name) constant returns (address) { return m_toRecord[_name].owner; } + function addr(string _name) constant returns (address) { return m_toRecord[_name].primary; } + function subRegistrar(string _name) constant returns (address) { return m_toRecord[_name].subRegistrar; } + function content(string _name) constant returns (bytes32) { return m_toRecord[_name].content; } + function name(address _addr) constant returns (string o_name) { return m_toName[_addr]; } + + function __throw() internal { + // workaround until we have "throw" + uint[] x; x[1]; + } + + mapping (address => string) m_toName; + mapping (string => Record) m_toRecord; +} +)DELIMITER"; + +static unique_ptr s_compiledRegistrar; + +class AuctionRegistrarTestFramework: 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("GlobalRegistrar"))); + } + sendMessage(*s_compiledRegistrar, true); + BOOST_REQUIRE(!m_output.empty()); + } + + using ContractInterface = ExecutionFramework::ContractInterface; + class RegistrarInterface: public ContractInterface + { + public: + RegistrarInterface(ExecutionFramework& _framework): ContractInterface(_framework) {} + void reserve(string const& _name) + { + callString("reserve", _name); + } + u160 owner(string const& _name) + { + return callStringReturnsAddress("owner", _name); + } + void setAddress(string const& _name, u160 const& _address, bool _primary) + { + callStringAddressBool("setAddress", _name, _address, _primary); + } + u160 addr(string const& _name) + { + return callStringReturnsAddress("addr", _name); + } + string name(u160 const& _addr) + { + return callAddressReturnsString("name", _addr); + } + void setSubRegistrar(string const& _name, u160 const& _address) + { + callStringAddress("setSubRegistrar", _name, _address); + } + u160 subRegistrar(string const& _name) + { + return callStringReturnsAddress("subRegistrar", _name); + } + void setContent(string const& _name, h256 const& _content) + { + callStringBytes32("setContent", _name, _content); + } + h256 content(string const& _name) + { + return callStringReturnsBytes32("content", _name); + } + void transfer(string const& _name, u160 const& _target) + { + return callStringAddress("transfer", _name, _target); + } + void disown(string const& _name) + { + return callString("disown", _name); + } + }; +}; + +} + +/// This is a test suite that tests optimised code! +BOOST_FIXTURE_TEST_SUITE(SolidityAuctionRegistrar, AuctionRegistrarTestFramework) + +BOOST_AUTO_TEST_CASE(creation) +{ + deployRegistrar(); +} + +BOOST_AUTO_TEST_CASE(reserve) +{ + // Test that reserving works for long strings + deployRegistrar(); + vector names{"abcabcabcabcabc", "defdefdefdefdef", "ghighighighighighighighighighighighighighighi"}; + m_sender = Address(0x123); + + RegistrarInterface registrar(*this); + + // should not work + registrar.reserve(""); + BOOST_CHECK_EQUAL(registrar.owner(""), u160(0)); + + for (auto const& name: names) + { + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), u160(0x123)); + } +} + +BOOST_AUTO_TEST_CASE(double_reserve_long) +{ + // Test that it is not possible to re-reserve from a different address. + deployRegistrar(); + string name = "abcabcabcabcabcabcabcabcabcabca"; + m_sender = Address(0x123); + RegistrarInterface registrar(*this); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), u160(0x123)); + + m_sender = Address(0x124); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), u160(0x123)); +} + +BOOST_AUTO_TEST_CASE(properties) +{ + // Test setting and retrieving the various properties works. + deployRegistrar(); + RegistrarInterface registrar(*this); + string names[] = {"abcaeouoeuaoeuaoeu", "defncboagufra,fui", "ghagpyajfbcuajouhaeoi"}; + size_t addr = 0x9872543; + for (string const& name: names) + { + addr++; + size_t sender = addr + 10007; + m_sender = Address(sender); + // setting by sender works + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), u160(sender)); + registrar.setAddress(name, addr, true); + BOOST_CHECK_EQUAL(registrar.addr(name), u160(addr)); + registrar.setSubRegistrar(name, addr + 20); + BOOST_CHECK_EQUAL(registrar.subRegistrar(name), u160(addr + 20)); + registrar.setContent(name, h256(u256(addr + 90))); + BOOST_CHECK_EQUAL(registrar.content(name), h256(u256(addr + 90))); + + // but not by someone else + m_sender = Address(h256(addr + 10007 - 1)); + BOOST_CHECK_EQUAL(registrar.owner(name), u160(sender)); + registrar.setAddress(name, addr + 1, true); + BOOST_CHECK_EQUAL(registrar.addr(name), u160(addr)); + registrar.setSubRegistrar(name, addr + 20 + 1); + BOOST_CHECK_EQUAL(registrar.subRegistrar(name), u160(addr + 20)); + registrar.setContent(name, h256(u256(addr + 90 + 1))); + BOOST_CHECK_EQUAL(registrar.content(name), h256(u256(addr + 90))); + } +} + +BOOST_AUTO_TEST_CASE(transfer) +{ + deployRegistrar(); + string name = "abcaoeguaoucaeoduceo"; + m_sender = Address(0x123); + RegistrarInterface registrar(*this); + registrar.reserve(name); + registrar.setContent(name, h256(u256(123))); + registrar.transfer(name, u160(555)); + BOOST_CHECK_EQUAL(registrar.owner(name), u160(555)); + BOOST_CHECK_EQUAL(registrar.content(name), h256(u256(123))); +} + +BOOST_AUTO_TEST_CASE(disown) +{ + deployRegistrar(); + string name = "abcaoeguaoucaeoduceo"; + m_sender = Address(0x123); + RegistrarInterface registrar(*this); + registrar.reserve(name); + registrar.setContent(name, h256(u256(123))); + registrar.setAddress(name, u160(124), true); + registrar.setSubRegistrar(name, u160(125)); + + // someone else tries disowning + m_sender = Address(0x128); + registrar.disown(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0x123); + + m_sender = Address(0x123); + registrar.disown(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0); + BOOST_CHECK_EQUAL(registrar.addr(name), 0); + BOOST_CHECK_EQUAL(registrar.subRegistrar(name), 0); + BOOST_CHECK_EQUAL(registrar.content(name), h256()); +} + +//@todo: +// - reverse lookup +// - actual auction + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces diff --git a/contracts/FixedFeeRegistrar.cpp b/contracts/FixedFeeRegistrar.cpp index 26373499a..ed2ecf0a1 100644 --- a/contracts/FixedFeeRegistrar.cpp +++ b/contracts/FixedFeeRegistrar.cpp @@ -35,6 +35,9 @@ namespace solidity namespace test { +namespace +{ + static char const* registrarCode = R"DELIMITER( //sol FixedFeeRegistrar // Simple global registrar with fixed-fee reservations. @@ -130,6 +133,8 @@ protected: u256 const m_fee = u256("69000000000000000000"); }; +} + /// This is a test suite that tests optimised code! BOOST_FIXTURE_TEST_SUITE(SolidityFixedFeeRegistrar, RegistrarTestFramework) diff --git a/libsolidity/solidityExecutionFramework.h b/libsolidity/solidityExecutionFramework.h index e4c4087f4..6a62c445b 100644 --- a/libsolidity/solidityExecutionFramework.h +++ b/libsolidity/solidityExecutionFramework.h @@ -25,6 +25,7 @@ #include #include #include "../TestHelper.h" +#include #include #include #include @@ -166,6 +167,69 @@ public: return encodeArgs(u256(0x20), u256(_arg.size()), _arg); } + class ContractInterface + { + public: + ContractInterface(ExecutionFramework& _framework): m_framework(_framework) {} + + protected: + template + bytes const& call(std::string const& _sig, Args const&... _arguments) + { + auto const& ret = m_framework.callContractFunctionWithValue(_sig, m_nextValue, _arguments...); + m_nextValue = 0; + return ret; + } + + void callString(std::string const& _name, std::string const& _arg) + { + BOOST_CHECK(call(_name + "(string)", u256(0x20), _arg.length(), _arg).empty()); + } + + void callStringAddress(std::string const& _name, std::string const& _arg1, u160 const& _arg2) + { + BOOST_CHECK(call(_name + "(string,address)", u256(0x40), _arg2, _arg1.length(), _arg1).empty()); + } + + void callStringAddressBool(std::string const& _name, std::string const& _arg1, u160 const& _arg2, bool _arg3) + { + BOOST_CHECK(call(_name + "(string,address,bool)", u256(0x60), _arg2, _arg3, _arg1.length(), _arg1).empty()); + } + + void callStringBytes32(std::string const& _name, std::string const& _arg1, h256 const& _arg2) + { + BOOST_CHECK(call(_name + "(string,bytes32)", u256(0x40), _arg2, _arg1.length(), _arg1).empty()); + } + + u160 callStringReturnsAddress(std::string const& _name, std::string const& _arg) + { + bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg); + BOOST_REQUIRE(ret.size() == 0x20); + BOOST_CHECK(std::count(ret.begin(), ret.begin() + 12, 0) == 12); + return eth::abiOut(ret); + } + + std::string callAddressReturnsString(std::string const& _name, u160 const& _arg) + { + bytes const& ret = call(_name + "(address)", _arg); + BOOST_REQUIRE(ret.size() >= 0x20); + u256 len = eth::abiOut(ret); + BOOST_REQUIRE(ret.size() == (0x20 + len) / 32 * 32); + return std::string(ret.begin() + 0x20, ret.begin() + 0x20 + size_t(len)); + } + + h256 callStringReturnsBytes32(std::string const& _name, std::string const& _arg) + { + bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg); + BOOST_REQUIRE(ret.size() == 0x20); + return eth::abiOut(ret); + } + + private: + u256 m_nextValue; + ExecutionFramework& m_framework; + }; + private: template auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) From e0863fbd27ae087e3afea94179274dbd29811f66 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 22 Jul 2015 10:30:01 +0100 Subject: [PATCH 47/75] First draft at splitting State. Continuation of State split. libethereum building again. Compile fixes galore. Remove a lot of code redundancy. mix using new state/block classes --- TestHelper.cpp | 128 +++++------------------ TestHelper.h | 21 ++-- libsolidity/solidityExecutionFramework.h | 2 +- 3 files changed, 36 insertions(+), 115 deletions(-) diff --git a/TestHelper.cpp b/TestHelper.cpp index a07378592..e2c51a66c 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -64,7 +64,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { std::unique_ptr sealer(Ethash::createSealEngine()); - s.commitToMine(_bc); + s.commitToSeal(_bc); Notified sealed; sealer->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); sealer->generateSeal(s.info()); @@ -97,7 +97,8 @@ bigint const c_max256plus1 = bigint(1) << 256; ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): m_statePre(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())), m_statePost(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())), - m_TestObject(_o) + m_environment(m_envInfo), + m_testObject(_o) { importEnv(_o["env"].get_obj()); importState(_o["pre"].get_obj(), m_statePre); @@ -144,99 +145,28 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentTimestamp") > 0); assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - - RLPStream rlpStream; - rlpStream.appendList(BlockInfo::BasicFields); - - rlpStream << h256(_o["previousHash"].get_str()); - rlpStream << EmptyListSHA3; - rlpStream << Address(_o["currentCoinbase"].get_str()); - rlpStream << h256(); // stateRoot - rlpStream << EmptyTrie; // transactionTrie - rlpStream << EmptyTrie; // receiptTrie - rlpStream << LogBloom(); // bloom - rlpStream << toInt(_o["currentDifficulty"]); - rlpStream << toInt(_o["currentNumber"]); - rlpStream << toInt(_o["currentGasLimit"]); - rlpStream << 0; //gasUsed - rlpStream << toInt(_o["currentTimestamp"]); - rlpStream << std::string(); //extra data - - m_environment.currentBlock = BlockInfo(rlpStream.out(), CheckEverything, h256{}, HeaderData); - m_statePre.m_previousBlock = m_environment.previousBlock; - m_statePre.m_currentBlock = m_environment.currentBlock; + m_envInfo.setBeneficiary(Address(_o["currentCoinbase"].get_str())); + m_envInfo.setDifficulty(toInt(_o["currentDifficulty"])); + m_envInfo.setNumber(toInt(_o["currentNumber"])); + m_envInfo.setGasLimit(toInt(_o["currentGasLimit"])); + m_envInfo.setTimestamp(toInt(_o["currentTimestamp"])); } // import state from not fully declared json_spirit::mObject, writing to _stateOptionsMap which fields were defined in json -void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptionsMap& _stateOptionsMap) +void ImportTest::importState(json_spirit::mObject& _o, State& _state, AccountMaskMap& o_mask) { - for (auto& i: _o) - { - json_spirit::mObject o = i.second.get_obj(); - - ImportStateOptions stateOptions; - u256 balance = 0; - u256 nonce = 0; - - if (o.count("balance") > 0) - { - stateOptions.m_bHasBalance = true; - if (bigint(o["balance"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); - balance = toInt(o["balance"]); - } - - if (o.count("nonce") > 0) - { - stateOptions.m_bHasNonce = true; - if (bigint(o["nonce"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); - nonce = toInt(o["nonce"]); - } - - Address address = Address(i.first); - - bytes code; - if (o.count("code") > 0) - { - code = importCode(o); - stateOptions.m_bHasCode = true; - } - - if (!code.empty()) - { - _state.m_cache[address] = Account(balance, Account::ContractConception); - _state.m_cache[address].setCode(std::move(code)); - } - else - _state.m_cache[address] = Account(balance, Account::NormalCreation); - - if (o.count("storage") > 0) - { - stateOptions.m_bHasStorage = true; - for (auto const& j: o["storage"].get_obj()) - _state.setStorage(address, toInt(j.first), toInt(j.second)); - } - - for (int i = 0; i < nonce; ++i) - _state.noteSending(address); - - _state.ensureCached(address, false, false); - _stateOptionsMap[address] = stateOptions; - } + _state.populateFrom(jsonToAccountMap(json_spirit::write_string(_o, false), &o_mask)); } void ImportTest::importState(json_spirit::mObject& _o, State& _state) { - stateOptionsMap importedMap; - importState(_o, _state, importedMap); - for (auto& stateOptionMap : importedMap) - { + AccountMaskMap mask; + importState(_o, _state, mask); + for (auto const& i: mask) //check that every parameter was declared in state object - if (!stateOptionMap.second.isAllSet()) + if (!i.second.allSet()) BOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); - } } void ImportTest::importTransaction(json_spirit::mObject& _o) @@ -347,41 +277,41 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost) { // export output - m_TestObject["out"] = (_output.size() > 4096 && !Options::get().fulloutput) ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add); + m_testObject["out"] = (_output.size() > 4096 && !Options::get().fulloutput) ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add); // compare expected output with post output - if (m_TestObject.count("expectOut") > 0) + if (m_testObject.count("expectOut") > 0) { - std::string warning = "Check State: Error! Unexpected output: " + m_TestObject["out"].get_str() + " Expected: " + m_TestObject["expectOut"].get_str(); + std::string warning = "Check State: Error! Unexpected output: " + m_testObject["out"].get_str() + " Expected: " + m_testObject["expectOut"].get_str(); if (Options::get().checkState) - {TBOOST_CHECK_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning);} + {TBOOST_CHECK_MESSAGE((m_testObject["out"].get_str() == m_testObject["expectOut"].get_str()), warning);} else - TBOOST_WARN_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning); + TBOOST_WARN_MESSAGE((m_testObject["out"].get_str() == m_testObject["expectOut"].get_str()), warning); - m_TestObject.erase(m_TestObject.find("expectOut")); + m_testObject.erase(m_testObject.find("expectOut")); } // export logs - m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); + m_testObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); // compare expected state with post state - if (m_TestObject.count("expect") > 0) + if (m_testObject.count("expect") > 0) { stateOptionsMap stateMap; State expectState(OverlayDB(), eth::BaseState::Empty); - importState(m_TestObject["expect"].get_obj(), expectState, stateMap); + importState(m_testObject["expect"].get_obj(), expectState, stateMap); checkExpectedState(expectState, _statePost, stateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); - m_TestObject.erase(m_TestObject.find("expect")); + m_testObject.erase(m_testObject.find("expect")); } // export post state - m_TestObject["post"] = fillJsonWithState(_statePost); - m_TestObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes()); + m_testObject["post"] = fillJsonWithState(_statePost); + m_testObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes()); // export pre state - m_TestObject["pre"] = fillJsonWithState(m_statePre); - m_TestObject["env"] = makeAllFieldsHex(m_TestObject["env"].get_obj()); - m_TestObject["transaction"] = makeAllFieldsHex(m_TestObject["transaction"].get_obj()); + m_testObject["pre"] = fillJsonWithState(m_statePre); + m_testObject["env"] = makeAllFieldsHex(m_testObject["env"].get_obj()); + m_testObject["transaction"] = makeAllFieldsHex(m_testObject["transaction"].get_obj()); } json_spirit::mObject fillJsonWithTransaction(Transaction _txn) diff --git a/TestHelper.h b/TestHelper.h index 48eb42c55..85e901b25 100644 --- a/TestHelper.h +++ b/TestHelper.h @@ -122,26 +122,16 @@ namespace test } \ while (0) -struct ImportStateOptions -{ - ImportStateOptions(bool _bSetAll = false):m_bHasBalance(_bSetAll), m_bHasNonce(_bSetAll), m_bHasCode(_bSetAll), m_bHasStorage(_bSetAll) {} - bool isAllSet() {return m_bHasBalance && m_bHasNonce && m_bHasCode && m_bHasStorage;} - bool m_bHasBalance; - bool m_bHasNonce; - bool m_bHasCode; - bool m_bHasStorage; -}; -typedef std::map stateOptionsMap; - class ImportTest { public: - ImportTest(json_spirit::mObject& _o): m_TestObject(_o) {} + ImportTest(json_spirit::mObject& _o): m_environment(m_envInfo), m_testObject(_o) {} ImportTest(json_spirit::mObject& _o, bool isFiller); + // imports void importEnv(json_spirit::mObject& _o); static void importState(json_spirit::mObject& _o, eth::State& _state); - static void importState(json_spirit::mObject& _o, eth::State& _state, stateOptionsMap& _stateOptionsMap); + static void importState(json_spirit::mObject& _o, eth::State& _state, eth::AccountMaskMap& o_mask); void importTransaction(json_spirit::mObject& _o); static json_spirit::mObject& makeAllFieldsHex(json_spirit::mObject& _o); @@ -150,17 +140,18 @@ public: eth::State m_statePre; eth::State m_statePost; + eth::EnvInfo m_envInfo; eth::ExtVMFace m_environment; eth::Transaction m_transaction; private: - json_spirit::mObject& m_TestObject; + json_spirit::mObject& m_testObject; }; class ZeroGasPricer: public eth::GasPricer { protected: - u256 ask(eth::State const&) const override { return 0; } + u256 ask(eth::Block const&) const override { return 0; } u256 bid(eth::TransactionPriority = eth::TransactionPriority::Medium) const override { return 0; } }; diff --git a/libsolidity/solidityExecutionFramework.h b/libsolidity/solidityExecutionFramework.h index e4c4087f4..580992354 100644 --- a/libsolidity/solidityExecutionFramework.h +++ b/libsolidity/solidityExecutionFramework.h @@ -185,7 +185,7 @@ protected: void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) { m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::Executive executive(m_state, eth::EnvInfo(), 0); eth::ExecutionResult res; executive.setResultRecipient(res); eth::Transaction t = From 4626890913b9639c886544cd38863b3ecd116ddc Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 6 Aug 2015 00:14:45 +0200 Subject: [PATCH 48/75] update test to new Block/State refactoring - credit to winsvega and chriseth --- TestHelper.cpp | 86 ++++++++++++------- TestHelper.h | 27 ++++-- TestUtils.cpp | 4 +- contracts/Wallet.cpp | 4 +- libsolidity/SolidityEndToEndTest.cpp | 37 ++------ libsolidity/SolidityNameAndTypeResolution.cpp | 17 ---- libsolidity/solidityExecutionFramework.h | 4 +- 7 files changed, 87 insertions(+), 92 deletions(-) diff --git a/TestHelper.cpp b/TestHelper.cpp index e2c51a66c..399779756 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "Stats.h" @@ -61,7 +62,7 @@ void connectClients(Client& c1, Client& c2) #endif } -void mine(State& s, BlockChain const& _bc) +void mine(Block& s, BlockChain const& _bc) { std::unique_ptr sealer(Ethash::createSealEngine()); s.commitToSeal(_bc); @@ -94,23 +95,43 @@ struct MissingFields : virtual Exception {}; bigint const c_max256plus1 = bigint(1) << 256; -ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): - m_statePre(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())), - m_statePost(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())), - m_environment(m_envInfo), +ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller, testType testTemplate): + m_statePre(OverlayDB(), eth::BaseState::Empty), + m_statePost(OverlayDB(), eth::BaseState::Empty), m_testObject(_o) { - importEnv(_o["env"].get_obj()); - importState(_o["pre"].get_obj(), m_statePre); - importTransaction(_o["transaction"].get_obj()); - - if (!isFiller) + if (testTemplate == testType::StateTests) { - importState(_o["post"].get_obj(), m_statePost); - m_environment.sub.logs = importLog(_o["logs"].get_array()); + importEnv(_o["env"].get_obj()); + importTransaction(_o["transaction"].get_obj()); + importState(_o["pre"].get_obj(), m_statePre); + if (!isFiller) + { + if (_o.count("post")) + importState(_o["post"].get_obj(), m_statePost); + else + importState(_o["postState"].get_obj(), m_statePost); + m_logsExpected = importLog(_o["logs"].get_array()); + } } } +//executes an imported transacton on preState +bytes ImportTest::executeTest() +{ + ExecutionResult res; + eth::State tmpState = m_statePre; + + std::pair execOut = m_statePre.execute(m_envInfo, m_transaction); + res = execOut.first; + m_logs = execOut.second.log(); + m_statePre.commit(); + m_statePost = m_statePre; + m_statePre = tmpState; + + return res.output; +} + json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o) { static const set hashes {"bloom" , "coinbase", "hash", "mixHash", "parentHash", "receiptTrie", @@ -139,24 +160,25 @@ json_spirit::mObject& ImportTest::makeAllFieldsHex(json_spirit::mObject& _o) void ImportTest::importEnv(json_spirit::mObject& _o) { - assert(_o.count("previousHash") > 0); assert(_o.count("currentGasLimit") > 0); - assert(_o.count("currentDifficulty") > 0); + assert(_o.count("currentDifficulty") > 0); + assert(_o.count("currentNumber") > 0); assert(_o.count("currentTimestamp") > 0); assert(_o.count("currentCoinbase") > 0); - assert(_o.count("currentNumber") > 0); - m_envInfo.setBeneficiary(Address(_o["currentCoinbase"].get_str())); + m_envInfo.setGasLimit(toInt(_o["currentGasLimit"])); m_envInfo.setDifficulty(toInt(_o["currentDifficulty"])); m_envInfo.setNumber(toInt(_o["currentNumber"])); - m_envInfo.setGasLimit(toInt(_o["currentGasLimit"])); m_envInfo.setTimestamp(toInt(_o["currentTimestamp"])); + m_envInfo.setBeneficiary(Address(_o["currentCoinbase"].get_str())); + m_envInfo.setLastHashes( lastHashes( m_envInfo.number() ) ); } // import state from not fully declared json_spirit::mObject, writing to _stateOptionsMap which fields were defined in json void ImportTest::importState(json_spirit::mObject& _o, State& _state, AccountMaskMap& o_mask) -{ - _state.populateFrom(jsonToAccountMap(json_spirit::write_string(_o, false), &o_mask)); +{ + std::string jsondata = json_spirit::write_string((json_spirit::mValue)_o, false); + _state.populateFrom(jsonToAccountMap(jsondata, &o_mask)); } void ImportTest::importState(json_spirit::mObject& _o, State& _state) @@ -215,7 +237,7 @@ void ImportTest::importTransaction(json_spirit::mObject& _o) } } -void ImportTest::checkExpectedState(State const& _stateExpect, State const& _statePost, stateOptionsMap const _expectedStateOptions, WhenError _throw) +void ImportTest::compareStates(State const& _stateExpect, State const& _statePost, AccountMaskMap const _expectedStateOptions, WhenError _throw) { #define CHECK(a,b) \ { \ @@ -230,7 +252,7 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta CHECK(_statePost.addressInUse(a.first), "Filling Test: " << a.first << " missing expected address!"); if (_statePost.addressInUse(a.first)) { - ImportStateOptions addressOptions(true); + AccountMask addressOptions(true); if(_expectedStateOptions.size()) { try @@ -244,15 +266,15 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta } } - if (addressOptions.m_bHasBalance) + if (addressOptions.hasBalance()) CHECK((_stateExpect.balance(a.first) == _statePost.balance(a.first)), "Check State: " << a.first << ": incorrect balance " << _statePost.balance(a.first) << ", expected " << _stateExpect.balance(a.first)); - if (addressOptions.m_bHasNonce) + if (addressOptions.hasNonce()) CHECK((_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first)), "Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first)); - if (addressOptions.m_bHasStorage) + if (addressOptions.hasStorage()) { unordered_map stateStorage = _statePost.storage(a.first); for (auto const& s: _stateExpect.storage(a.first)) @@ -266,14 +288,14 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(s.second) << ", expected [" << s.first << "] = " << toHex(stateStorage[s.first])); } - if (addressOptions.m_bHasCode) + if (addressOptions.hasCode()) CHECK((_stateExpect.code(a.first) == _statePost.code(a.first)), "Check State: " << a.first << ": incorrect code '" << toHex(_statePost.code(a.first)) << "', expected '" << toHex(_stateExpect.code(a.first)) << "'"); } } } -void ImportTest::exportTest(bytes const& _output, State const& _statePost) +void ImportTest::exportTest(bytes const& _output) { // export output @@ -291,22 +313,22 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost) m_testObject.erase(m_testObject.find("expectOut")); } - // export logs - m_testObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); + // export logs + m_testObject["logs"] = exportLog(m_logs); // compare expected state with post state if (m_testObject.count("expect") > 0) { - stateOptionsMap stateMap; + eth::AccountMaskMap stateMap; State expectState(OverlayDB(), eth::BaseState::Empty); importState(m_testObject["expect"].get_obj(), expectState, stateMap); - checkExpectedState(expectState, _statePost, stateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); + compareStates(expectState, m_statePost, stateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); m_testObject.erase(m_testObject.find("expect")); } // export post state - m_testObject["post"] = fillJsonWithState(_statePost); - m_testObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes()); + m_testObject["post"] = fillJsonWithState(m_statePost); + m_testObject["postStateRoot"] = toHex(m_statePost.rootHash().asBytes()); // export pre state m_testObject["pre"] = fillJsonWithState(m_statePre); diff --git a/TestHelper.h b/TestHelper.h index 85e901b25..9d2625e19 100644 --- a/TestHelper.h +++ b/TestHelper.h @@ -32,6 +32,7 @@ #include #include + #ifdef NOBOOST #define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception(); #define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); @@ -62,7 +63,7 @@ class State; void mine(Client& c, int numBlocks); void connectClients(Client& c1, Client& c2); -void mine(State& _s, BlockChain const& _bc); +void mine(Block& _s, BlockChain const& _bc); void mine(Ethash::BlockHeader& _bi); } @@ -122,11 +123,17 @@ namespace test } \ while (0) +enum class testType +{ + StateTests, + BlockChainTests, + Other +}; + class ImportTest { public: - ImportTest(json_spirit::mObject& _o): m_environment(m_envInfo), m_testObject(_o) {} - ImportTest(json_spirit::mObject& _o, bool isFiller); + ImportTest(json_spirit::mObject& _o, bool isFiller, testType testTemplate = testType::StateTests); // imports void importEnv(json_spirit::mObject& _o); @@ -135,14 +142,16 @@ public: void importTransaction(json_spirit::mObject& _o); static json_spirit::mObject& makeAllFieldsHex(json_spirit::mObject& _o); - void exportTest(bytes const& _output, eth::State const& _statePost); - static void checkExpectedState(eth::State const& _stateExpect, eth::State const& _statePost, stateOptionsMap const _expectedStateOptions = stateOptionsMap(), WhenError _throw = WhenError::Throw); + bytes executeTest(); + void exportTest(bytes const& _output); + static void compareStates(eth::State const& _stateExpect, eth::State const& _statePost, eth::AccountMaskMap const _expectedStateOptions = eth::AccountMaskMap(), WhenError _throw = WhenError::Throw); eth::State m_statePre; eth::State m_statePost; eth::EnvInfo m_envInfo; - eth::ExtVMFace m_environment; - eth::Transaction m_transaction; + eth::Transaction m_transaction; + eth::LogEntries m_logs; + eth::LogEntries m_logsExpected; private: json_spirit::mObject& m_testObject; @@ -196,7 +205,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin); void doBlockchainTests(json_spirit::mValue& _v, bool _fillin); void doRlpTests(json_spirit::mValue& v, bool _fillin); -template +/*template void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) { for (auto& resultPair : _resultAddrs) @@ -207,7 +216,7 @@ void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) TBOOST_ERROR("Missing result address " << resultAddr); } TBOOST_CHECK((_expectedAddrs == _resultAddrs)); -} +}*/ class Options { diff --git a/TestUtils.cpp b/TestUtils.cpp index bd603a61f..053ffa21f 100644 --- a/TestUtils.cpp +++ b/TestUtils.cpp @@ -101,7 +101,9 @@ void ClientBaseFixture::enumerateClients(std::function void { - FixedClient client(_bc, _state); + cerr << "void ClientBaseFixture::enumerateClients. FixedClient now accepts block not sate!" << endl; + _state.commit(); //unused variable. remove this line + FixedClient client(_bc, eth::Block {}); callback(_json, client); }); } diff --git a/contracts/Wallet.cpp b/contracts/Wallet.cpp index 3c88afd95..5f9febd40 100644 --- a/contracts/Wallet.cpp +++ b/contracts/Wallet.cpp @@ -545,7 +545,7 @@ BOOST_AUTO_TEST_CASE(multisig_value_transfer) // 4 owners, set required to 3 BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); // check that balance is and stays zero at destination address - h256 opHash("8f27f478ebcfaf28b0c354f4809ace8087000d668b89c8bc3b1b608bfdbe6654"); + h256 opHash("6244b4fa93f73e09db0ae52750095ca0364a76b72bc01723c97011fcb876cc9e"); BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); m_sender = Address(0x12); BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash)); @@ -596,7 +596,7 @@ BOOST_AUTO_TEST_CASE(revoke_transaction) BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); // create a transaction Address deployer = m_sender; - h256 opHash("8f27f478ebcfaf28b0c354f4809ace8087000d668b89c8bc3b1b608bfdbe6654"); + h256 opHash("6244b4fa93f73e09db0ae52750095ca0364a76b72bc01723c97011fcb876cc9e"); BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); m_sender = Address(0x12); BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash)); diff --git a/libsolidity/SolidityEndToEndTest.cpp b/libsolidity/SolidityEndToEndTest.cpp index a10b47676..fdffed1e8 100644 --- a/libsolidity/SolidityEndToEndTest.cpp +++ b/libsolidity/SolidityEndToEndTest.cpp @@ -1151,8 +1151,10 @@ BOOST_AUTO_TEST_CASE(blockchain) " blockNumber = block.number;\n" " }\n" "}\n"; + m_envInfo.setBeneficiary(Address(0x123)); + m_envInfo.setNumber(7); compileAndRun(sourceCode, 27); - BOOST_CHECK(callContractFunctionWithValue("someInfo()", 28) == encodeArgs(28, 0, 1)); + BOOST_CHECK(callContractFunctionWithValue("someInfo()", 28) == encodeArgs(28, 0x123, 7)); } BOOST_AUTO_TEST_CASE(msg_sig) @@ -1187,12 +1189,14 @@ BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same) BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" - " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " function someInfo() returns (bool equal, uint val) {\n" + " equal = block.timestamp == now;\n" + " val = now;\n" " }\n" "}\n"; + m_envInfo.setTimestamp(9); compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("someInfo()") == encodeArgs(true)); + BOOST_CHECK(callContractFunction("someInfo()") == encodeArgs(true, 9)); } BOOST_AUTO_TEST_CASE(type_conversions_cleanup) @@ -5099,31 +5103,6 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0))); } -BOOST_AUTO_TEST_CASE(string_bytes_conversion) -{ - char const* sourceCode = R"( - contract Test { - string s; - bytes b; - function f(string _s, uint n) returns (byte) { - b = bytes(_s); - s = string(b); - return bytes(s)[n]; - } - function l() returns (uint) { return bytes(s).length; } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - BOOST_CHECK(callContractFunction( - "f(string,uint256)", - u256(0x40), - u256(2), - u256(6), - string("abcdef") - ) == encodeArgs("c")); - BOOST_CHECK(callContractFunction("l()") == encodeArgs(u256(6))); -} - BOOST_AUTO_TEST_CASE(string_as_mapping_key) { char const* sourceCode = R"( diff --git a/libsolidity/SolidityNameAndTypeResolution.cpp b/libsolidity/SolidityNameAndTypeResolution.cpp index 6b116f251..cfc43df91 100644 --- a/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2149,23 +2149,6 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } -BOOST_AUTO_TEST_CASE(string_bytes_conversion) -{ - char const* text = R"( - contract Test { - string s; - bytes b; - function h(string _s) external { bytes(_s).length; } - function i(string _s) internal { bytes(_s).length; } - function j() internal { bytes(s).length; } - function k(bytes _b) external { string(_b); } - function l(bytes _b) internal { string(_b); } - function m() internal { string(b); } - } - )"; - BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); -} - BOOST_AUTO_TEST_SUITE_END() } diff --git a/libsolidity/solidityExecutionFramework.h b/libsolidity/solidityExecutionFramework.h index 580992354..c66868834 100644 --- a/libsolidity/solidityExecutionFramework.h +++ b/libsolidity/solidityExecutionFramework.h @@ -44,7 +44,6 @@ public: ExecutionFramework() { g_logVerbosity = 0; - m_state.resetCurrent(); } bytes const& compileAndRunWithoutCheck( @@ -185,7 +184,7 @@ protected: void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) { m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, eth::EnvInfo(), 0); + eth::Executive executive(m_state, m_envInfo, 0); eth::ExecutionResult res; executive.setResultRecipient(res); eth::Transaction t = @@ -226,6 +225,7 @@ protected: dev::solidity::CompilerStack m_compiler; Address m_sender; Address m_contractAddress; + eth::EnvInfo m_envInfo; eth::State m_state; u256 const m_gasPrice = 100 * eth::szabo; u256 const m_gas = 100000000; From 228fdf633d9e6589eb6769221ebb15eb31099407 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 6 Aug 2015 00:31:35 +0200 Subject: [PATCH 49/75] readd solidity tests --- libsolidity/SolidityEndToEndTest.cpp | 25 +++++++++++++++++++ libsolidity/SolidityNameAndTypeResolution.cpp | 17 +++++++++++++ 2 files changed, 42 insertions(+) diff --git a/libsolidity/SolidityEndToEndTest.cpp b/libsolidity/SolidityEndToEndTest.cpp index fdffed1e8..ae2fc6dcf 100644 --- a/libsolidity/SolidityEndToEndTest.cpp +++ b/libsolidity/SolidityEndToEndTest.cpp @@ -5103,6 +5103,31 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0))); } +BOOST_AUTO_TEST_CASE(string_bytes_conversion) +{ + char const* sourceCode = R"( + contract Test { + string s; + bytes b; + function f(string _s, uint n) returns (byte) { + b = bytes(_s); + s = string(b); + return bytes(s)[n]; + } + function l() returns (uint) { return bytes(s).length; } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + BOOST_CHECK(callContractFunction( + "f(string,uint256)", + u256(0x40), + u256(2), + u256(6), + string("abcdef") + ) == encodeArgs("c")); + BOOST_CHECK(callContractFunction("l()") == encodeArgs(u256(6))); +} + BOOST_AUTO_TEST_CASE(string_as_mapping_key) { char const* sourceCode = R"( diff --git a/libsolidity/SolidityNameAndTypeResolution.cpp b/libsolidity/SolidityNameAndTypeResolution.cpp index cfc43df91..6b116f251 100644 --- a/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2149,6 +2149,23 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(string_bytes_conversion) +{ + char const* text = R"( + contract Test { + string s; + bytes b; + function h(string _s) external { bytes(_s).length; } + function i(string _s) internal { bytes(_s).length; } + function j() internal { bytes(s).length; } + function k(bytes _b) external { string(_b); } + function l(bytes _b) internal { string(_b); } + function m() internal { string(b); } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + BOOST_AUTO_TEST_SUITE_END() } From d285cf13985000d54ffd9f54026fa6dd62a0a92e Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 22 Jul 2015 21:27:30 +0300 Subject: [PATCH 50/75] libethereum:Transaction coverage From a536bc35d3baf0e5435f2e38221136b5e137ebde Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 22 Jul 2015 21:55:30 +0300 Subject: [PATCH 51/75] cover1: toTransactionExceptionConvert From 13b2fa96f3cab0f3427c14e886fcb946e952691b Mon Sep 17 00:00:00 2001 From: Dimitry Date: Thu, 23 Jul 2015 16:41:11 +0300 Subject: [PATCH 52/75] cover1: Transaction From 029902627a15ffb26f4bb4233863e662a4d63d69 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Fri, 24 Jul 2015 19:02:13 +0300 Subject: [PATCH 53/75] Coverage: Transaction From a25f6c80b0a2d58369f484b9501526f4bdac46a6 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Fri, 24 Jul 2015 20:57:12 +0300 Subject: [PATCH 54/75] Tests - ExtraData32 From ab76878e6f4a085c46981e8186a1e2d737bcb3ad Mon Sep 17 00:00:00 2001 From: Dimitry Date: Sat, 1 Aug 2015 18:13:28 +0300 Subject: [PATCH 55/75] Cover: style From 033b99fc1a11446bebf0ea9804d919c289102084 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 3 Aug 2015 13:06:33 +0300 Subject: [PATCH 56/75] cover1: ExtraData1024 Test Filler From f9c9dc6281796f76bde1cabfd92f3c2cb340f6b6 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 3 Aug 2015 23:33:52 +0300 Subject: [PATCH 57/75] Style From bec89ca9a02f5d41d59124d4b99cb4c2cafdb08f Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Wed, 5 Aug 2015 16:44:32 +0200 Subject: [PATCH 58/75] peer test updated From 513773490d7d893a043b480668755c979c256984 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Wed, 5 Aug 2015 17:07:02 +0200 Subject: [PATCH 59/75] tests for whisper api From e24d24b34bb05fcf3ed9413f426fcfad9c618809 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Aug 2015 16:49:18 +0200 Subject: [PATCH 60/75] Fix key manager test. From 5aec9fba478e57e2173f596eed3868743c3d8a7d Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Aug 2015 11:01:59 +0200 Subject: [PATCH 61/75] Actual auction tests. --- contracts/AuctionRegistrar.cpp | 85 +++++++++++++++++++++++- libsolidity/solidityExecutionFramework.h | 10 ++- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/contracts/AuctionRegistrar.cpp b/contracts/AuctionRegistrar.cpp index 3832e8e09..7c5d9fa35 100644 --- a/contracts/AuctionRegistrar.cpp +++ b/contracts/AuctionRegistrar.cpp @@ -289,6 +289,9 @@ protected: return callString("disown", _name); } }; + + u256 const m_biddingTime = u256(7 * 24 * 3600); + u256 const m_renewalInterval = u256(365 * 24 * 3600); }; } @@ -393,6 +396,7 @@ BOOST_AUTO_TEST_CASE(disown) registrar.setContent(name, h256(u256(123))); registrar.setAddress(name, u160(124), true); registrar.setSubRegistrar(name, u160(125)); + BOOST_CHECK_EQUAL(registrar.name(u160(124)), name); // someone else tries disowning m_sender = Address(0x128); @@ -405,11 +409,86 @@ BOOST_AUTO_TEST_CASE(disown) BOOST_CHECK_EQUAL(registrar.addr(name), 0); BOOST_CHECK_EQUAL(registrar.subRegistrar(name), 0); BOOST_CHECK_EQUAL(registrar.content(name), h256()); + BOOST_CHECK_EQUAL(registrar.name(u160(124)), ""); } -//@todo: -// - reverse lookup -// - actual auction +BOOST_AUTO_TEST_CASE(auction_simple) +{ + deployRegistrar(); + string name = "x"; + m_sender = Address(0x123); + RegistrarInterface registrar(*this); + // initiate auction + registrar.setNextValue(8); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0); + // "wait" until auction end + m_envInfo.setTimestamp(m_envInfo.timestamp() + m_biddingTime + 10); + // trigger auction again + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0x123); +} + +BOOST_AUTO_TEST_CASE(auction_bidding) +{ + deployRegistrar(); + string name = "x"; + m_sender = Address(0x123); + RegistrarInterface registrar(*this); + // initiate auction + registrar.setNextValue(8); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0); + // overbid self + m_envInfo.setTimestamp(m_biddingTime - 10); + registrar.setNextValue(12); + registrar.reserve(name); + // another bid by someone else + m_sender = Address(0x124); + m_envInfo.setTimestamp(2 * m_biddingTime - 50); + registrar.setNextValue(13); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0); + // end auction by first bidder (which is not highest) trying to overbid again (too late) + m_sender = Address(0x123); + m_envInfo.setTimestamp(4 * m_biddingTime); + registrar.setNextValue(20); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0x124); +} + +BOOST_AUTO_TEST_CASE(auction_renewal) +{ + deployRegistrar(); + string name = "x"; + RegistrarInterface registrar(*this); + // register name by auction + m_sender = Address(0x123); + registrar.setNextValue(8); + registrar.reserve(name); + m_envInfo.setTimestamp(4 * m_biddingTime); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0x123); + + // try to re-register before interval end + m_sender = Address(0x222); + registrar.setNextValue(80); + m_envInfo.setTimestamp(m_envInfo.timestamp() + m_renewalInterval - 1); + registrar.reserve(name); + m_envInfo.setTimestamp(m_envInfo.timestamp() + m_biddingTime); + // if there is a bug in the renewal logic, this would transfer the ownership to 0x222, + // but if there is no bug, this will initiate the auction, albeit with a zero bid + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0x123); + + m_envInfo.setTimestamp(m_envInfo.timestamp() + 2); + registrar.setNextValue(80); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0x123); + m_envInfo.setTimestamp(m_envInfo.timestamp() + m_biddingTime + 2); + registrar.reserve(name); + BOOST_CHECK_EQUAL(registrar.owner(name), 0x222); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/libsolidity/solidityExecutionFramework.h b/libsolidity/solidityExecutionFramework.h index 3f4437200..98241b2ff 100644 --- a/libsolidity/solidityExecutionFramework.h +++ b/libsolidity/solidityExecutionFramework.h @@ -171,6 +171,8 @@ public: public: ContractInterface(ExecutionFramework& _framework): m_framework(_framework) {} + void setNextValue(u256 const& _value) { m_nextValue = _value; } + protected: template bytes const& call(std::string const& _sig, Args const&... _arguments) @@ -210,11 +212,13 @@ public: std::string callAddressReturnsString(std::string const& _name, u160 const& _arg) { - bytes const& ret = call(_name + "(address)", _arg); + bytesConstRef ret = ref(call(_name + "(address)", _arg)); BOOST_REQUIRE(ret.size() >= 0x20); + u256 offset = eth::abiOut(ret); + BOOST_REQUIRE_EQUAL(offset, 0x20); u256 len = eth::abiOut(ret); - BOOST_REQUIRE(ret.size() == (0x20 + len) / 32 * 32); - return std::string(ret.begin() + 0x20, ret.begin() + 0x20 + size_t(len)); + BOOST_REQUIRE_EQUAL(ret.size(), ((len + 0x1f) / 0x20) * 0x20); + return ret.cropped(0, size_t(len)).toString(); } h256 callStringReturnsBytes32(std::string const& _name, std::string const& _arg) From 71986b983a8c6e3a6b8b6d6ed55e58967ca14c47 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 7 Aug 2015 13:33:56 +0200 Subject: [PATCH 62/75] style update From ff1f5fba50c85c4bcf7fa68861f7e9246bdce8d4 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 7 Aug 2015 15:40:59 +0200 Subject: [PATCH 63/75] disable whisper tests which need networking From 3e6deb92d4646b2cb887c2805d43b94c166de6cd Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 7 Aug 2015 16:11:06 +0200 Subject: [PATCH 64/75] nonetwork check added From 46381f9e91073c6b521f1ef07b29df905c5be022 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 7 Aug 2015 16:24:28 +0200 Subject: [PATCH 65/75] compile fix, missing include From a0fa194d6a53d21fdcfd2fba60c3055d121ef1a8 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 7 Aug 2015 16:54:01 +0200 Subject: [PATCH 66/75] nonetwork check added From e3c7bc100b59901758edfe9f138b07b7c6adb1d5 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 7 Aug 2015 17:03:58 +0200 Subject: [PATCH 67/75] a small update From 19874090a2d4adae8245bb3de9465221bd804656 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 7 Aug 2015 17:07:56 +0200 Subject: [PATCH 68/75] bugfix From e0fbdd57e6ca44472850c05a74f56c7ed555cf2d Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Aug 2015 15:33:06 +0200 Subject: [PATCH 69/75] Do not allow boolean operators for integers. Fixes #2496 --- libsolidity/SolidityNameAndTypeResolution.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libsolidity/SolidityNameAndTypeResolution.cpp b/libsolidity/SolidityNameAndTypeResolution.cpp index 6b116f251..e59217bf5 100644 --- a/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1883,6 +1883,22 @@ BOOST_AUTO_TEST_CASE(positive_integers_to_unsigned_out_of_bound) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(integer_boolean_operators) +{ + char const* sourceCode1 = R"( + contract test { function() { uint x = 1; uint y = 2; x || y; } } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode1), TypeError); + char const* sourceCode2 = R"( + contract test { function() { uint x = 1; uint y = 2; x && y; } } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode2), TypeError); + char const* sourceCode3 = R"( + contract test { function() { uint x = 1; !x; } } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode3), TypeError); +} + BOOST_AUTO_TEST_CASE(overwrite_memory_location_external) { char const* sourceCode = R"( From 4288543847307de17d7fbde393a1a3f647be5f05 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Aug 2015 15:39:42 +0200 Subject: [PATCH 70/75] Disallow comparison for reference types. Fixes #2690 --- libsolidity/SolidityNameAndTypeResolution.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libsolidity/SolidityNameAndTypeResolution.cpp b/libsolidity/SolidityNameAndTypeResolution.cpp index e59217bf5..ba5a5a60f 100644 --- a/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1899,6 +1899,18 @@ BOOST_AUTO_TEST_CASE(integer_boolean_operators) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode3), TypeError); } +BOOST_AUTO_TEST_CASE(reference_compare_operators) +{ + char const* sourceCode1 = R"( + contract test { bytes a; bytes b; function() { a == b; } } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode1), TypeError); + char const* sourceCode2 = R"( + contract test { struct s {uint a;}; s x; s y; function() { x == y; } } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode2), TypeError); +} + BOOST_AUTO_TEST_CASE(overwrite_memory_location_external) { char const* sourceCode = R"( From 6d644c64b6fe9cce49905e5faa4b5679cbfbf211 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 10 Aug 2015 10:07:43 +0200 Subject: [PATCH 71/75] icap encoding and decoding tests From 15fca6ea5063f5ea307019f2322d7a444ea71dff Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 10 Aug 2015 11:18:32 +0200 Subject: [PATCH 72/75] remove MoveNonceToTempDir --- TestUtils.cpp | 5 ----- TestUtils.h | 8 -------- 2 files changed, 13 deletions(-) diff --git a/TestUtils.cpp b/TestUtils.cpp index 0ec76386b..5e0619c0e 100644 --- a/TestUtils.cpp +++ b/TestUtils.cpp @@ -120,8 +120,3 @@ void ParallelClientBaseFixture::enumerateClients(std::function Date: Mon, 10 Aug 2015 14:57:08 +0200 Subject: [PATCH 73/75] fixed boost % bug From cdd9cf3c5325f4d37945d333d49df739bee55f78 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 10 Aug 2015 14:59:34 +0200 Subject: [PATCH 74/75] fixed header files From 4907bda371804b152c7af71a1ba818cda5da60c4 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 10 Aug 2015 23:49:46 +0200 Subject: [PATCH 75/75] Fix an error in a type resolution SOL test This will also fix the build. --- libsolidity/SolidityNameAndTypeResolution.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/SolidityNameAndTypeResolution.cpp b/libsolidity/SolidityNameAndTypeResolution.cpp index ba5a5a60f..3daabc85e 100644 --- a/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1906,7 +1906,7 @@ BOOST_AUTO_TEST_CASE(reference_compare_operators) )"; BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode1), TypeError); char const* sourceCode2 = R"( - contract test { struct s {uint a;}; s x; s y; function() { x == y; } } + contract test { struct s {uint a;} s x; s y; function() { x == y; } } )"; BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode2), TypeError); }