mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge branch 'develop' into mk_jsonrpc_upgrade
Conflicts: alethzero/MainWin.cpp libweb3jsonrpc/WebThreeStubServer.cpp libweb3jsonrpc/abstractwebthreestubserver.h libweb3jsonrpc/spec.json test/jsonrpc.cpp test/webthreestubclient.h
This commit is contained in:
		
						commit
						1d278d2857
					
				| @ -7,7 +7,7 @@ include_directories(..) | ||||
| 
 | ||||
| file(GLOB HEADERS "*.h") | ||||
| add_executable(testeth ${SRC_LIST} ${HEADERS}) | ||||
| add_executable(createRandomTest createRandomTest.cpp vm.cpp) | ||||
| add_executable(createRandomTest createRandomTest.cpp vm.cpp TestHelper.cpp) | ||||
| 
 | ||||
| target_link_libraries(testeth ethereum) | ||||
| target_link_libraries(testeth ethcore) | ||||
|  | ||||
							
								
								
									
										341
									
								
								TestHelper.cpp
									
									
									
									
									
								
							
							
						
						
									
										341
									
								
								TestHelper.cpp
									
									
									
									
									
								
							| @ -23,7 +23,12 @@ | ||||
| 
 | ||||
| #include <thread> | ||||
| #include <chrono> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <libethereum/Client.h> | ||||
| #include <liblll/Compiler.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev::eth; | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| @ -53,6 +58,342 @@ void connectClients(Client& c1, Client& c2) | ||||
| 	c2.connect("127.0.0.1", c1Port); | ||||
| #endif | ||||
| } | ||||
| } | ||||
| 
 | ||||
| namespace test | ||||
| { | ||||
| 
 | ||||
| ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller): m_TestObject(_o) | ||||
| { | ||||
| 	importEnv(_o["env"].get_obj()); | ||||
| 	importState(_o["pre"].get_obj(), m_statePre); | ||||
| 	importTransaction(_o["transaction"].get_obj()); | ||||
| 
 | ||||
| 	if (!isFiller) | ||||
| 	{ | ||||
| 		importState(_o["post"].get_obj(), m_statePost); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ImportTest::importEnv(json_spirit::mObject& _o) | ||||
| { | ||||
| 	BOOST_REQUIRE(_o.count("previousHash") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("currentGasLimit") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("currentDifficulty") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("currentTimestamp") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("currentCoinbase") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("currentNumber") > 0); | ||||
| 
 | ||||
| 	m_environment.previousBlock.hash = h256(_o["previousHash"].get_str()); | ||||
| 	m_environment.currentBlock.number = toInt(_o["currentNumber"]); | ||||
| 	m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); | ||||
| 	m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); | ||||
| 	m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); | ||||
| 	m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); | ||||
| 
 | ||||
| 	m_statePre.m_previousBlock = m_environment.previousBlock; | ||||
| 	m_statePre.m_currentBlock = m_environment.currentBlock; | ||||
| } | ||||
| 
 | ||||
| void ImportTest::importState(json_spirit::mObject& _o, State& _state) | ||||
| { | ||||
| 	for (auto& i: _o) | ||||
| 	{ | ||||
| 		json_spirit::mObject o = i.second.get_obj(); | ||||
| 
 | ||||
| 		BOOST_REQUIRE(o.count("balance") > 0); | ||||
| 		BOOST_REQUIRE(o.count("nonce") > 0); | ||||
| 		BOOST_REQUIRE(o.count("storage") > 0); | ||||
| 		BOOST_REQUIRE(o.count("code") > 0); | ||||
| 
 | ||||
| 		Address address = Address(i.first); | ||||
| 
 | ||||
| 		for (auto const& j: o["storage"].get_obj()) | ||||
| 			_state.setStorage(address, toInt(j.first), toInt(j.second)); | ||||
| 
 | ||||
| 		bytes code = importCode(o); | ||||
| 
 | ||||
| 		if (code.size()) | ||||
| 		{ | ||||
| 			_state.m_cache[address] = Account(toInt(o["balance"]), Account::ContractConception); | ||||
| 			_state.m_cache[address].setCode(bytesConstRef(&code)); | ||||
| 		} | ||||
| 		else | ||||
| 			_state.m_cache[address] = Account(toInt(o["balance"]), Account::NormalCreation); | ||||
| 
 | ||||
| 		for(int i=0; i<toInt(o["nonce"]); ++i) | ||||
| 			_state.noteSending(address); | ||||
| 
 | ||||
| 		_state.ensureCached(address, false, false); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ImportTest::importTransaction(json_spirit::mObject& _o) | ||||
| { | ||||
| 	BOOST_REQUIRE(_o.count("nonce")> 0); | ||||
| 	BOOST_REQUIRE(_o.count("gasPrice") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("gasLimit") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("to") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("value") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("secretKey") > 0); | ||||
| 	BOOST_REQUIRE(_o.count("data") > 0); | ||||
| 
 | ||||
| 	m_transaction = _o["to"].get_str().empty() ? | ||||
| 		Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) : | ||||
| 		Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), Address(_o["to"].get_str()), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())); | ||||
| } | ||||
| 
 | ||||
| void ImportTest::exportTest(bytes _output, State& _statePost) | ||||
| { | ||||
| 	// export output
 | ||||
| 	m_TestObject["out"] = "0x" + toHex(_output); | ||||
| 
 | ||||
| 	// export post state
 | ||||
| 	json_spirit::mObject postState; | ||||
| 
 | ||||
| 	std::map<Address, Account> genesis = genesisState(); | ||||
| 
 | ||||
| 	for (auto const& a: _statePost.addresses()) | ||||
| 	{ | ||||
| 		if (genesis.count(a.first)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		json_spirit::mObject o; | ||||
| 		o["balance"] = toString(_statePost.balance(a.first)); | ||||
| 		o["nonce"] = toString(_statePost.transactionsFrom(a.first)); | ||||
| 		{ | ||||
| 			json_spirit::mObject store; | ||||
| 			for (auto const& s: _statePost.storage(a.first)) | ||||
| 				store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second)); | ||||
| 			o["storage"] = store; | ||||
| 		} | ||||
| 		o["code"] = "0x" + toHex(_statePost.code(a.first)); | ||||
| 
 | ||||
| 		postState[toString(a.first)] = o; | ||||
| 	} | ||||
| 	m_TestObject["post"] = json_spirit::mValue(postState); | ||||
| 
 | ||||
| 	// export pre state
 | ||||
| 	json_spirit::mObject preState; | ||||
| 
 | ||||
| 	for (auto const& a: m_statePre.addresses()) | ||||
| 	{ | ||||
| 		if (genesis.count(a.first)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		json_spirit::mObject o; | ||||
| 		o["balance"] = toString(m_statePre.balance(a.first)); | ||||
| 		o["nonce"] = toString(m_statePre.transactionsFrom(a.first)); | ||||
| 		{ | ||||
| 			json_spirit::mObject store; | ||||
| 			for (auto const& s: m_statePre.storage(a.first)) | ||||
| 				store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second)); | ||||
| 			o["storage"] = store; | ||||
| 		} | ||||
| 		o["code"] = "0x" + toHex(m_statePre.code(a.first)); | ||||
| 
 | ||||
| 		preState[toString(a.first)] = o; | ||||
| 	} | ||||
| 	m_TestObject["pre"] = json_spirit::mValue(preState); | ||||
| } | ||||
| 
 | ||||
| u256 toInt(json_spirit::mValue const& _v) | ||||
| { | ||||
| 	switch (_v.type()) | ||||
| 	{ | ||||
| 	case json_spirit::str_type: return u256(_v.get_str()); | ||||
| 	case json_spirit::int_type: return (u256)_v.get_uint64(); | ||||
| 	case json_spirit::bool_type: return (u256)(uint64_t)_v.get_bool(); | ||||
| 	case json_spirit::real_type: return (u256)(uint64_t)_v.get_real(); | ||||
| 	default: cwarn << "Bad type for scalar: " << _v.type(); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| byte toByte(json_spirit::mValue const& _v) | ||||
| { | ||||
| 	switch (_v.type()) | ||||
| 	{ | ||||
| 	case json_spirit::str_type: return (byte)stoi(_v.get_str()); | ||||
| 	case json_spirit::int_type: return (byte)_v.get_uint64(); | ||||
| 	case json_spirit::bool_type: return (byte)_v.get_bool(); | ||||
| 	case json_spirit::real_type: return (byte)_v.get_real(); | ||||
| 	default: cwarn << "Bad type for scalar: " << _v.type(); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| bytes importData(json_spirit::mObject& _o) | ||||
| { | ||||
| 	bytes data; | ||||
| 	if (_o["data"].type() == json_spirit::str_type) | ||||
| 		if (_o["data"].get_str().find_first_of("0x") == 0) | ||||
| 			data = fromHex(_o["data"].get_str().substr(2)); | ||||
| 		else | ||||
| 			data = fromHex(_o["data"].get_str()); | ||||
| 	else | ||||
| 		for (auto const& j: _o["data"].get_array()) | ||||
| 			data.push_back(toByte(j)); | ||||
| 
 | ||||
| 	return data; | ||||
| } | ||||
| 
 | ||||
| bytes importCode(json_spirit::mObject& _o) | ||||
| { | ||||
| 	bytes code; | ||||
| 	if (_o["code"].type() == json_spirit::str_type) | ||||
| 		if (_o["code"].get_str().find_first_of("0x") != 0) | ||||
| 			code = compileLLL(_o["code"].get_str(), false); | ||||
| 		else | ||||
| 			code = fromHex(_o["code"].get_str().substr(2)); | ||||
| 	else if (_o["code"].type() == json_spirit::array_type) | ||||
| 	{ | ||||
| 		code.clear(); | ||||
| 		for (auto const& j: _o["code"].get_array()) | ||||
| 			code.push_back(toByte(j)); | ||||
| 	} | ||||
| 	return code; | ||||
| } | ||||
| 
 | ||||
| void checkOutput(bytes const& _output, json_spirit::mObject& _o) | ||||
| { | ||||
| 	int j = 0; | ||||
| 	if (_o["out"].type() == json_spirit::array_type) | ||||
| 		for (auto const& d: _o["out"].get_array()) | ||||
| 		{ | ||||
| 			BOOST_CHECK_MESSAGE(_output[j] == toInt(d), "Output byte [" << j << "] different!"); | ||||
| 			++j; | ||||
| 		} | ||||
| 	else if (_o["out"].get_str().find("0x") == 0) | ||||
| 		BOOST_CHECK(_output == fromHex(_o["out"].get_str().substr(2))); | ||||
| 	else | ||||
| 		BOOST_CHECK(_output == fromHex(_o["out"].get_str())); | ||||
| } | ||||
| 
 | ||||
| void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore, Address _expectedAddr) | ||||
| { | ||||
| 	for (auto&& expectedStorePair : _expectedStore) | ||||
| 	{ | ||||
| 		auto& expectedStoreKey = expectedStorePair.first; | ||||
| 		auto resultStoreIt = _resultStore.find(expectedStoreKey); | ||||
| 		if (resultStoreIt == _resultStore.end()) | ||||
| 			BOOST_ERROR(_expectedAddr << ": missing store key " << expectedStoreKey); | ||||
| 		else | ||||
| 		{ | ||||
| 			auto& expectedStoreValue = expectedStorePair.second; | ||||
| 			auto& resultStoreValue = resultStoreIt->second; | ||||
| 			BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| std::string getTestPath() | ||||
| { | ||||
| 	string testPath; | ||||
| 	const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); | ||||
| 
 | ||||
| 	if (ptestPath == NULL) | ||||
| 	{ | ||||
| 		cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; | ||||
| 		testPath = "../../../tests"; | ||||
| 	} | ||||
| 	else | ||||
| 		testPath = ptestPath; | ||||
| 
 | ||||
| 	return testPath; | ||||
| } | ||||
| 
 | ||||
| void userDefinedTest(string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests) | ||||
| { | ||||
| 	for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) | ||||
| 	{ | ||||
| 		string arg = boost::unit_test::framework::master_test_suite().argv[i]; | ||||
| 		if (arg == testTypeFlag) | ||||
| 		{ | ||||
| 			if (i + 1 >= boost::unit_test::framework::master_test_suite().argc) | ||||
| 			{ | ||||
| 				cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " <filename>\n"; | ||||
| 				return; | ||||
| 			} | ||||
| 			string filename = boost::unit_test::framework::master_test_suite().argv[i + 1]; | ||||
| 			int currentVerbosity = g_logVerbosity; | ||||
| 			g_logVerbosity = 12; | ||||
| 			try | ||||
| 			{ | ||||
| 				cnote << "Testing user defined test: " << filename; | ||||
| 				json_spirit::mValue v; | ||||
| 				string s = asString(contents(filename)); | ||||
| 				BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); | ||||
| 				json_spirit::read_string(s, v); | ||||
| 				doTests(v, false); | ||||
| 			} | ||||
| 			catch (Exception const& _e) | ||||
| 			{ | ||||
| 				BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e)); | ||||
| 				g_logVerbosity = currentVerbosity; | ||||
| 			} | ||||
| 			catch (std::exception const& _e) | ||||
| 			{ | ||||
| 				BOOST_ERROR("Failed Test with Exception: " << _e.what()); | ||||
| 				g_logVerbosity = currentVerbosity; | ||||
| 			} | ||||
| 			g_logVerbosity = currentVerbosity; | ||||
| 		} | ||||
| 		else | ||||
| 			continue; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void executeTests(const string& _name, const string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests) | ||||
| { | ||||
| 	string testPath = getTestPath(); | ||||
| 	testPath += _testPathAppendix; | ||||
| 
 | ||||
| 	for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) | ||||
| 	{ | ||||
| 		string arg = boost::unit_test::framework::master_test_suite().argv[i]; | ||||
| 		if (arg == "--filltests") | ||||
| 		{ | ||||
| 			try | ||||
| 			{ | ||||
| 				cnote << "Populating tests..."; | ||||
| 				json_spirit::mValue v; | ||||
| 				boost::filesystem::path p(__FILE__); | ||||
| 				boost::filesystem::path dir = p.parent_path(); | ||||
| 				string s = asString(dev::contents(dir.string() + "/" + _name + "Filler.json")); | ||||
| 				BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + dir.string() + "/" + _name + "Filler.json is empty."); | ||||
| 				json_spirit::read_string(s, v); | ||||
| 				doTests(v, true); | ||||
| 				writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); | ||||
| 			} | ||||
| 			catch (Exception const& _e) | ||||
| 			{ | ||||
| 				BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); | ||||
| 			} | ||||
| 			catch (std::exception const& _e) | ||||
| 			{ | ||||
| 				BOOST_ERROR("Failed test with Exception: " << _e.what()); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	try | ||||
| 	{ | ||||
| 		cnote << "Testing ..." << _name; | ||||
| 		json_spirit::mValue v; | ||||
| 		string s = asString(dev::contents(testPath + "/" + _name + ".json")); | ||||
| 		BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); | ||||
| 		json_spirit::read_string(s, v); | ||||
| 		doTests(v, false); | ||||
| 	} | ||||
| 	catch (Exception const& _e) | ||||
| 	{ | ||||
| 		BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); | ||||
| 	} | ||||
| 	catch (std::exception const& _e) | ||||
| 	{ | ||||
| 		BOOST_ERROR("Failed test with Exception: " << _e.what()); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| } } // namespaces
 | ||||
|  | ||||
							
								
								
									
										55
									
								
								TestHelper.h
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								TestHelper.h
									
									
									
									
									
								
							| @ -21,6 +21,11 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include "JsonSpiritHeaders.h" | ||||
| #include <libethereum/State.h> | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| namespace eth | ||||
| @ -31,5 +36,55 @@ class Client; | ||||
| void mine(Client& c, int numBlocks); | ||||
| void connectClients(Client& c1, Client& c2); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| namespace test | ||||
| { | ||||
| 
 | ||||
| class ImportTest | ||||
| { | ||||
| public: | ||||
| 	ImportTest() = default; | ||||
| 	ImportTest(json_spirit::mObject& _o, bool isFiller); | ||||
| 
 | ||||
| 	// imports
 | ||||
| 	void importEnv(json_spirit::mObject& _o); | ||||
| 	void importState(json_spirit::mObject& _o, eth::State& _state); | ||||
| 	void importTransaction(json_spirit::mObject& _o); | ||||
| 	void exportTest(bytes _output, eth::State& _statePost); | ||||
| 
 | ||||
| 	eth::State m_statePre; | ||||
| 	eth::State m_statePost; | ||||
| 	eth::ExtVMFace m_environment; | ||||
| 	eth::Transaction m_transaction; | ||||
| 
 | ||||
| private: | ||||
| 	json_spirit::mObject& m_TestObject; | ||||
| }; | ||||
| 
 | ||||
| // helping functions
 | ||||
| u256 toInt(json_spirit::mValue const& _v); | ||||
| byte toByte(json_spirit::mValue const& _v); | ||||
| bytes importCode(json_spirit::mObject& _o); | ||||
| bytes importData(json_spirit::mObject& _o); | ||||
| void checkOutput(bytes const& _output, json_spirit::mObject& _o); | ||||
| void checkStorage(std::map<u256, u256> _expectedStore, std::map<u256, u256> _resultStore, Address _expectedAddr); | ||||
| void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests); | ||||
| std::string getTestPath(); | ||||
| void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests); | ||||
| 
 | ||||
| template<typename mapType> | ||||
| void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) | ||||
| { | ||||
| 	for (auto& resultPair : _resultAddrs) | ||||
| 	{ | ||||
| 		auto& resultAddr = resultPair.first; | ||||
| 		auto expectedAddrIt = _expectedAddrs.find(resultAddr); | ||||
| 		if (expectedAddrIt == _expectedAddrs.end()) | ||||
| 			BOOST_ERROR("Missing result address " << resultAddr); | ||||
| 	} | ||||
| 	BOOST_CHECK(_expectedAddrs == _resultAddrs); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -1,51 +0,0 @@ | ||||
| /*
 | ||||
|  This file is part of cpp-ethereum. | ||||
|   | ||||
|  cpp-ethereum is free software: you can redistribute it and/or modify | ||||
|  it under the terms of the GNU General Public License as published by | ||||
|  the Free Software Foundation, either version 3 of the License, or | ||||
|  (at your option) any later version. | ||||
|   | ||||
|  cpp-ethereum is distributed in the hope that it will be useful, | ||||
|  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  GNU General Public License for more details. | ||||
|   | ||||
|  You should have received a copy of the GNU General Public License | ||||
|  along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| /** @file TestHelperCrypto.h
 | ||||
|  * @author Alex Leverington <nessence@gmail.com> | ||||
|  * @date 2014 | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <libdevcrypto/CryptoPP.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace CryptoPP; | ||||
| 
 | ||||
| void SavePrivateKey(const PrivateKey& key, const string& file = "ecies.private.key") | ||||
| { | ||||
| 	FileSink sink(file.c_str()); | ||||
| 	key.Save(sink); | ||||
| } | ||||
| 
 | ||||
| void SavePublicKey(const PublicKey& key, const string& file = "ecies.public.key") | ||||
| { | ||||
| 	FileSink sink(file.c_str()); | ||||
| 	key.Save(sink); | ||||
| } | ||||
| 
 | ||||
| void LoadPrivateKey(PrivateKey& key, const string& file = "ecies.private.key") | ||||
| { | ||||
| 	FileSource source(file.c_str(), true); | ||||
| 	key.Load(source); | ||||
| } | ||||
| 
 | ||||
| void LoadPublicKey(PublicKey& key, const string& file = "ecies.public.key") | ||||
| { | ||||
| 	FileSource source(file.c_str(), true); | ||||
| 	key.Load(source); | ||||
| } | ||||
| @ -31,7 +31,8 @@ | ||||
| #include <json_spirit/json_spirit_writer_template.h> | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libdevcore/CommonData.h> | ||||
| #include <libevmface/Instruction.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevm/VM.h> | ||||
| #include "vm.h" | ||||
| 
 | ||||
| using namespace std; | ||||
| @ -134,18 +135,24 @@ void doMyTests(json_spirit::mValue& v) | ||||
| 		o["pre"] = mValue(fev.exportState()); | ||||
| 
 | ||||
| 		fev.importExec(o["exec"].get_obj()); | ||||
| 		if (!fev.code) | ||||
| 		if (fev.code.empty()) | ||||
| 		{ | ||||
| 			fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); | ||||
| 			fev.code = &fev.thisTxCode; | ||||
| 			fev.code = fev.thisTxCode; | ||||
| 		} | ||||
| 
 | ||||
| 		vm.reset(fev.gas); | ||||
| 		bytes output; | ||||
| 		u256 gas; | ||||
| 		try | ||||
| 		{ | ||||
| 			output = vm.go(fev).toBytes(); | ||||
| 		} | ||||
| 		catch (eth::VMException const& _e) | ||||
| 		{ | ||||
| 			cnote << "VM did throw an exception: " << diagnostic_information(_e); | ||||
| 			gas = 0; | ||||
| 		} | ||||
| 		catch (Exception const& _e) | ||||
| 		{ | ||||
| 			cnote << "VM did throw an exception: " << diagnostic_information(_e); | ||||
| @ -176,6 +183,6 @@ void doMyTests(json_spirit::mValue& v) | ||||
| 		o["post"] = mValue(fev.exportState()); | ||||
| 		o["callcreates"] = fev.exportCallCreates(); | ||||
| 		o["out"] = "0x" + toHex(output); | ||||
| 		fev.push(o, "gas", vm.gas()); | ||||
| 		fev.push(o, "gas", gas); | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										432
									
								
								crypto.cpp
									
									
									
									
									
								
							
							
						
						
									
										432
									
								
								crypto.cpp
									
									
									
									
									
								
							| @ -27,8 +27,9 @@ | ||||
| #include <libdevcore/Log.h> | ||||
| #include <libethereum/Transaction.h> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include <libdevcrypto/EC.h> | ||||
| #include "TestHelperCrypto.h" | ||||
| #include <libdevcrypto/SHA3.h> | ||||
| #include <libdevcrypto/ECDHE.h> | ||||
| #include <libdevcrypto/CryptoPP.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| @ -37,131 +38,265 @@ using namespace CryptoPP; | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(devcrypto) | ||||
| 
 | ||||
| static Secp256k1 s_secp256k1; | ||||
| static CryptoPP::AutoSeededRandomPool s_rng; | ||||
| static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1()); | ||||
| static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> s_params(s_curveOID); | ||||
| static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP>::EllipticCurve s_curve(s_params.GetCurve()); | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(verify_secert) | ||||
| { | ||||
| 	h256 empty; | ||||
| 	KeyPair kNot(empty); | ||||
| 	BOOST_REQUIRE(!kNot.address()); | ||||
| 	KeyPair k(sha3(empty)); | ||||
| 	BOOST_REQUIRE(k.address()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) | ||||
| { | ||||
| 	string message("Now is the time for all good persons to come to the aide of humanity."); | ||||
| 	string message("Now is the time for all good persons to come to the aid of humanity."); | ||||
| 	bytes m = asBytes(message); | ||||
| 	bytesConstRef bcr(&m); | ||||
| 
 | ||||
| 	KeyPair k = KeyPair::create(); | ||||
| 	bytes cipher; | ||||
| 	encrypt(k.pub(), bcr, cipher); | ||||
| 	assert(cipher != asBytes(message) && cipher.size() > 0); | ||||
| 	BOOST_REQUIRE(cipher != asBytes(message) && cipher.size() > 0); | ||||
| 	 | ||||
| 	bytes plain; | ||||
| 	decrypt(k.sec(), bytesConstRef(&cipher), plain); | ||||
| 	 | ||||
| 	assert(asString(plain) == message); | ||||
| 	assert(plain == asBytes(message)); | ||||
| 	BOOST_REQUIRE(asString(plain) == message); | ||||
| 	BOOST_REQUIRE(plain == asBytes(message)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) | ||||
| BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) | ||||
| { | ||||
| 	ECIES<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1()); | ||||
| 	ECIES<ECP>::Encryptor e(d.GetKey()); | ||||
| 	secp256k1_start(); | ||||
| 	 | ||||
| 	Secret s; | ||||
| 	pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); | ||||
| 	// base secret
 | ||||
| 	Secret secret(sha3("privacy")); | ||||
| 	 | ||||
| 	Public p; | ||||
| 	pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); | ||||
| 	// we get ec params from signer
 | ||||
| 	ECDSA<ECP, SHA3_256>::Signer signer; | ||||
| 	 | ||||
| 	assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); | ||||
| 	 | ||||
| 	Secret previous = s; | ||||
| 	for (auto i = 0; i < 30; i++) | ||||
| 	// e := sha3(msg)
 | ||||
| 	bytes e(fromHex("0x01")); | ||||
| 	e.resize(32); | ||||
| 	int tests = 2; | ||||
| 	while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) | ||||
| 	{ | ||||
| 		ECIES<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1()); | ||||
| 		ECIES<ECP>::Encryptor e(d.GetKey()); | ||||
| 		KeyPair key(secret); | ||||
| 		Public pkey = key.pub(); | ||||
| 		signer.AccessKey().Initialize(s_params, secretToExponent(secret)); | ||||
| 		 | ||||
| 		Secret s; | ||||
| 		pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); | ||||
| 		assert(s != previous); | ||||
| 		h256 he(sha3(e)); | ||||
| 		Integer heInt(he.asBytes().data(), 32); | ||||
| 		h256 k(crypto::kdf(secret, he)); | ||||
| 		Integer kInt(k.asBytes().data(), 32); | ||||
| 		kInt %= s_params.GetSubgroupOrder()-1; | ||||
| 
 | ||||
| 		Public p; | ||||
| 		pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); | ||||
| 		ECP::Point rp = s_params.ExponentiateBase(kInt); | ||||
| 		Integer const& q = s_params.GetGroupOrder(); | ||||
| 		Integer r = s_params.ConvertElementToInteger(rp); | ||||
| 
 | ||||
| 		assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); | ||||
| 		Integer kInv = kInt.InverseMod(q); | ||||
| 		Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; | ||||
| 		BOOST_REQUIRE(!!r && !!s); | ||||
| 
 | ||||
| 		Signature sig; | ||||
| 		sig[64] = rp.y.IsOdd() ? 1 : 0; | ||||
| 		r.Encode(sig.data(), 32); | ||||
| 		s.Encode(sig.data() + 32, 32); | ||||
| 
 | ||||
| 		Public p = dev::recover(sig, he); | ||||
| 		BOOST_REQUIRE(p == pkey); | ||||
| 		 | ||||
| 		// verify w/cryptopp
 | ||||
| 		BOOST_REQUIRE(s_secp256k1.verify(pkey, sig, bytesConstRef(&e))); | ||||
| 		 | ||||
| 		// verify with secp256k1lib
 | ||||
| 		byte encpub[65] = {0x04}; | ||||
| 		memcpy(&encpub[1], pkey.data(), 64); | ||||
| 		byte dersig[72]; | ||||
| 		size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sig.data(), 64, DSA_P1363); | ||||
| 		BOOST_CHECK(cssz <= 72); | ||||
| 		BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(he.data(), sizeof(he), dersig, cssz, encpub, 65)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(cryptopp_keys_cryptor_sipaseckp256k1) | ||||
| BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) | ||||
| { | ||||
| 	KeyPair k = KeyPair::create(); | ||||
| 	Secret s = k.sec(); | ||||
| 	secp256k1_start(); | ||||
| 	 | ||||
| 	// Convert secret to exponent used by pp
 | ||||
| 	Integer e = pp::ExponentFromSecret(s); | ||||
| 	// cryptopp integer encoding
 | ||||
| 	Integer nHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); | ||||
| 	Integer nB(fromHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2").data(), 32); | ||||
| 	BOOST_REQUIRE(nHex == nB); | ||||
| 	 | ||||
| 	// Test that exported DL_EC private is same as exponent from Secret
 | ||||
| 	CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> privatek; | ||||
| 	privatek.AccessGroupParameters().Initialize(pp::secp256k1()); | ||||
| 	privatek.SetPrivateExponent(e); | ||||
| 	assert(e == privatek.GetPrivateExponent()); | ||||
| 	bytes sbytes(fromHex("0xFFFF")); | ||||
| 	Secret secret(sha3(sbytes)); | ||||
| 	KeyPair key(secret); | ||||
| 	 | ||||
| 	// Test that exported secret is same as decryptor(privatek) secret
 | ||||
| 	ECIES<ECP>::Decryptor d; | ||||
| 	d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); | ||||
| 	d.AccessKey().SetPrivateExponent(e); | ||||
| 	assert(d.AccessKey().GetPrivateExponent() == e); | ||||
| 	bytes m(1, 0xff); | ||||
| 	int tests = 2; | ||||
| 	while (m[0]++, tests--) | ||||
| 	{ | ||||
| 		h256 hm(sha3(m)); | ||||
| 		Integer hInt(hm.asBytes().data(), 32); | ||||
| 		h256 k(hm ^ key.sec()); | ||||
| 		Integer kInt(k.asBytes().data(), 32); | ||||
| 
 | ||||
| 	// Test that decryptor->encryptor->public == private->makepublic->public
 | ||||
| 	CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> pubk; | ||||
| 	pubk.AccessGroupParameters().Initialize(pp::secp256k1()); | ||||
| 	privatek.MakePublicKey(pubk); | ||||
| 		// raw sign w/cryptopp (doesn't pass through cryptopp hash filter)
 | ||||
| 		ECDSA<ECP, SHA3_256>::Signer signer; | ||||
| 		signer.AccessKey().Initialize(s_params, secretToExponent(key.sec())); | ||||
| 		Integer r, s; | ||||
| 		signer.RawSign(kInt, hInt, r, s); | ||||
| 
 | ||||
| 	ECIES<ECP>::Encryptor enc(d); | ||||
| 	assert(pubk.GetPublicElement() == enc.AccessKey().GetPublicElement()); | ||||
| 		// verify cryptopp raw-signature w/cryptopp
 | ||||
| 		ECDSA<ECP, SHA3_256>::Verifier verifier; | ||||
| 		verifier.AccessKey().Initialize(s_params, publicToPoint(key.pub())); | ||||
| 		Signature sigppraw; | ||||
| 		r.Encode(sigppraw.data(), 32); | ||||
| 		s.Encode(sigppraw.data() + 32, 32); | ||||
| 		BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); | ||||
| //		BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m)));
 | ||||
| 		BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm)); | ||||
| 		 | ||||
| 	// Test against sipa/seckp256k1
 | ||||
| 	Public p; | ||||
| 	pp::PublicFromExponent(pp::ExponentFromSecret(s), p); | ||||
| 	assert(toAddress(s) == dev::right160(dev::sha3(p.ref()))); | ||||
| 	assert(k.pub() == p); | ||||
| 		// sign with cryptopp, verify, recover w/sec256lib
 | ||||
| 		Signature seclibsig(dev::sign(key.sec(), hm)); | ||||
| 		BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); | ||||
| //		BOOST_REQUIRE(crypto::verify(key.pub(), seclibsig, bytesConstRef(&m)));
 | ||||
| 		BOOST_REQUIRE(dev::verify(key.pub(), seclibsig, hm)); | ||||
| 		BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub()); | ||||
| 
 | ||||
| 		// sign with cryptopp (w/hash filter?), verify with cryptopp
 | ||||
| 		bytes sigppb(signer.MaxSignatureLength()); | ||||
| 		size_t ssz = signer.SignMessage(s_rng, m.data(), m.size(), sigppb.data()); | ||||
| 		Signature sigpp; | ||||
| 		memcpy(sigpp.data(), sigppb.data(), 64); | ||||
| 		BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); | ||||
| //		BOOST_REQUIRE(crypto::verify(key.pub(), sigpp, bytesConstRef(&m)));
 | ||||
| 		BOOST_REQUIRE(dev::verify(key.pub(), sigpp, hm)); | ||||
| 
 | ||||
| 		// sign with cryptopp and stringsource hash filter
 | ||||
| 		string sigstr; | ||||
| 		StringSource ssrc(asString(m), true, new SignerFilter(s_rng, signer, new StringSink(sigstr))); | ||||
| 		FixedHash<sizeof(Signature)> retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); | ||||
| 		BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64)); | ||||
| //		BOOST_REQUIRE(crypto::verify(key.pub(), retsig, bytesConstRef(&m)));
 | ||||
| 		BOOST_REQUIRE(dev::verify(key.pub(), retsig, hm)); | ||||
| 		 | ||||
| 		/// verification w/sec256lib
 | ||||
| 		// requires public key and sig in standard format
 | ||||
| 		byte encpub[65] = {0x04}; | ||||
| 		memcpy(&encpub[1], key.pub().data(), 64); | ||||
| 		byte dersig[72]; | ||||
| 		 | ||||
| 		// verify sec256lib sig w/sec256lib
 | ||||
| 		size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, seclibsig.data(), 64, DSA_P1363); | ||||
| 		BOOST_CHECK(cssz <= 72); | ||||
| 		BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); | ||||
| 		 | ||||
| 		// verify cryptopp-raw sig w/sec256lib
 | ||||
| 		cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sigppraw.data(), 64, DSA_P1363); | ||||
| 		BOOST_CHECK(cssz <= 72); | ||||
| 		BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); | ||||
| 
 | ||||
| 		// verify cryptopp sig w/sec256lib
 | ||||
| 		cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sigppb.data(), 64, DSA_P1363); | ||||
| 		BOOST_CHECK(cssz <= 72); | ||||
| 		BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); | ||||
| 	} | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(cryptopp_public_export_import) | ||||
| { | ||||
| 	ECIES<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1()); | ||||
| 	ECIES<ECP>::Encryptor e(d.GetKey()); | ||||
| 
 | ||||
| 	Secret s; | ||||
| 	pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); | ||||
| 	Public p; | ||||
| 	pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); | ||||
| 	Address addr = right160(dev::sha3(p.ref())); | ||||
| 	assert(toAddress(s) == addr); | ||||
| 	 | ||||
| 	KeyPair l(s); | ||||
| 	assert(l.address() == addr); | ||||
| 	 | ||||
| 	DL_PublicKey_EC<ECP> pub; | ||||
| 	pub.Initialize(pp::secp256k1(), pp::PointFromPublic(p)); | ||||
| 	assert(pub.GetPublicElement() == e.GetKey().GetPublicElement()); | ||||
| 
 | ||||
| 	KeyPair k = KeyPair::create(); | ||||
| 	Public p2; | ||||
| 	pp::PublicFromExponent(pp::ExponentFromSecret(k.sec()), p2); | ||||
| 	assert(k.pub() == p2); | ||||
| 	 | ||||
| 	Address a = k.address(); | ||||
| 	Address a2 = toAddress(k.sec()); | ||||
| 	assert(a2 == a); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(ecies_eckeypair) | ||||
| { | ||||
| 	KeyPair k = KeyPair::create(); | ||||
| 
 | ||||
| 	string message("Now is the time for all good persons to come to the aide of humanity."); | ||||
| 	string message("Now is the time for all good persons to come to the aid of humanity."); | ||||
| 	string original = message; | ||||
| 	 | ||||
| 	bytes b = asBytes(message); | ||||
| 	encrypt(k.pub(), b); | ||||
| 	assert(b != asBytes(original)); | ||||
| 	s_secp256k1.encrypt(k.pub(), b); | ||||
| 	BOOST_REQUIRE(b != asBytes(original)); | ||||
| 
 | ||||
| 	decrypt(k.sec(), b); | ||||
| 	assert(b == asBytes(original)); | ||||
| 	s_secp256k1.decrypt(k.sec(), b); | ||||
| 	BOOST_REQUIRE(b == asBytes(original)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(ecdh) | ||||
| { | ||||
| 	cnote << "Testing ecdh..."; | ||||
| 
 | ||||
| 	ECDH<ECP>::Domain dhLocal(s_curveOID); | ||||
| 	SecByteBlock privLocal(dhLocal.PrivateKeyLength()); | ||||
| 	SecByteBlock pubLocal(dhLocal.PublicKeyLength()); | ||||
| 	dhLocal.GenerateKeyPair(s_rng, privLocal, pubLocal); | ||||
| 	 | ||||
| 	ECDH<ECP>::Domain dhRemote(s_curveOID); | ||||
| 	SecByteBlock privRemote(dhRemote.PrivateKeyLength()); | ||||
| 	SecByteBlock pubRemote(dhRemote.PublicKeyLength()); | ||||
| 	dhRemote.GenerateKeyPair(s_rng, privRemote, pubRemote); | ||||
| 	 | ||||
| 	assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength()); | ||||
| 	 | ||||
| 	// local: send public to remote; remote: send public to local
 | ||||
| 	 | ||||
| 	// Local
 | ||||
| 	SecByteBlock sharedLocal(dhLocal.AgreedValueLength()); | ||||
| 	assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote)); | ||||
| 	 | ||||
| 	// Remote
 | ||||
| 	SecByteBlock sharedRemote(dhRemote.AgreedValueLength()); | ||||
| 	assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal)); | ||||
| 	 | ||||
| 	// Test
 | ||||
| 	Integer ssLocal, ssRemote; | ||||
| 	ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes()); | ||||
| 	ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes()); | ||||
| 	 | ||||
| 	assert(ssLocal != 0); | ||||
| 	assert(ssLocal == ssRemote); | ||||
| 	 | ||||
| 	 | ||||
| 	// Now use our keys
 | ||||
| 	KeyPair a = KeyPair::create(); | ||||
| 	byte puba[65] = {0x04}; | ||||
| 	memcpy(&puba[1], a.pub().data(), 64); | ||||
| 	 | ||||
| 	KeyPair b = KeyPair::create(); | ||||
| 	byte pubb[65] = {0x04}; | ||||
| 	memcpy(&pubb[1], b.pub().data(), 64); | ||||
| 	 | ||||
| 	ECDH<ECP>::Domain dhA(s_curveOID); | ||||
| 	Secret shared; | ||||
| 	BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb)); | ||||
| 	BOOST_REQUIRE(shared); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(ecdhe) | ||||
| { | ||||
| 	cnote << "Testing ecdhe..."; | ||||
| 	 | ||||
| 	ECDHE a, b; | ||||
| 	BOOST_CHECK_NE(a.pubkey(), b.pubkey()); | ||||
| 	 | ||||
| 	ECDHE local; | ||||
| 	ECDHE remote; | ||||
| 	 | ||||
| 	// local tx pubkey -> remote
 | ||||
| 	Secret sremote; | ||||
| 	remote.agree(local.pubkey(), sremote); | ||||
| 	 | ||||
| 	// remote tx pbukey -> local
 | ||||
| 	Secret slocal; | ||||
| 	local.agree(remote.pubkey(), slocal); | ||||
| 
 | ||||
| 	BOOST_REQUIRE(sremote); | ||||
| 	BOOST_REQUIRE(slocal); | ||||
| 	BOOST_REQUIRE_EQUAL(sremote, slocal); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) | ||||
| @ -172,62 +307,12 @@ BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) | ||||
| 	// All connections should share seed for PRF (or PRNG) for nonces
 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) | ||||
| { | ||||
| 	cnote << "Testing cryptopp_ecies_message..."; | ||||
| 
 | ||||
| 	string const message("Now is the time for all good persons to come to the aide of humanity."); | ||||
| 
 | ||||
| 	ECIES<ECP>::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1()); | ||||
| 	SavePrivateKey(localDecryptor.GetPrivateKey()); | ||||
| 	 | ||||
| 	ECIES<ECP>::Encryptor localEncryptor(localDecryptor); | ||||
| 	SavePublicKey(localEncryptor.GetPublicKey()); | ||||
| 
 | ||||
| 	ECIES<ECP>::Decryptor futureDecryptor; | ||||
| 	LoadPrivateKey(futureDecryptor.AccessPrivateKey()); | ||||
| 	futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3); | ||||
| 	 | ||||
| 	ECIES<ECP>::Encryptor futureEncryptor; | ||||
| 	LoadPublicKey(futureEncryptor.AccessPublicKey()); | ||||
| 	futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG(), 3); | ||||
| 
 | ||||
| 	// encrypt/decrypt with local
 | ||||
| 	string cipherLocal; | ||||
| 	StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG(), localEncryptor, new StringSink(cipherLocal) ) ); | ||||
| 	string plainLocal; | ||||
| 	StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocal) ) ); | ||||
| 
 | ||||
| 	// encrypt/decrypt with future
 | ||||
| 	string cipherFuture; | ||||
| 	StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG(), futureEncryptor, new StringSink(cipherFuture) ) ); | ||||
| 	string plainFuture; | ||||
| 	StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFuture) ) ); | ||||
| 	 | ||||
| 	// decrypt local w/future
 | ||||
| 	string plainFutureFromLocal; | ||||
| 	StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFutureFromLocal) ) ); | ||||
| 	 | ||||
| 	// decrypt future w/local
 | ||||
| 	string plainLocalFromFuture; | ||||
| 	StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); | ||||
| 	 | ||||
| 	 | ||||
| 	assert(plainLocal == message); | ||||
| 	assert(plainFuture == plainLocal); | ||||
| 	assert(plainFutureFromLocal == plainLocal); | ||||
| 	assert(plainLocalFromFuture == plainLocal); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) | ||||
| { | ||||
| 	const int aesKeyLen = 16; | ||||
| 	assert(sizeof(char) == sizeof(byte)); | ||||
| 	BOOST_REQUIRE(sizeof(char) == sizeof(byte)); | ||||
| 	 | ||||
| 	// generate test key
 | ||||
| 	AutoSeededRandomPool rng; | ||||
| @ -235,22 +320,29 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) | ||||
| 	rng.GenerateBlock(key, key.size()); | ||||
| 	 | ||||
| 	// cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr
 | ||||
| 	byte ctr[AES::BLOCKSIZE]; | ||||
| 	rng.GenerateBlock(ctr, sizeof(ctr)); | ||||
| 	FixedHash<AES::BLOCKSIZE> ctr; | ||||
| 	rng.GenerateBlock(ctr.data(), sizeof(ctr)); | ||||
| 
 | ||||
| 	string text = "Now is the time for all good persons to come to the aide of humanity."; | ||||
| 	// c++11 ftw
 | ||||
| 	// used for decrypt
 | ||||
| 	FixedHash<AES::BLOCKSIZE> ctrcopy(ctr); | ||||
| 	 | ||||
| 	string text = "Now is the time for all good persons to come to the aid of humanity."; | ||||
| 	unsigned char const* in = (unsigned char*)&text[0]; | ||||
| 	unsigned char* out = (unsigned char*)&text[0]; | ||||
| 	string original = text; | ||||
| 	string doublespeak = text + text; | ||||
| 	 | ||||
| 	string cipherCopy; | ||||
| 	try | ||||
| 	{ | ||||
| 		CTR_Mode<AES>::Encryption e; | ||||
| 		e.SetKeyWithIV(key, key.size(), ctr); | ||||
| 		e.SetKeyWithIV(key, key.size(), ctr.data()); | ||||
| 		 | ||||
| 		// 68 % 255 should be difference of counter
 | ||||
| 		e.ProcessData(out, in, text.size()); | ||||
| 		assert(text != original); | ||||
| 		ctr = h128(u128(ctr) + text.size() % 16); | ||||
| 		 | ||||
| 		BOOST_REQUIRE(text != original); | ||||
| 		cipherCopy = text; | ||||
| 	} | ||||
| 	catch(CryptoPP::Exception& e) | ||||
| @ -261,9 +353,9 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) | ||||
| 	try | ||||
| 	{ | ||||
| 		CTR_Mode< AES >::Decryption d; | ||||
| 		d.SetKeyWithIV(key, key.size(), ctr); | ||||
| 		d.SetKeyWithIV(key, key.size(), ctrcopy.data()); | ||||
| 		d.ProcessData(out, in, text.size()); | ||||
| 		assert(text == original); | ||||
| 		BOOST_REQUIRE(text == original); | ||||
| 	} | ||||
| 	catch(CryptoPP::Exception& e) | ||||
| 	{ | ||||
| @ -274,16 +366,16 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) | ||||
| 	// reencrypt ciphertext...
 | ||||
| 	try | ||||
| 	{ | ||||
| 		assert(cipherCopy != text); | ||||
| 		BOOST_REQUIRE(cipherCopy != text); | ||||
| 		in = (unsigned char*)&cipherCopy[0]; | ||||
| 		out = (unsigned char*)&cipherCopy[0]; | ||||
| 		 | ||||
| 		CTR_Mode<AES>::Encryption e; | ||||
| 		e.SetKeyWithIV(key, key.size(), ctr); | ||||
| 		e.SetKeyWithIV(key, key.size(), ctrcopy.data()); | ||||
| 		e.ProcessData(out, in, text.size()); | ||||
| 		 | ||||
| 		// yep, ctr mode.
 | ||||
| 		assert(cipherCopy == original); | ||||
| 		BOOST_REQUIRE(cipherCopy == original); | ||||
| 	} | ||||
| 	catch(CryptoPP::Exception& e) | ||||
| 	{ | ||||
| @ -295,7 +387,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) | ||||
| BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) | ||||
| { | ||||
| 	const int aesKeyLen = 16; | ||||
| 	assert(sizeof(char) == sizeof(byte)); | ||||
| 	BOOST_REQUIRE(sizeof(char) == sizeof(byte)); | ||||
| 	 | ||||
| 	AutoSeededRandomPool rng; | ||||
| 	SecByteBlock key(0x00, aesKeyLen); | ||||
| @ -310,11 +402,11 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) | ||||
| 	 | ||||
| 	CryptoPP::CBC_Mode<Rijndael>::Encryption cbcEncryption(key, key.size(), iv); | ||||
| 	cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); | ||||
| 	assert(string128 != plainOriginal); | ||||
| 	BOOST_REQUIRE(string128 != plainOriginal); | ||||
| 	 | ||||
| 	CBC_Mode<Rijndael>::Decryption cbcDecryption(key, key.size(), iv); | ||||
| 	cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); | ||||
| 	assert(plainOriginal == string128); | ||||
| 	BOOST_REQUIRE(plainOriginal == string128); | ||||
| 	 | ||||
| 	 | ||||
| 	// plaintext whose size isn't divisible by block size must use stream filter for padding
 | ||||
| @ -324,10 +416,10 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) | ||||
| 	string cipher; | ||||
| 	StreamTransformationFilter* aesStream = new StreamTransformationFilter(cbcEncryption, new StringSink(cipher)); | ||||
| 	StringSource source(string192, true, aesStream); | ||||
| 	assert(cipher.size() == 32); | ||||
| 	BOOST_REQUIRE(cipher.size() == 32); | ||||
| 
 | ||||
| 	cbcDecryption.ProcessData((byte*)&cipher[0], (byte*)&string192[0], cipher.size()); | ||||
| 	assert(string192 == plainOriginal); | ||||
| 	BOOST_REQUIRE(string192 == plainOriginal); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(eth_keypairs) | ||||
| @ -339,20 +431,15 @@ BOOST_AUTO_TEST_CASE(eth_keypairs) | ||||
| 	BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); | ||||
| 	BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); | ||||
| 	{ | ||||
| 		eth::Transaction t; | ||||
| 		t.nonce = 0; | ||||
| 		t.type = eth::Transaction::MessageCall; | ||||
| 		t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); | ||||
| 		t.value = 1000; | ||||
| 		auto rlp = t.rlp(false); | ||||
| 		eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); | ||||
| 		auto rlp = t.rlp(eth::WithoutSignature); | ||||
| 		cnote << RLP(rlp); | ||||
| 		cnote << toHex(rlp); | ||||
| 		cnote << t.sha3(false); | ||||
| 		t.sign(p.secret()); | ||||
| 		rlp = t.rlp(true); | ||||
| 		cnote << t.sha3(eth::WithoutSignature); | ||||
| 		rlp = t.rlp(eth::WithSignature); | ||||
| 		cnote << RLP(rlp); | ||||
| 		cnote << toHex(rlp); | ||||
| 		cnote << t.sha3(true); | ||||
| 		cnote << t.sha3(eth::WithSignature); | ||||
| 		BOOST_REQUIRE(t.sender() == p.address()); | ||||
| 	} | ||||
| 
 | ||||
| @ -365,23 +452,18 @@ int cryptoTest() | ||||
| 	secp256k1_start(); | ||||
| 
 | ||||
| 	KeyPair p(Secret(fromHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4"))); | ||||
| 	assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); | ||||
| 	assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); | ||||
| 	BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); | ||||
| 	BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); | ||||
| 	{ | ||||
| 		eth::Transaction t; | ||||
| 		t.nonce = 0; | ||||
| 		t.type = eth::Transaction::MessageCall; | ||||
| 		t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); | ||||
| 		t.value = 1000; | ||||
| 		auto rlp = t.rlp(false); | ||||
| 		eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); | ||||
| 		auto rlp = t.rlp(eth::WithoutSignature); | ||||
| 		cnote << RLP(rlp); | ||||
| 		cnote << toHex(rlp); | ||||
| 		cnote << t.sha3(false); | ||||
| 		t.sign(p.secret()); | ||||
| 		rlp = t.rlp(true); | ||||
| 		cnote << t.sha3(eth::WithoutSignature); | ||||
| 		rlp = t.rlp(eth::WithSignature); | ||||
| 		cnote << RLP(rlp); | ||||
| 		cnote << toHex(rlp); | ||||
| 		cnote << t.sha3(true); | ||||
| 		cnote << t.sha3(eth::WithSignature); | ||||
| 		assert(t.sender() == p.address()); | ||||
| 	} | ||||
| 
 | ||||
| @ -407,8 +489,8 @@ int cryptoTest() | ||||
| 
 | ||||
| 	auto msg = t.rlp(false); | ||||
| 	cout << "TX w/o SIG: " << RLP(msg) << endl; | ||||
| 	cout << "RLP(TX w/o SIG): " << toHex(t.rlpString(false)) << endl; | ||||
| 	std::string hmsg = sha3(t.rlpString(false), false); | ||||
| 	cout << "RLP(TX w/o SIG): " << toHex(t.rlp(false)) << endl; | ||||
| 	std::string hmsg = sha3(t.rlp(false), false); | ||||
| 	cout << "SHA256(RLP(TX w/o SIG)): 0x" << toHex(hmsg) << endl; | ||||
| 
 | ||||
| 	bytes privkey = sha3Bytes("123"); | ||||
|  | ||||
							
								
								
									
										17
									
								
								genesis.cpp
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								genesis.cpp
									
									
									
									
									
								
							| @ -26,6 +26,7 @@ | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libethereum/BlockChain.h> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include "TestHelper.h" | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| @ -33,18 +34,12 @@ using namespace dev::eth; | ||||
| 
 | ||||
| namespace js = json_spirit; | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(BasicTests) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(genesis_tests) | ||||
| { | ||||
| 	const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); | ||||
| 	string testPath; | ||||
| 
 | ||||
| 	if (ptestPath == NULL) | ||||
| 	{ | ||||
| 		cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; | ||||
| 		testPath = "../../../tests"; | ||||
| 	} | ||||
| 	else | ||||
| 		testPath = ptestPath; | ||||
| 	string testPath = test::getTestPath(); | ||||
| 	testPath += "/BasicTests"; | ||||
| 
 | ||||
| 	cnote << "Testing Genesis block..."; | ||||
| 	js::mValue v; | ||||
| @ -59,3 +54,5 @@ BOOST_AUTO_TEST_CASE(genesis_tests) | ||||
| 	BOOST_CHECK_EQUAL(sha3(BlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
|  | ||||
| @ -26,23 +26,19 @@ | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libdevcrypto/TrieCommon.h> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include "TestHelper.h" | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| namespace js = json_spirit; | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(BasicTests) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(hexPrefix_test) | ||||
| { | ||||
| 	const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); | ||||
| 	string testPath; | ||||
| 
 | ||||
| 	if (ptestPath == NULL) | ||||
| 	{ | ||||
| 		cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; | ||||
| 		testPath = "../../../tests"; | ||||
| 	} | ||||
| 	else | ||||
| 		testPath = ptestPath; | ||||
| 	string testPath = test::getTestPath(); | ||||
| 	testPath += "/BasicTests"; | ||||
| 
 | ||||
| 	cnote << "Testing Hex-Prefix-Encode..."; | ||||
| 	js::mValue v; | ||||
| @ -62,3 +58,4 @@ BOOST_AUTO_TEST_CASE(hexPrefix_test) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
|  | ||||
							
								
								
									
										149
									
								
								jsonrpc.cpp
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								jsonrpc.cpp
									
									
									
									
									
								
							| @ -29,8 +29,8 @@ | ||||
| #include <libwebthree/WebThree.h> | ||||
| #include <libweb3jsonrpc/WebThreeStubServer.h> | ||||
| #include <libweb3jsonrpc/CorsHttpServer.h> | ||||
| #include <jsonrpccpp/server/connectors/httpserver.h> | ||||
| #include <jsonrpccpp/client/connectors/httpclient.h> | ||||
| #include <jsonrpc/connectors/httpserver.h> | ||||
| #include <jsonrpc/connectors/httpclient.h> | ||||
| #include <set> | ||||
| #include "JsonSpiritHeaders.h" | ||||
| #include "TestHelper.h" | ||||
| @ -43,53 +43,45 @@ using namespace dev; | ||||
| using namespace dev::eth; | ||||
| namespace js = json_spirit; | ||||
| 
 | ||||
| namespace jsonrpc_tests | ||||
| { | ||||
| 
 | ||||
| string name = "Ethereum(++) tests"; | ||||
| string dbPath; | ||||
| auto s = set<string>{"eth", "shh"}; | ||||
| dev::p2p::NetworkPreferences np(30303, std::string(), false); | ||||
| dev::WebThreeDirect web3(name, dbPath, true, s, np); | ||||
| 
 | ||||
| WebThreeDirect *web3; | ||||
| unique_ptr<WebThreeStubServer> jsonrpcServer; | ||||
| unique_ptr<WebThreeStubClient> jsonrpcClient; | ||||
| unique_ptr<jsonrpc::AbstractServerConnector> jsonrpcConnector; | ||||
| jsonrpc::HttpClient httpClient("http://localhost:8080"); | ||||
| 
 | ||||
| struct JsonrpcFixture  { | ||||
| 	JsonrpcFixture() | ||||
| struct Setup | ||||
| { | ||||
| 		cnote << "setup jsonrpc"; | ||||
| 	Setup() | ||||
| 	{ | ||||
| 		static bool setup = false; | ||||
| 		if (setup) | ||||
| 			return; | ||||
| 		setup = true; | ||||
| 
 | ||||
| 		web3.setIdealPeerCount(5); | ||||
| 		web3.ethereum()->setForceMining(true); | ||||
| 		jsonrpcConnector = unique_ptr<jsonrpc::AbstractServerConnector>(new jsonrpc::CorsHttpServer(8080)); | ||||
| 		jsonrpcServer = unique_ptr<WebThreeStubServer>(new WebThreeStubServer(*jsonrpcConnector.get(), web3, {})); | ||||
| 		dev::p2p::NetworkPreferences nprefs(30303, std::string(), false); | ||||
| 		web3 = new WebThreeDirect("Ethereum(++) tests", "", true, {"eth", "shh"}, nprefs); | ||||
| 		 | ||||
| 		web3->setIdealPeerCount(5); | ||||
| 		web3->ethereum()->setForceMining(true); | ||||
| 		jsonrpcServer = unique_ptr<WebThreeStubServer>(new WebThreeStubServer(new jsonrpc::CorsHttpServer(8080), *web3, {})); | ||||
| 		jsonrpcServer->setIdentities({}); | ||||
| 		jsonrpcServer->StartListening(); | ||||
| 		 | ||||
| 		jsonrpcClient = unique_ptr<WebThreeStubClient>(new WebThreeStubClient(httpClient)); | ||||
| 	} | ||||
| 	~JsonrpcFixture() | ||||
| 	{ | ||||
| 		cnote << "teardown jsonrpc"; | ||||
| 		jsonrpcClient = unique_ptr<WebThreeStubClient>(new WebThreeStubClient(new jsonrpc::HttpClient("http://localhost:8080"))); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| BOOST_GLOBAL_FIXTURE(JsonrpcFixture) | ||||
| BOOST_FIXTURE_TEST_SUITE(environment, Setup) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_defaultBlock) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc defaultBlock..."; | ||||
| 	int defaultBlock = jsonrpcClient->defaultBlock(); | ||||
| 	BOOST_CHECK_EQUAL(defaultBlock, web3.ethereum()->getDefault()); | ||||
| 	int defaultBlock = jsonrpcClient->eth_defaultBlock(); | ||||
| 	BOOST_CHECK_EQUAL(defaultBlock, web3->ethereum()->getDefault()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_gasPrice) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc gasPrice..."; | ||||
| 	string gasPrice = jsonrpcClient->gasPrice(); | ||||
| 	string gasPrice = jsonrpcClient->eth_gasPrice(); | ||||
| 	BOOST_CHECK_EQUAL(gasPrice, toJS(10 * dev::eth::szabo)); | ||||
| } | ||||
| 
 | ||||
| @ -97,26 +89,26 @@ BOOST_AUTO_TEST_CASE(jsonrpc_isListening) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc isListening..."; | ||||
| 
 | ||||
| 	web3.startNetwork(); | ||||
| 	bool listeningOn = jsonrpcClient->listening(); | ||||
| 	BOOST_CHECK_EQUAL(listeningOn, web3.isNetworkStarted()); | ||||
| 	web3->startNetwork(); | ||||
| 	bool listeningOn = jsonrpcClient->eth_listening(); | ||||
| 	BOOST_CHECK_EQUAL(listeningOn, web3->isNetworkStarted()); | ||||
| 	 | ||||
| 	web3.stopNetwork(); | ||||
| 	bool listeningOff = jsonrpcClient->listening(); | ||||
| 	BOOST_CHECK_EQUAL(listeningOff, web3.isNetworkStarted()); | ||||
| 	web3->stopNetwork(); | ||||
| 	bool listeningOff = jsonrpcClient->eth_listening(); | ||||
| 	BOOST_CHECK_EQUAL(listeningOff, web3->isNetworkStarted()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_isMining) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc isMining..."; | ||||
| 
 | ||||
| 	web3.ethereum()->startMining(); | ||||
| 	bool miningOn = jsonrpcClient->mining(); | ||||
| 	BOOST_CHECK_EQUAL(miningOn, web3.ethereum()->isMining()); | ||||
| 	web3->ethereum()->startMining(); | ||||
| 	bool miningOn = jsonrpcClient->eth_mining(); | ||||
| 	BOOST_CHECK_EQUAL(miningOn, web3->ethereum()->isMining()); | ||||
| 
 | ||||
| 	web3.ethereum()->stopMining(); | ||||
| 	bool miningOff = jsonrpcClient->mining(); | ||||
| 	BOOST_CHECK_EQUAL(miningOff, web3.ethereum()->isMining()); | ||||
| 	web3->ethereum()->stopMining(); | ||||
| 	bool miningOff = jsonrpcClient->eth_mining(); | ||||
| 	BOOST_CHECK_EQUAL(miningOff, web3->ethereum()->isMining()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_accounts) | ||||
| @ -124,7 +116,7 @@ BOOST_AUTO_TEST_CASE(jsonrpc_accounts) | ||||
| 	cnote << "Testing jsonrpc accounts..."; | ||||
| 	std::vector <dev::KeyPair> keys = {KeyPair::create(), KeyPair::create()}; | ||||
| 	jsonrpcServer->setAccounts(keys); | ||||
| 	Json::Value k = jsonrpcClient->accounts(); | ||||
| 	Json::Value k = jsonrpcClient->eth_accounts(); | ||||
| 	jsonrpcServer->setAccounts({}); | ||||
| 	BOOST_CHECK_EQUAL(k.isArray(), true); | ||||
| 	BOOST_CHECK_EQUAL(k.size(),  keys.size()); | ||||
| @ -141,41 +133,41 @@ BOOST_AUTO_TEST_CASE(jsonrpc_accounts) | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_number) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc number2..."; | ||||
| 	int number = jsonrpcClient->number(); | ||||
| 	BOOST_CHECK_EQUAL(number, web3.ethereum()->number() + 1); | ||||
| 	dev::eth::mine(*(web3.ethereum()), 1); | ||||
| 	int numberAfter = jsonrpcClient->number(); | ||||
| 	int number = jsonrpcClient->eth_number(); | ||||
| 	BOOST_CHECK_EQUAL(number, web3->ethereum()->number() + 1); | ||||
| 	dev::eth::mine(*(web3->ethereum()), 1); | ||||
| 	int numberAfter = jsonrpcClient->eth_number(); | ||||
| 	BOOST_CHECK_EQUAL(number + 1, numberAfter); | ||||
| 	BOOST_CHECK_EQUAL(numberAfter, web3.ethereum()->number() + 1); | ||||
| 	BOOST_CHECK_EQUAL(numberAfter, web3->ethereum()->number() + 1); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_peerCount) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc peerCount..."; | ||||
| 	int peerCount = jsonrpcClient->peerCount(); | ||||
| 	BOOST_CHECK_EQUAL(web3.peerCount(), peerCount); | ||||
| 	int peerCount = jsonrpcClient->eth_peerCount(); | ||||
| 	BOOST_CHECK_EQUAL(web3->peerCount(), peerCount); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_setListening) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc setListening..."; | ||||
| 
 | ||||
| 	jsonrpcClient->setListening(true); | ||||
| 	BOOST_CHECK_EQUAL(web3.isNetworkStarted(), true); | ||||
| 	jsonrpcClient->eth_setListening(true); | ||||
| 	BOOST_CHECK_EQUAL(web3->isNetworkStarted(), true); | ||||
| 	 | ||||
| 	jsonrpcClient->setListening(false); | ||||
| 	BOOST_CHECK_EQUAL(web3.isNetworkStarted(), false); | ||||
| 	jsonrpcClient->eth_setListening(false); | ||||
| 	BOOST_CHECK_EQUAL(web3->isNetworkStarted(), false); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_setMining) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc setMining..."; | ||||
| 
 | ||||
| 	jsonrpcClient->setMining(true); | ||||
| 	BOOST_CHECK_EQUAL(web3.ethereum()->isMining(), true); | ||||
| 	jsonrpcClient->eth_setMining(true); | ||||
| 	BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), true); | ||||
| 
 | ||||
| 	jsonrpcClient->setMining(false); | ||||
| 	BOOST_CHECK_EQUAL(web3.ethereum()->isMining(), false); | ||||
| 	jsonrpcClient->eth_setMining(false); | ||||
| 	BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), false); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_stateAt) | ||||
| @ -183,38 +175,38 @@ BOOST_AUTO_TEST_CASE(jsonrpc_stateAt) | ||||
| 	cnote << "Testing jsonrpc stateAt..."; | ||||
| 	dev::KeyPair key = KeyPair::create(); | ||||
| 	auto address = key.address(); | ||||
| 	string stateAt = jsonrpcClient->stateAt(toJS(address), "0"); | ||||
| 	BOOST_CHECK_EQUAL(toJS(web3.ethereum()->stateAt(address, jsToU256("0"), 0)), stateAt); | ||||
| 	string stateAt = jsonrpcClient->eth_stateAt(toJS(address), "0"); | ||||
| 	BOOST_CHECK_EQUAL(toJS(web3->ethereum()->stateAt(address, jsToU256("0"), 0)), stateAt); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(jsonrpc_transact) | ||||
| { | ||||
| 	cnote << "Testing jsonrpc transact..."; | ||||
| 	string coinbase = jsonrpcClient->coinbase(); | ||||
| 	BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3.ethereum()->address()); | ||||
| 	string coinbase = jsonrpcClient->eth_coinbase(); | ||||
| 	BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address()); | ||||
| 	 | ||||
| 	dev::KeyPair key = KeyPair::create(); | ||||
| 	auto address = key.address(); | ||||
| 	auto receiver = KeyPair::create(); | ||||
| 	web3.ethereum()->setAddress(address); | ||||
| 	web3->ethereum()->setAddress(address); | ||||
| 
 | ||||
| 	coinbase = jsonrpcClient->coinbase(); | ||||
| 	BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3.ethereum()->address()); | ||||
| 	coinbase = jsonrpcClient->eth_coinbase(); | ||||
| 	BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address()); | ||||
| 	BOOST_CHECK_EQUAL(jsToAddress(coinbase), address); | ||||
| 	 | ||||
| 	jsonrpcServer->setAccounts({key}); | ||||
| 	auto balance = web3.ethereum()->balanceAt(address, 0); | ||||
| 	string balanceString = jsonrpcClient->balanceAt(toJS(address)); | ||||
| 	double countAt = jsonrpcClient->countAt(toJS(address)); | ||||
| 	auto balance = web3->ethereum()->balanceAt(address, 0); | ||||
| 	string balanceString = jsonrpcClient->eth_balanceAt(toJS(address)); | ||||
| 	double countAt = jsonrpcClient->eth_countAt(toJS(address)); | ||||
| 	 | ||||
| 	BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3.ethereum()->countAt(address)); | ||||
| 	BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address)); | ||||
| 	BOOST_CHECK_EQUAL(countAt, 0); | ||||
| 	BOOST_CHECK_EQUAL(toJS(balance), balanceString); | ||||
| 	BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "0"); | ||||
| 	 | ||||
| 	dev::eth::mine(*(web3.ethereum()), 1); | ||||
| 	balance = web3.ethereum()->balanceAt(address, 0); | ||||
| 	balanceString = jsonrpcClient->balanceAt(toJS(address)); | ||||
| 	dev::eth::mine(*(web3->ethereum()), 1); | ||||
| 	balance = web3->ethereum()->balanceAt(address, 0); | ||||
| 	balanceString = jsonrpcClient->eth_balanceAt(toJS(address)); | ||||
| 	 | ||||
| 	BOOST_CHECK_EQUAL(toJS(balance), balanceString); | ||||
| 	BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "1500000000000000000"); | ||||
| @ -231,23 +223,22 @@ BOOST_AUTO_TEST_CASE(jsonrpc_transact) | ||||
| 	t["gas"] = toJS(gas); | ||||
| 	t["gasPrice"] = toJS(gasPrice); | ||||
| 	 | ||||
| 	jsonrpcClient->transact(t); | ||||
| 	jsonrpcClient->eth_transact(t); | ||||
| 	jsonrpcServer->setAccounts({}); | ||||
| 	dev::eth::mine(*(web3.ethereum()), 1); | ||||
| 	dev::eth::mine(*(web3->ethereum()), 1); | ||||
| 	 | ||||
| 	countAt = jsonrpcClient->countAt(toJS(address)); | ||||
| 	auto balance2 = web3.ethereum()->balanceAt(receiver.address()); | ||||
| 	string balanceString2 = jsonrpcClient->balanceAt(toJS(receiver.address())); | ||||
| 	countAt = jsonrpcClient->eth_countAt(toJS(address)); | ||||
| 	auto balance2 = web3->ethereum()->balanceAt(receiver.address()); | ||||
| 	string balanceString2 = jsonrpcClient->eth_balanceAt(toJS(receiver.address())); | ||||
| 	 | ||||
| 	BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3.ethereum()->countAt(address)); | ||||
| 	BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address)); | ||||
| 	BOOST_CHECK_EQUAL(countAt, 1); | ||||
| 	BOOST_CHECK_EQUAL(toJS(balance2), balanceString2); | ||||
| 	BOOST_CHECK_EQUAL(jsToDecimal(balanceString2), "750000000000000000"); | ||||
| 	BOOST_CHECK_EQUAL(txAmount, balance2); | ||||
| } | ||||
| 	 | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										6
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								main.cpp
									
									
									
									
									
								
							| @ -41,8 +41,8 @@ using namespace std; | ||||
| using namespace dev; | ||||
| using namespace dev::eth; | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(basic_tests) | ||||
| { | ||||
| //BOOST_AUTO_TEST_CASE(basic_tests)
 | ||||
| //{
 | ||||
| /*	RLPStream s;
 | ||||
| 	BlockInfo::genesis().streamRLP(s, false); | ||||
| 	std::cout << RLP(s.out()) << std::endl; | ||||
| @ -54,5 +54,5 @@ BOOST_AUTO_TEST_CASE(basic_tests) | ||||
| //	r += stateTest();
 | ||||
| //	r += peerTest(argc, argv);
 | ||||
| //	BOOST_REQUIRE(!r);
 | ||||
| } | ||||
| //}
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										15
									
								
								rlp.cpp
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								rlp.cpp
									
									
									
									
									
								
							| @ -29,6 +29,7 @@ | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include <algorithm> | ||||
| #include "JsonSpiritHeaders.h" | ||||
| #include "TestHelper.h" | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| @ -61,16 +62,8 @@ namespace dev | ||||
| 
 | ||||
| 		static void getRLPTestCases(js::mValue& v) | ||||
| 		{ | ||||
| 			const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); | ||||
| 			string testPath; | ||||
| 
 | ||||
| 			if (ptestPath == NULL) | ||||
| 			{ | ||||
| 				cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; | ||||
| 				testPath = "../../../tests"; | ||||
| 			} | ||||
| 			else | ||||
| 				testPath = ptestPath; | ||||
| 			string testPath = getTestPath(); | ||||
| 			testPath += "/BasicTests"; | ||||
| 
 | ||||
| 			string s = asString(contents(testPath + "/rlptest.json")); | ||||
| 			BOOST_REQUIRE_MESSAGE( s.length() > 0,  | ||||
| @ -144,6 +137,7 @@ namespace dev | ||||
| 	} | ||||
| }  | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(BasicTests) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(rlp_encoding_test) | ||||
| { | ||||
| @ -202,4 +196,5 @@ BOOST_AUTO_TEST_CASE(rlp_decoding_test) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| 
 | ||||
| /*
 | ||||
| 	This file is part of cpp-ethereum. | ||||
| 
 | ||||
| @ -18,18 +17,21 @@ | ||||
| /**
 | ||||
|  * @author Christian <c@ethdev.com> | ||||
|  * @date 2014 | ||||
|  * Unit tests for the name and type resolution of the solidity parser. | ||||
|  * Unit tests for the solidity compiler. | ||||
|  */ | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include <libdevcore/Log.h> | ||||
| #include <libsolidity/Scanner.h> | ||||
| #include <libsolidity/Parser.h> | ||||
| #include <libsolidity/NameAndTypeResolver.h> | ||||
| #include <libsolidity/Compiler.h> | ||||
| #include <libsolidity/AST.h> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev::eth; | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| @ -41,184 +43,185 @@ namespace test | ||||
| namespace | ||||
| { | ||||
| 
 | ||||
| /**
 | ||||
|  * Helper class that extracts the first expression in an AST. | ||||
|  */ | ||||
| class FirstExpressionExtractor: private ASTVisitor | ||||
| { | ||||
| public: | ||||
| 	FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); } | ||||
| 	Expression* getExpression() const { return m_expression; } | ||||
| private: | ||||
| 	virtual bool visit(Expression& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(Literal& _expression) override { return checkExpression(_expression); } | ||||
| 	bool checkExpression(Expression& _expression) | ||||
| 	{ | ||||
| 		if (m_expression == nullptr) | ||||
| 			m_expression = &_expression; | ||||
| 		return false; | ||||
| 	} | ||||
| private: | ||||
| 	Expression* m_expression; | ||||
| }; | ||||
| 
 | ||||
| bytes compileFirstExpression(std::string const& _sourceCode) | ||||
| bytes compileContract(const string& _sourceCode) | ||||
| { | ||||
| 	Parser parser; | ||||
| 	ASTPointer<ContractDefinition> contract; | ||||
| 	BOOST_REQUIRE_NO_THROW(contract = parser.parse(std::make_shared<Scanner>(CharStream(_sourceCode)))); | ||||
| 	BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared<Scanner>(CharStream(_sourceCode)))); | ||||
| 	NameAndTypeResolver resolver; | ||||
| 	BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); | ||||
| 	FirstExpressionExtractor extractor(*contract); | ||||
| 	BOOST_REQUIRE(extractor.getExpression() != nullptr); | ||||
| 
 | ||||
| 	CompilerContext context; | ||||
| 	ExpressionCompiler compiler(context); | ||||
| 	compiler.compile(*extractor.getExpression()); | ||||
| 	bytes instructions = compiler.getAssembledBytecode(); | ||||
| 	Compiler compiler; | ||||
| 	compiler.compileContract(*contract); | ||||
| 	// debug
 | ||||
| 	//std::cout << eth::disassemble(instructions) << std::endl;
 | ||||
| 	return instructions; | ||||
| 	//compiler.streamAssembly(cout);
 | ||||
| 	return compiler.getAssembledBytecode(); | ||||
| } | ||||
| 
 | ||||
| /// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
 | ||||
| /// This is necessary since the compiler will add boilerplate add the beginning that is not
 | ||||
| /// tested here.
 | ||||
| void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset) | ||||
| { | ||||
| 	BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size()); | ||||
| 	auto checkStart = _compiledCode.begin() + _offset; | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(), | ||||
| 								  _expectation.begin(), _expectation.end()); | ||||
| } | ||||
| 
 | ||||
| } // end anonymous namespace
 | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(SolidityExpressionCompiler) | ||||
| BOOST_AUTO_TEST_SUITE(SolidityCompiler) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(literal_true) | ||||
| BOOST_AUTO_TEST_CASE(smoke_test) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = true; }" | ||||
| 							 "  function f() { var x = 2; }\n" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 	bytes code = compileContract(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| 	unsigned boilerplateSize = 42; | ||||
| 	bytes expectation({byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::PUSH1), 0x0, // initialize local variable x
 | ||||
| 					   byte(Instruction::PUSH1), 0x2, | ||||
| 					   byte(Instruction::SWAP1), | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::JUMP)}); | ||||
| 	checkCodePresentAt(code, expectation, boilerplateSize); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(literal_false) | ||||
| BOOST_AUTO_TEST_CASE(different_argument_numbers) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = false; }" | ||||
| 							 "  function f(uint a, uint b, uint c) returns(uint d) { return b; }\n" | ||||
| 							 "  function g() returns (uint e, uint h) { h = f(1, 2, 3); }\n" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 	bytes code = compileContract(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x0}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| 	unsigned shift = 70; | ||||
| 	unsigned boilerplateSize = 83; | ||||
| 	bytes expectation({byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::PUSH1), 0x0, // initialize return variable d
 | ||||
| 					   byte(Instruction::DUP3), | ||||
| 					   byte(Instruction::SWAP1), // assign b to d
 | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::PUSH1), byte(0xa + shift), // jump to return
 | ||||
| 					   byte(Instruction::JUMP), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::SWAP4), // store d and fetch return address
 | ||||
| 					   byte(Instruction::SWAP3), // store return address
 | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::JUMP), // end of f
 | ||||
| 					   byte(Instruction::JUMPDEST), // beginning of g
 | ||||
| 					   byte(Instruction::PUSH1), 0x0, | ||||
| 					   byte(Instruction::DUP1), // initialized e and h
 | ||||
| 					   byte(Instruction::PUSH1), byte(0x29 + shift), // ret address
 | ||||
| 					   byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), | ||||
| 					   byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), | ||||
| 					   byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), | ||||
| 					   byte(Instruction::PUSH1), byte(0x1 + shift), | ||||
| 					   // stack here: ret e h 0x20 1 2 3 0x1
 | ||||
| 					   byte(Instruction::JUMP), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   // stack here: ret e h f(1,2,3)
 | ||||
| 					   byte(Instruction::SWAP1), | ||||
| 					   // stack here: ret e f(1,2,3) h
 | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::DUP1), // retrieve it again as "value of expression"
 | ||||
| 					   byte(Instruction::POP), // end of assignment
 | ||||
| 					   // stack here: ret e f(1,2,3)
 | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::SWAP1), | ||||
| 					   // ret e f(1,2,3)
 | ||||
| 					   byte(Instruction::SWAP2), | ||||
| 					   // f(1,2,3) e ret
 | ||||
| 					   byte(Instruction::JUMP) // end of g
 | ||||
| 					   }); | ||||
| 	checkCodePresentAt(code, expectation, boilerplateSize); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(int_literal) | ||||
| BOOST_AUTO_TEST_CASE(ifStatement) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = 0x12345678901234567890; }" | ||||
| 							 "  function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 	bytes code = compileContract(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, | ||||
| 													   0x12, 0x34, 0x56, 0x78, 0x90}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| 	unsigned shift = 29; | ||||
| 	unsigned boilerplateSize = 42; | ||||
| 	bytes expectation({byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::PUSH1), 0x0, | ||||
| 					   byte(Instruction::DUP1), | ||||
| 					   byte(Instruction::PUSH1), byte(0x1b + shift), // "true" target
 | ||||
| 					   byte(Instruction::JUMPI), | ||||
| 					   // new check "else if" condition
 | ||||
| 					   byte(Instruction::DUP1), | ||||
| 					   byte(Instruction::ISZERO), | ||||
| 					   byte(Instruction::PUSH1), byte(0x13 + shift), | ||||
| 					   byte(Instruction::JUMPI), | ||||
| 					   // "else" body
 | ||||
| 					   byte(Instruction::PUSH1), 0x4f, | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::PUSH1), byte(0x17 + shift), // exit path of second part
 | ||||
| 					   byte(Instruction::JUMP), | ||||
| 					   // "else if" body
 | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::PUSH1), 0x4e, | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::PUSH1), byte(0x1f + shift), | ||||
| 					   byte(Instruction::JUMP), | ||||
| 					   // "if" body
 | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::PUSH1), 0x4d, | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::JUMP)}); | ||||
| 	checkCodePresentAt(code, expectation, boilerplateSize); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(comparison) | ||||
| BOOST_AUTO_TEST_CASE(loops) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = (0x10aa < 0x11aa) != true; }" | ||||
| 							 "  function f() { while(true){1;break;2;continue;3;return;4;} }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 	bytes code = compileContract(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, | ||||
| 					   byte(eth::Instruction::PUSH2), 0x11, 0xaa, | ||||
| 					   byte(eth::Instruction::GT), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::NOT)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 	unsigned shift = 29; | ||||
| 	unsigned boilerplateSize = 42; | ||||
| 	bytes expectation({byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::ISZERO), | ||||
| 					   byte(Instruction::PUSH1), byte(0x21 + shift), | ||||
| 					   byte(Instruction::JUMPI), | ||||
| 					   byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::PUSH1), byte(0x21 + shift), | ||||
| 					   byte(Instruction::JUMP), // break
 | ||||
| 					   byte(Instruction::PUSH1), 0x2, | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::PUSH1), byte(0x2 + shift), | ||||
| 					   byte(Instruction::JUMP), // continue
 | ||||
| 					   byte(Instruction::PUSH1), 0x3, | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::PUSH1), byte(0x22 + shift), | ||||
| 					   byte(Instruction::JUMP), // return
 | ||||
| 					   byte(Instruction::PUSH1), 0x4, | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::PUSH1), byte(0x2 + shift), | ||||
| 					   byte(Instruction::JUMP), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::JUMP)}); | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(short_circuiting) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = (10 + 8 >= 4 || 2 != 9) != true; }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0xa, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x8, | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x4, | ||||
| 					   byte(eth::Instruction::GT), | ||||
| 					   byte(eth::Instruction::NOT), // after this we have 10 + 8 >= 4
 | ||||
| 					   byte(eth::Instruction::DUP1), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x14, | ||||
| 					   byte(eth::Instruction::JUMPI), // short-circuit if it is true
 | ||||
| 					   byte(eth::Instruction::PUSH1), 0x2, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x9, | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::NOT), // after this we have 2 != 9
 | ||||
| 					   byte(eth::Instruction::JUMPDEST), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::NOT)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(arithmetics) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x2, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x3, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x4, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x5, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x6, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x7, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x8, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x9, | ||||
| 					   byte(eth::Instruction::XOR), | ||||
| 					   byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::OR), | ||||
| 					   byte(eth::Instruction::SWAP1), | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   byte(eth::Instruction::MOD), | ||||
| 					   byte(eth::Instruction::DIV), | ||||
| 					   byte(eth::Instruction::MUL)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(unary_operators) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = !(~+-(--(++1++)--) == 2); }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::SWAP1), | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x0, | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(eth::Instruction::NOT), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x2, | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| 	checkCodePresentAt(code, expectation, boilerplateSize); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
|  | ||||
							
								
								
									
										708
									
								
								solidityEndToEndTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										708
									
								
								solidityEndToEndTest.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,708 @@ | ||||
| 
 | ||||
| /*
 | ||||
| 	This file is part of cpp-ethereum. | ||||
| 
 | ||||
| 	cpp-ethereum is free software: you can redistribute it and/or modify | ||||
| 	it under the terms of the GNU General Public License as published by | ||||
| 	the Free Software Foundation, either version 3 of the License, or | ||||
| 	(at your option) any later version. | ||||
| 
 | ||||
| 	cpp-ethereum is distributed in the hope that it will be useful, | ||||
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| 	GNU General Public License for more details. | ||||
| 
 | ||||
| 	You should have received a copy of the GNU General Public License | ||||
| 	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| /**
 | ||||
|  * @author Christian <c@ethdev.com> | ||||
|  * @date 2014 | ||||
|  * Unit tests for the solidity expression compiler, testing the behaviour of the code. | ||||
|  */ | ||||
| 
 | ||||
| #include <string> | ||||
| #include <tuple> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include <libethereum/State.h> | ||||
| #include <libethereum/Executive.h> | ||||
| #include <libsolidity/CompilerStack.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| /// Provider another overload for toBigEndian to encode arguments and return values.
 | ||||
| inline bytes toBigEndian(bool _value) { return bytes({byte(_value)}); } | ||||
| 
 | ||||
| namespace solidity | ||||
| { | ||||
| namespace test | ||||
| { | ||||
| 
 | ||||
| class ExecutionFramework | ||||
| { | ||||
| public: | ||||
| 	ExecutionFramework() { g_logVerbosity = 0; } | ||||
| 
 | ||||
| 	bytes const& compileAndRun(string const& _sourceCode) | ||||
| 	{ | ||||
| 		bytes code = dev::solidity::CompilerStack::staticCompile(_sourceCode); | ||||
| 		sendMessage(code, true); | ||||
| 		BOOST_REQUIRE(!m_output.empty()); | ||||
| 		return m_output; | ||||
| 	} | ||||
| 
 | ||||
| 	bytes const& callContractFunction(byte _index, bytes const& _data = bytes()) | ||||
| 	{ | ||||
| 		sendMessage(bytes(1, _index) + _data, false); | ||||
| 		return m_output; | ||||
| 	} | ||||
| 
 | ||||
| 	template <class... Args> | ||||
| 	bytes const& callContractFunction(byte _index, Args const&... _arguments) | ||||
| 	{ | ||||
| 		return callContractFunction(_index, argsToBigEndian(_arguments...)); | ||||
| 	} | ||||
| 
 | ||||
| 	template <class CppFunction, class... Args> | ||||
| 	void testSolidityAgainstCpp(byte _index, CppFunction const& _cppFunction, Args const&... _arguments) | ||||
| 	{ | ||||
| 		bytes solidityResult = callContractFunction(_index, _arguments...); | ||||
| 		bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); | ||||
| 		BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." | ||||
| 							"\nSolidity: " + toHex(solidityResult) + "\nC++:      " + toHex(cppResult)); | ||||
| 	} | ||||
| 
 | ||||
| 	template <class CppFunction, class... Args> | ||||
| 	void testSolidityAgainstCppOnRange(byte _index, CppFunction const& _cppFunction, | ||||
| 									   u256 const& _rangeStart, u256 const& _rangeEnd) | ||||
| 	{ | ||||
| 		for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) | ||||
| 		{ | ||||
| 			bytes solidityResult = callContractFunction(_index, argument); | ||||
| 			bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); | ||||
| 			BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." | ||||
| 								"\nSolidity: " + toHex(solidityResult) + "\nC++:      " + toHex(cppResult) + | ||||
| 								"\nArgument: " + toHex(toBigEndian(argument))); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	template <class FirstArg, class... Args> | ||||
| 	bytes argsToBigEndian(FirstArg const& _firstArg, Args const&... _followingArgs) const | ||||
| 	{ | ||||
| 		return toBigEndian(_firstArg) + argsToBigEndian(_followingArgs...); | ||||
| 	} | ||||
| 
 | ||||
| 	bytes argsToBigEndian() const { return bytes(); } | ||||
| 
 | ||||
| 	template <class CppFunction, class... Args> | ||||
| 	auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) | ||||
| 	-> typename enable_if<is_void<decltype(_cppFunction(_arguments...))>::value, bytes>::type | ||||
| 	{ | ||||
| 		_cppFunction(_arguments...); | ||||
| 		return bytes(); | ||||
| 	} | ||||
| 	template <class CppFunction, class... Args> | ||||
| 	auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) | ||||
| 	-> typename enable_if<!is_void<decltype(_cppFunction(_arguments...))>::value, bytes>::type | ||||
| 	{ | ||||
| 		return toBigEndian(_cppFunction(_arguments...)); | ||||
| 	} | ||||
| 
 | ||||
| 	void sendMessage(bytes const& _data, bool _isCreation) | ||||
| 	{ | ||||
| 		eth::Executive executive(m_state); | ||||
| 		eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) | ||||
| 										 : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); | ||||
| 		bytes transactionRLP = t.rlp(); | ||||
| 		try | ||||
| 		{ | ||||
| 			// this will throw since the transaction is invalid, but it should nevertheless store the transaction
 | ||||
| 			executive.setup(&transactionRLP); | ||||
| 		} | ||||
| 		catch (...) {} | ||||
| 		if (_isCreation) | ||||
| 		{ | ||||
| 			BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address())); | ||||
| 			m_contractAddress = executive.newAddress(); | ||||
| 			BOOST_REQUIRE(m_contractAddress); | ||||
| 			BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); | ||||
| 			BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); | ||||
| 		} | ||||
| 		BOOST_REQUIRE(executive.go()); | ||||
| 		executive.finalize(); | ||||
| 		m_output = executive.out().toVector(); | ||||
| 	} | ||||
| 
 | ||||
| protected: | ||||
| 	Address m_contractAddress; | ||||
| 	eth::State m_state; | ||||
| 	u256 const m_gasPrice = 100 * eth::szabo; | ||||
| 	u256 const m_gas = 1000000; | ||||
| 	bytes m_output; | ||||
| }; | ||||
| 
 | ||||
| BOOST_FIXTURE_TEST_SUITE(SolidityCompilerEndToEndTest, ExecutionFramework) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(smoke_test) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f(uint a) returns(uint d) { return a * 7; }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	testSolidityAgainstCppOnRange(0, [](u256 const& a) -> u256 { return a * 7; }, 0, 100); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(empty_contract) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes()).empty()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(recursive_calls) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f(uint n) returns(uint nfac) {\n" | ||||
| 							 "    if (n <= 1) return 1;\n" | ||||
| 							 "    else return n * f(n - 1);\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	function<u256(u256)> recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256 | ||||
| 	{ | ||||
| 		if (n <= 1) | ||||
| 			return 1; | ||||
| 		else | ||||
| 			return n * recursive_calls_cpp(n - 1); | ||||
| 	}; | ||||
| 
 | ||||
| 	testSolidityAgainstCppOnRange(0, recursive_calls_cpp, 0, 5); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(multiple_functions) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function a() returns(uint n) { return 0; }\n" | ||||
| 							 "  function b() returns(uint n) { return 1; }\n" | ||||
| 							 "  function c() returns(uint n) { return 2; }\n" | ||||
| 							 "  function f() returns(uint n) { return 3; }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes()) == toBigEndian(u256(0))); | ||||
| 	BOOST_CHECK(callContractFunction(1, bytes()) == toBigEndian(u256(1))); | ||||
| 	BOOST_CHECK(callContractFunction(2, bytes()) == toBigEndian(u256(2))); | ||||
| 	BOOST_CHECK(callContractFunction(3, bytes()) == toBigEndian(u256(3))); | ||||
| 	BOOST_CHECK(callContractFunction(4, bytes()) == bytes()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(while_loop) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f(uint n) returns(uint nfac) {\n" | ||||
| 							 "    nfac = 1;\n" | ||||
| 							 "    var i = 2;\n" | ||||
| 							 "    while (i <= n) nfac *= i++;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 
 | ||||
| 	auto while_loop_cpp = [](u256 const& n) -> u256 | ||||
| 	{ | ||||
| 		u256 nfac = 1; | ||||
| 		u256 i = 2; | ||||
| 		while (i <= n) | ||||
| 			nfac *= i++; | ||||
| 
 | ||||
| 		return nfac; | ||||
| 	}; | ||||
| 
 | ||||
| 	testSolidityAgainstCppOnRange(0, while_loop_cpp, 0, 5); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(break_outside_loop) | ||||
| { | ||||
| 	// break and continue outside loops should be simply ignored
 | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f(uint x) returns(uint y) {\n" | ||||
| 							 "    break; continue; return 2;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	testSolidityAgainstCpp(0, [](u256 const&) -> u256 { return 2; }, u256(0)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(nested_loops) | ||||
| { | ||||
| 	// tests that break and continue statements in nested loops jump to the correct place
 | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f(uint x) returns(uint y) {\n" | ||||
| 							 "    while (x > 1) {\n" | ||||
| 							 "      if (x == 10) break;\n" | ||||
| 							 "      while (x > 5) {\n" | ||||
| 							 "        if (x == 8) break;\n" | ||||
| 							 "        x--;\n" | ||||
| 							 "        if (x == 6) continue;\n" | ||||
| 							 "        return x;\n" | ||||
| 							 "      }\n" | ||||
| 							 "      x--;\n" | ||||
| 							 "      if (x == 3) continue;\n" | ||||
| 							 "      break;\n" | ||||
| 							 "    }\n" | ||||
| 							 "    return x;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 
 | ||||
| 	auto nested_loops_cpp = [](u256  n) -> u256 | ||||
| 	{ | ||||
| 		while (n > 1) | ||||
| 		{ | ||||
| 			if (n == 10) | ||||
| 				break; | ||||
| 			while (n > 5) | ||||
| 			{ | ||||
| 				if (n == 8) | ||||
| 					break; | ||||
| 				n--; | ||||
| 				if (n == 6) | ||||
| 					continue; | ||||
| 				return n; | ||||
| 			} | ||||
| 			n--; | ||||
| 			if (n == 3) | ||||
| 				continue; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		return n; | ||||
| 	}; | ||||
| 
 | ||||
| 	testSolidityAgainstCppOnRange(0, nested_loops_cpp, 0, 12); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(calling_other_functions) | ||||
| { | ||||
| 	// note that the index of a function is its index in the sorted sequence of functions
 | ||||
| 	char const* sourceCode = "contract collatz {\n" | ||||
| 							 "  function run(uint x) returns(uint y) {\n" | ||||
| 							 "    while ((y = x) > 1) {\n" | ||||
| 							 "      if (x % 2 == 0) x = evenStep(x);\n" | ||||
| 							 "      else x = oddStep(x);\n" | ||||
| 							 "    }\n" | ||||
| 							 "  }\n" | ||||
| 							 "  function evenStep(uint x) returns(uint y) {\n" | ||||
| 							 "    return x / 2;\n" | ||||
| 							 "  }\n" | ||||
| 							 "  function oddStep(uint x) returns(uint y) {\n" | ||||
| 							 "    return 3 * x + 1;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 
 | ||||
| 	auto evenStep_cpp = [](u256 const& n) -> u256 | ||||
| 	{ | ||||
| 		return n / 2; | ||||
| 	}; | ||||
| 
 | ||||
| 	auto oddStep_cpp = [](u256 const& n) -> u256 | ||||
| 	{ | ||||
| 		return 3 * n + 1; | ||||
| 	}; | ||||
| 
 | ||||
| 	auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp](u256 n) -> u256 | ||||
| 	{ | ||||
| 		u256 y; | ||||
| 		while ((y = n) > 1) | ||||
| 		{ | ||||
| 			if (n % 2 == 0) | ||||
| 				n = evenStep_cpp(n); | ||||
| 			else | ||||
| 				n = oddStep_cpp(n); | ||||
| 		} | ||||
| 		return y; | ||||
| 	}; | ||||
| 
 | ||||
| 	testSolidityAgainstCpp(2, collatz_cpp, u256(0)); | ||||
| 	testSolidityAgainstCpp(2, collatz_cpp, u256(1)); | ||||
| 	testSolidityAgainstCpp(2, collatz_cpp, u256(2)); | ||||
| 	testSolidityAgainstCpp(2, collatz_cpp, u256(8)); | ||||
| 	testSolidityAgainstCpp(2, collatz_cpp, u256(127)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(many_local_variables) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function run(uint x1, uint x2, uint x3) returns(uint y) {\n" | ||||
| 							 "    var a = 0x1; var b = 0x10; var c = 0x100;\n" | ||||
| 							 "    y = a + b + c + x1 + x2 + x3;\n" | ||||
| 							 "    y += b + x2;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	auto f = [](u256 const& x1, u256 const& x2, u256 const& x3) -> u256 | ||||
| 	{ | ||||
| 		u256 a = 0x1; | ||||
| 		u256 b = 0x10; | ||||
| 		u256 c = 0x100; | ||||
| 		u256 y = a + b + c + x1 + x2 + x3; | ||||
| 		return y + b + x2; | ||||
| 	}; | ||||
| 	testSolidityAgainstCpp(0, f, u256(0x1000), u256(0x10000), u256(0x100000)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(packing_unpacking_types) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n" | ||||
| 							 "    if (a) y = 1;\n" | ||||
| 							 "    y = y * 0x100000000 | ~b;\n" | ||||
| 							 "    y = y * 0x10000000000000000 | ~c;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	BOOST_CHECK(callContractFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) | ||||
| 				== fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f")); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(multiple_return_values) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function run(bool x1, uint x2) returns(uint y1, bool y2, uint y3) {\n" | ||||
| 							 "    y1 = x2; y2 = x1;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) | ||||
| 				== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0))); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(short_circuiting) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function run(uint x) returns(uint y) {\n" | ||||
| 							 "    x == 0 || ((x = 8) > 0);\n" | ||||
| 							 "    return x;" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 
 | ||||
| 	auto short_circuiting_cpp = [](u256 n) -> u256 | ||||
| 	{ | ||||
| 		n == 0 || (n = 8) > 0; | ||||
| 		return n; | ||||
| 	}; | ||||
| 
 | ||||
| 	testSolidityAgainstCppOnRange(0, short_circuiting_cpp, 0, 2); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(high_bits_cleaning) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function run() returns(uint256 y) {\n" | ||||
| 							 "    uint32 x = uint32(0xffffffff) + 10;\n" | ||||
| 							 "    if (x >= 0xffffffff) return 0;\n" | ||||
| 							 "    return x;" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	auto high_bits_cleaning_cpp = []() -> u256 | ||||
| 	{ | ||||
| 		uint32_t x = uint32_t(0xffffffff) + 10; | ||||
| 		if (x >= 0xffffffff) | ||||
| 			return 0; | ||||
| 		return x; | ||||
| 	}; | ||||
| 	testSolidityAgainstCpp(0, high_bits_cleaning_cpp); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(sign_extension) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function run() returns(uint256 y) {\n" | ||||
| 							 "    int64 x = -int32(0xff);\n" | ||||
| 							 "    if (x >= 0xff) return 0;\n" | ||||
| 							 "    return -uint256(x);" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	auto sign_extension_cpp = []() -> u256 | ||||
| 	{ | ||||
| 		int64_t x = -int32_t(0xff); | ||||
| 		if (x >= 0xff) | ||||
| 			return 0; | ||||
| 		return u256(x) * -1; | ||||
| 	}; | ||||
| 	testSolidityAgainstCpp(0, sign_extension_cpp); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(small_unsigned_types) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function run() returns(uint256 y) {\n" | ||||
| 							 "    uint32 x = uint32(0xffffff) * 0xffffff;\n" | ||||
| 							 "    return x / 0x100;" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	auto small_unsigned_types_cpp = []() -> u256 | ||||
| 	{ | ||||
| 		uint32_t x = uint32_t(0xffffff) * 0xffffff; | ||||
| 		return x / 0x100; | ||||
| 	}; | ||||
| 	testSolidityAgainstCpp(0, small_unsigned_types_cpp); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(small_signed_types) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function run() returns(int256 y) {\n" | ||||
| 							 "    return -int32(10) * -int64(20);\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	auto small_signed_types_cpp = []() -> u256 | ||||
| 	{ | ||||
| 		return -int32_t(10) * -int64_t(20); | ||||
| 	}; | ||||
| 	testSolidityAgainstCpp(0, small_signed_types_cpp); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(state_smoke_test) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  uint256 value1;\n" | ||||
| 							 "  uint256 value2;\n" | ||||
| 							 "  function get(uint8 which) returns (uint256 value) {\n" | ||||
| 							 "    if (which == 0) return value1;\n" | ||||
| 							 "    else return value2;\n" | ||||
| 							 "  }\n" | ||||
| 							 "  function set(uint8 which, uint256 value) {\n" | ||||
| 							 "    if (which == 0) value1 = value;\n" | ||||
| 							 "    else value2 = value;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0))); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0))); | ||||
| 	BOOST_CHECK(callContractFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes()); | ||||
| 	BOOST_CHECK(callContractFunction(1, bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes()); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x1234))); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0x8765))); | ||||
| 	BOOST_CHECK(callContractFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes()); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3))); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(simple_mapping) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  mapping(uint8 => uint8) table;\n" | ||||
| 							 "  function get(uint8 k) returns (uint8 v) {\n" | ||||
| 							 "    return table[k];\n" | ||||
| 							 "  }\n" | ||||
| 							 "  function set(uint8 k, uint8 v) {\n" | ||||
| 							 "    table[k] = v;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 
 | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0x00})) == bytes({0x00})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0x01})) == bytes({0x00})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0xa7})) == bytes({0x00})); | ||||
| 	callContractFunction(1, bytes({0x01, 0xa1})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0x00})) == bytes({0x00})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0x01})) == bytes({0xa1})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0xa7})) == bytes({0x00})); | ||||
| 	callContractFunction(1, bytes({0x00, 0xef})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0x00})) == bytes({0xef})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0x01})) == bytes({0xa1})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0xa7})) == bytes({0x00})); | ||||
| 	callContractFunction(1, bytes({0x01, 0x05})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0x00})) == bytes({0xef})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0x01})) == bytes({0x05})); | ||||
| 	BOOST_CHECK(callContractFunction(0, bytes({0xa7})) == bytes({0x00})); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(mapping_state) | ||||
| { | ||||
| 	char const* sourceCode = "contract Ballot {\n" | ||||
| 							 "  mapping(address => bool) canVote;\n" | ||||
| 							 "  mapping(address => uint) voteCount;\n" | ||||
| 							 "  mapping(address => bool) voted;\n" | ||||
| 							 "  function getVoteCount(address addr) returns (uint retVoteCount) {\n" | ||||
| 							 "    return voteCount[addr];\n" | ||||
| 							 "  }\n" | ||||
| 							 "  function grantVoteRight(address addr) {\n" | ||||
| 							 "    canVote[addr] = true;\n" | ||||
| 							 "  }\n" | ||||
| 							 "  function vote(address voter, address vote) returns (bool success) {\n" | ||||
| 							 "    if (!canVote[voter] || voted[voter]) return false;\n" | ||||
| 							 "    voted[voter] = true;\n" | ||||
| 							 "    voteCount[vote] = voteCount[vote] + 1;\n" | ||||
| 							 "    return true;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	class Ballot | ||||
| 	{ | ||||
| 	public: | ||||
| 		u256 getVoteCount(u160 _address) { return m_voteCount[_address]; } | ||||
| 		void grantVoteRight(u160 _address) { m_canVote[_address] = true; } | ||||
| 		bool vote(u160 _voter, u160 _vote) | ||||
| 		{ | ||||
| 			if (!m_canVote[_voter] || m_voted[_voter]) return false; | ||||
| 			m_voted[_voter] = true; | ||||
| 			m_voteCount[_vote]++; | ||||
| 			return true; | ||||
| 		} | ||||
| 	private: | ||||
| 		map<u160, bool> m_canVote; | ||||
| 		map<u160, u256> m_voteCount; | ||||
| 		map<u160, bool> m_voted; | ||||
| 	} ballot; | ||||
| 
 | ||||
| 	auto getVoteCount = bind(&Ballot::getVoteCount, &ballot, _1); | ||||
| 	auto grantVoteRight = bind(&Ballot::grantVoteRight, &ballot, _1); | ||||
| 	auto vote = bind(&Ballot::vote, &ballot, _1, _2); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(0)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(2)); | ||||
| 	// voting without vote right shourd be rejected
 | ||||
| 	testSolidityAgainstCpp(2, vote, u160(0), u160(2)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(0)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(2)); | ||||
| 	// grant vote rights
 | ||||
| 	testSolidityAgainstCpp(1, grantVoteRight, u160(0)); | ||||
| 	testSolidityAgainstCpp(1, grantVoteRight, u160(1)); | ||||
| 	// vote, should increase 2's vote count
 | ||||
| 	testSolidityAgainstCpp(2, vote, u160(0), u160(2)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(0)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(2)); | ||||
| 	// vote again, should be rejected
 | ||||
| 	testSolidityAgainstCpp(2, vote, u160(0), u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(0)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(2)); | ||||
| 	// vote without right to vote
 | ||||
| 	testSolidityAgainstCpp(2, vote, u160(2), u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(0)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(2)); | ||||
| 	// grant vote right and now vote again
 | ||||
| 	testSolidityAgainstCpp(1, grantVoteRight, u160(2)); | ||||
| 	testSolidityAgainstCpp(2, vote, u160(2), u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(0)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(1)); | ||||
| 	testSolidityAgainstCpp(0, getVoteCount, u160(2)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(mapping_state_inc_dec) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  uint value;\n" | ||||
| 							 "  mapping(uint => uint) table;\n" | ||||
| 							 "  function f(uint x) returns (uint y) {\n" | ||||
| 							 "    value = x;\n" | ||||
| 							 "    if (x > 0) table[++value] = 8;\n" | ||||
| 							 "    if (x > 1) value--;\n" | ||||
| 							 "    if (x > 2) table[value]++;\n" | ||||
| 							 "    return --table[value++];\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 
 | ||||
| 	u256 value = 0; | ||||
| 	map<u256, u256> table; | ||||
| 	auto f = [&](u256 const& _x) -> u256 | ||||
| 	{ | ||||
| 		value = _x; | ||||
| 		if (_x > 0) | ||||
| 			table[++value] = 8; | ||||
| 		if (_x > 1) | ||||
| 			value --; | ||||
| 		if (_x > 2) | ||||
| 			table[value]++; | ||||
| 		return --table[value++]; | ||||
| 	}; | ||||
| 	testSolidityAgainstCppOnRange(0, f, 0, 5); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(multi_level_mapping) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  mapping(uint => mapping(uint => uint)) table;\n" | ||||
| 							 "  function f(uint x, uint y, uint z) returns (uint w) {\n" | ||||
| 							 "    if (z == 0) return table[x][y];\n" | ||||
| 							 "    else return table[x][y] = z;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 
 | ||||
| 	map<u256, map<u256, u256>> table; | ||||
| 	auto f = [&](u256 const& _x, u256 const& _y, u256 const& _z) -> u256 | ||||
| 	{ | ||||
| 		if (_z == 0) return table[_x][_y]; | ||||
| 		else return table[_x][_y] = _z; | ||||
| 	}; | ||||
| 	testSolidityAgainstCpp(0, f, u256(4), u256(5), u256(0)); | ||||
| 	testSolidityAgainstCpp(0, f, u256(5), u256(4), u256(0)); | ||||
| 	testSolidityAgainstCpp(0, f, u256(4), u256(5), u256(9)); | ||||
| 	testSolidityAgainstCpp(0, f, u256(4), u256(5), u256(0)); | ||||
| 	testSolidityAgainstCpp(0, f, u256(5), u256(4), u256(0)); | ||||
| 	testSolidityAgainstCpp(0, f, u256(5), u256(4), u256(7)); | ||||
| 	testSolidityAgainstCpp(0, f, u256(4), u256(5), u256(0)); | ||||
| 	testSolidityAgainstCpp(0, f, u256(5), u256(4), u256(0)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(structs) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  struct s1 {\n" | ||||
| 							 "    uint8 x;\n" | ||||
| 							 "    bool y;\n" | ||||
| 							 "  }\n" | ||||
| 							 "  struct s2 {\n" | ||||
| 							 "    uint32 z;\n" | ||||
| 							 "    s1 s1data;\n" | ||||
| 							 "    mapping(uint8 => s2) recursive;\n" | ||||
| 							 "  }\n" | ||||
| 							 "  s2 data;\n" | ||||
| 							 "  function check() returns (bool ok) {\n" | ||||
| 							 "    return data.z == 1 && data.s1data.x == 2 && \n" | ||||
| 							 "        data.s1data.y == true && \n" | ||||
| 							 "        data.recursive[3].recursive[4].z == 5 && \n" | ||||
| 							 "        data.recursive[4].recursive[3].z == 6 && \n" | ||||
| 							 "        data.recursive[0].s1data.y == false && \n" | ||||
| 							 "        data.recursive[4].z == 9;\n" | ||||
| 							 "  }\n" | ||||
| 							 "  function set() {\n" | ||||
| 							 "    data.z = 1;\n" | ||||
| 							 "    data.s1data.x = 2;\n" | ||||
| 							 "    data.s1data.y = true;\n" | ||||
| 							 "    data.recursive[3].recursive[4].z = 5;\n" | ||||
| 							 "    data.recursive[4].recursive[3].z = 6;\n" | ||||
| 							 "    data.recursive[0].s1data.y = false;\n" | ||||
| 							 "    data.recursive[4].z = 9;\n" | ||||
| 							 "  }\n" | ||||
| 							 "}\n"; | ||||
| 	compileAndRun(sourceCode); | ||||
| 	BOOST_CHECK(callContractFunction(0) == bytes({0x00})); | ||||
| 	BOOST_CHECK(callContractFunction(1) == bytes()); | ||||
| 	BOOST_CHECK(callContractFunction(0) == bytes({0x01})); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| } | ||||
| } | ||||
| } // end namespaces
 | ||||
| 
 | ||||
							
								
								
									
										389
									
								
								solidityExpressionCompiler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										389
									
								
								solidityExpressionCompiler.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,389 @@ | ||||
| 
 | ||||
| /*
 | ||||
| 	This file is part of cpp-ethereum. | ||||
| 
 | ||||
| 	cpp-ethereum is free software: you can redistribute it and/or modify | ||||
| 	it under the terms of the GNU General Public License as published by | ||||
| 	the Free Software Foundation, either version 3 of the License, or | ||||
| 	(at your option) any later version. | ||||
| 
 | ||||
| 	cpp-ethereum is distributed in the hope that it will be useful, | ||||
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| 	GNU General Public License for more details. | ||||
| 
 | ||||
| 	You should have received a copy of the GNU General Public License | ||||
| 	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| /**
 | ||||
|  * @author Christian <c@ethdev.com> | ||||
|  * @date 2014 | ||||
|  * Unit tests for the solidity expression compiler. | ||||
|  */ | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include <libdevcore/Log.h> | ||||
| #include <libsolidity/Scanner.h> | ||||
| #include <libsolidity/Parser.h> | ||||
| #include <libsolidity/NameAndTypeResolver.h> | ||||
| #include <libsolidity/CompilerContext.h> | ||||
| #include <libsolidity/ExpressionCompiler.h> | ||||
| #include <libsolidity/AST.h> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| namespace solidity | ||||
| { | ||||
| namespace test | ||||
| { | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| 
 | ||||
| /// Helper class that extracts the first expression in an AST.
 | ||||
| class FirstExpressionExtractor: private ASTVisitor | ||||
| { | ||||
| public: | ||||
| 	FirstExpressionExtractor(ASTNode& _node): m_expression(nullptr) { _node.accept(*this); } | ||||
| 	Expression* getExpression() const { return m_expression; } | ||||
| private: | ||||
| 	virtual bool visit(Expression& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(Assignment& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(UnaryOperation& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(BinaryOperation& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(FunctionCall& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(MemberAccess& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(IndexAccess& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(PrimaryExpression& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(Identifier& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(ElementaryTypeNameExpression& _expression) override { return checkExpression(_expression); } | ||||
| 	virtual bool visit(Literal& _expression) override { return checkExpression(_expression); } | ||||
| 	bool checkExpression(Expression& _expression) | ||||
| 	{ | ||||
| 		if (m_expression == nullptr) | ||||
| 			m_expression = &_expression; | ||||
| 		return false; | ||||
| 	} | ||||
| private: | ||||
| 	Expression* m_expression; | ||||
| }; | ||||
| 
 | ||||
| Declaration const& resolveDeclaration(vector<string> const& _namespacedName, | ||||
| 											  NameAndTypeResolver const& _resolver) | ||||
| { | ||||
| 	Declaration const* declaration = nullptr; | ||||
| 	for (string const& namePart: _namespacedName) | ||||
| 		BOOST_REQUIRE(declaration = _resolver.resolveName(namePart, declaration)); | ||||
| 	BOOST_REQUIRE(declaration); | ||||
| 	return *declaration; | ||||
| } | ||||
| 
 | ||||
| bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _functions = {}, | ||||
| 							 vector<vector<string>> _localVariables = {}) | ||||
| { | ||||
| 	Parser parser; | ||||
| 	ASTPointer<ContractDefinition> contract; | ||||
| 	BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared<Scanner>(CharStream(_sourceCode)))); | ||||
| 	NameAndTypeResolver resolver; | ||||
| 	BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); | ||||
| 	FirstExpressionExtractor extractor(*contract); | ||||
| 	BOOST_REQUIRE(extractor.getExpression() != nullptr); | ||||
| 
 | ||||
| 	CompilerContext context; | ||||
| 	for (vector<string> const& function: _functions) | ||||
| 		context.addFunction(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver))); | ||||
| 	for (vector<string> const& variable: _localVariables) | ||||
| 		context.addVariable(dynamic_cast<VariableDeclaration const&>(resolveDeclaration(variable, resolver))); | ||||
| 
 | ||||
| 	ExpressionCompiler::compileExpression(context, *extractor.getExpression()); | ||||
| 
 | ||||
| 	for (vector<string> const& function: _functions) | ||||
| 		context << context.getFunctionEntryLabel(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver))); | ||||
| 	bytes instructions = context.getAssembledBytecode(); | ||||
| 	// debug
 | ||||
| 	// cout << eth::disassemble(instructions) << endl;
 | ||||
| 	return instructions; | ||||
| } | ||||
| 
 | ||||
| } // end anonymous namespace
 | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(SolidityExpressionCompiler) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(literal_true) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = true; }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(literal_false) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = false; }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x0}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(int_literal) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = 0x12345678901234567890; }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, | ||||
| 													   0x12, 0x34, 0x56, 0x78, 0x90}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(comparison) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = (0x10aa < 0x11aa) != true; }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::LT), | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(short_circuiting) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = true != (4 <= 8 + 10 || 9 != 2); }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0xa, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x8, | ||||
| 					   byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::GT), | ||||
| 					   byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4
 | ||||
| 					   byte(eth::Instruction::DUP1), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x20, | ||||
| 					   byte(eth::Instruction::JUMPI), // short-circuit if it is true
 | ||||
| 					   byte(eth::Instruction::POP), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO), // after this we have 2 != 9
 | ||||
| 					   byte(eth::Instruction::JUMPDEST), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(arithmetics) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = ((((((((9 ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x2, | ||||
| 					   byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x3, | ||||
| 					   byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x4, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x5, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x6, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x7, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x8, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x9, | ||||
| 					   byte(eth::Instruction::XOR), | ||||
| 					   byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::OR), | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::MOD), | ||||
| 					   byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::DIV), | ||||
| 					   byte(eth::Instruction::MUL)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(unary_operators) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { var x = !(~+- 1 == 2); }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x0, | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(unary_inc_dec) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f(uint a) { var x = --a ^ (a-- ^ (++a ^ a++)); }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}}); | ||||
| 
 | ||||
| 	// Stack: a, x
 | ||||
| 	bytes expectation({byte(eth::Instruction::DUP2), | ||||
| 					   byte(eth::Instruction::DUP1), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   // Stack here: a x a (a+1)
 | ||||
| 					   byte(eth::Instruction::SWAP3), | ||||
| 					   byte(eth::Instruction::POP), // first ++
 | ||||
| 					   // Stack here: (a+1) x a
 | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   // Stack here: (a+1) x a (a+2)
 | ||||
| 					   byte(eth::Instruction::SWAP3), | ||||
| 					   byte(eth::Instruction::POP), | ||||
| 					   // Stack here: (a+2) x a
 | ||||
| 					   byte(eth::Instruction::DUP3), // second ++
 | ||||
| 					   byte(eth::Instruction::XOR), | ||||
| 					   // Stack here: (a+2) x a^(a+2)
 | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::DUP1), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::SWAP1), | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   // Stack here: (a+2) x a^(a+2) (a+2) (a+1)
 | ||||
| 					   byte(eth::Instruction::SWAP4), | ||||
| 					   byte(eth::Instruction::POP), // first --
 | ||||
| 					   byte(eth::Instruction::XOR), | ||||
| 					   // Stack here: (a+1) x a^(a+2)^(a+2)
 | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::SWAP1), | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   // Stack here: (a+1) x a^(a+2)^(a+2) a
 | ||||
| 					   byte(eth::Instruction::SWAP3), | ||||
| 					   byte(eth::Instruction::POP), // second ++
 | ||||
| 					   // Stack here: a x a^(a+2)^(a+2)
 | ||||
| 					   byte(eth::Instruction::DUP3), // will change
 | ||||
| 					   byte(eth::Instruction::XOR)}); | ||||
| 					   // Stack here: a x a^(a+2)^(a+2)^a
 | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(assignment) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f(uint a, uint b) { (a += b) * 2; }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}}); | ||||
| 
 | ||||
| 	// Stack: a, b
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::DUP2), | ||||
| 					   byte(eth::Instruction::DUP4), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   // Stack here: a b 2 a+b
 | ||||
| 					   byte(eth::Instruction::SWAP3), | ||||
| 					   byte(eth::Instruction::POP), | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   // Stack here: a+b b 2 a+b
 | ||||
| 					   byte(eth::Instruction::MUL)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(function_call) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f(uint a, uint b) { a += g(a + 1, b) * 2; }\n" | ||||
| 							 "  function g(uint a, uint b) returns (uint c) {}\n" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode, {{"test", "g"}}, | ||||
| 										{{"test", "f", "a"}, {"test", "f", "b"}}); | ||||
| 
 | ||||
| 	// Stack: a, b
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x12, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::DUP5), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   // Stack here: a b 2 <ret label> (a+1)
 | ||||
| 					   byte(eth::Instruction::DUP4), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x19, | ||||
| 					   byte(eth::Instruction::JUMP), | ||||
| 					   byte(eth::Instruction::JUMPDEST), | ||||
| 					   // Stack here: a b 2 g(a+1, b)
 | ||||
| 					   byte(eth::Instruction::MUL), | ||||
| 					   // Stack here: a b g(a+1, b)*2
 | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   // Stack here: a b a+g(a+1, b)*2
 | ||||
| 					   byte(eth::Instruction::SWAP2), | ||||
| 					   byte(eth::Instruction::POP), | ||||
| 					   byte(eth::Instruction::DUP2), | ||||
| 					   byte(eth::Instruction::JUMPDEST)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(negative_literals_8bits) | ||||
| { | ||||
| 	// these all fit in 8 bits
 | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { int8 x = -0 + -1 + -0x01 + -127 + -128; }\n" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) + | ||||
| 					  bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) + | ||||
| 					  bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + | ||||
| 					  bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + | ||||
| 					  bytes({byte(eth::Instruction::PUSH1), 0x00, | ||||
| 							 byte(eth::Instruction::ADD), | ||||
| 							 byte(eth::Instruction::ADD), | ||||
| 							 byte(eth::Instruction::ADD), | ||||
| 							 byte(eth::Instruction::ADD)})); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(negative_literals_16bits) | ||||
| { | ||||
| 	// -1 should need 8 bits, -129 should need 16 bits, how many bits are used is visible
 | ||||
| 	// from the SIGNEXTEND opcodes
 | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 							 "  function f() { int64 x = int64(-1 + -129); }\n" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) + | ||||
| 					  bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + | ||||
| 					  bytes({byte(eth::Instruction::PUSH1), 0x00, | ||||
| 							 byte(eth::Instruction::SIGNEXTEND), | ||||
| 							 byte(eth::Instruction::ADD), | ||||
| 							 byte(eth::Instruction::PUSH1), 0x01, | ||||
| 							 byte(eth::Instruction::SIGNEXTEND)})); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| } | ||||
| } | ||||
| } // end namespaces
 | ||||
| 
 | ||||
							
								
								
									
										214
									
								
								solidityJSONInterfaceTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								solidityJSONInterfaceTest.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,214 @@ | ||||
| /*
 | ||||
| 	This file is part of cpp-ethereum. | ||||
| 
 | ||||
| 	cpp-ethereum is free software: you can redistribute it and/or modify | ||||
| 	it under the terms of the GNU General Public License as published by | ||||
| 	the Free Software Foundation, either version 3 of the License, or | ||||
| 	(at your option) any later version. | ||||
| 
 | ||||
| 	cpp-ethereum is distributed in the hope that it will be useful, | ||||
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| 	GNU General Public License for more details. | ||||
| 
 | ||||
| 	You should have received a copy of the GNU General Public License | ||||
| 	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| /**
 | ||||
|  * @author Marek Kotewicz <marek@ethdev.com> | ||||
|  * @date 2014 | ||||
|  * Unit tests for the solidity compiler JSON Interface output. | ||||
|  */ | ||||
| 
 | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include <libsolidity/CompilerStack.h> | ||||
| #include <jsonrpc/json/json.h> | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| namespace solidity | ||||
| { | ||||
| namespace test | ||||
| { | ||||
| 
 | ||||
| class InterfaceChecker | ||||
| { | ||||
| public: | ||||
| 	bool checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) | ||||
| 	{ | ||||
| 		m_compilerStack.parse(_code); | ||||
| 		std::string generatedInterfaceString = m_compilerStack.getInterface(); | ||||
| 		Json::Value generatedInterface; | ||||
| 		m_reader.parse(generatedInterfaceString, generatedInterface); | ||||
| 		Json::Value expectedInterface; | ||||
| 		m_reader.parse(_expectedInterfaceString, expectedInterface); | ||||
| 		return expectedInterface == generatedInterface; | ||||
| 	} | ||||
| 	 | ||||
| private: | ||||
| 	CompilerStack m_compilerStack; | ||||
| 	Json::Reader m_reader; | ||||
| }; | ||||
| 
 | ||||
| BOOST_FIXTURE_TEST_SUITE(SolidityCompilerJSONInterfaceOutput, InterfaceChecker) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(basic_test) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 	"  function f(uint a) returns(uint d) { return a * 7; }\n" | ||||
| 	"}\n"; | ||||
| 
 | ||||
| 	char const* interface = R"([ | ||||
| 	{ | ||||
| 		"name": "f", | ||||
| 		"inputs": [ | ||||
| 		{ | ||||
| 			"name": "a", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		], | ||||
| 		"outputs": [ | ||||
| 		{ | ||||
| 			"name": "d", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		] | ||||
| 	} | ||||
| 	])"; | ||||
| 
 | ||||
| 	BOOST_CHECK(checkInterface(sourceCode, interface)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(empty_contract) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 	"}\n"; | ||||
| 
 | ||||
| 	char const* interface = "[]"; | ||||
| 
 | ||||
| 	BOOST_CHECK(checkInterface(sourceCode, interface)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(multiple_methods) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 	"  function f(uint a) returns(uint d) { return a * 7; }\n" | ||||
| 	"  function g(uint b) returns(uint e) { return b * 8; }\n" | ||||
| 	"}\n"; | ||||
| 	 | ||||
| 	char const* interface = R"([ | ||||
| 	{ | ||||
| 		"name": "f", | ||||
| 		"inputs": [ | ||||
| 		{ | ||||
| 			"name": "a", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		], | ||||
| 		"outputs": [ | ||||
| 		{ | ||||
| 			"name": "d", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		] | ||||
| 	}, | ||||
| 	{ | ||||
| 		"name": "g", | ||||
| 		"inputs": [ | ||||
| 		{ | ||||
| 			"name": "b", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		], | ||||
| 		"outputs": [ | ||||
| 		{ | ||||
| 			"name": "e", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		] | ||||
| 	} | ||||
| 	])"; | ||||
| 
 | ||||
| 	BOOST_CHECK(checkInterface(sourceCode, interface)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(multiple_params) | ||||
| { | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 	"  function f(uint a, uint b) returns(uint d) { return a + b; }\n" | ||||
| 	"}\n"; | ||||
| 
 | ||||
| 	char const* interface = R"([ | ||||
| 	{ | ||||
| 		"name": "f", | ||||
| 		"inputs": [ | ||||
| 		{ | ||||
| 			"name": "a", | ||||
| 			"type": "uint256" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"name": "b", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		], | ||||
| 		"outputs": [ | ||||
| 		{ | ||||
| 			"name": "d", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		] | ||||
| 	} | ||||
| 	])"; | ||||
| 
 | ||||
| 	BOOST_CHECK(checkInterface(sourceCode, interface)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(multiple_methods_order) | ||||
| { | ||||
| 	// methods are expected to be in alpabetical order
 | ||||
| 	char const* sourceCode = "contract test {\n" | ||||
| 	"  function f(uint a) returns(uint d) { return a * 7; }\n" | ||||
| 	"  function c(uint b) returns(uint e) { return b * 8; }\n" | ||||
| 	"}\n"; | ||||
| 		 | ||||
| 	char const* interface = R"([ | ||||
| 	{ | ||||
| 		"name": "c", | ||||
| 		"inputs": [ | ||||
| 		{ | ||||
| 			"name": "b", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		], | ||||
| 		"outputs": [ | ||||
| 		{ | ||||
| 			"name": "e", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		] | ||||
| 	}, | ||||
| 	{ | ||||
| 		"name": "f", | ||||
| 		"inputs": [ | ||||
| 		{ | ||||
| 			"name": "a", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		], | ||||
| 		"outputs": [ | ||||
| 		{ | ||||
| 			"name": "d", | ||||
| 			"type": "uint256" | ||||
| 		} | ||||
| 		] | ||||
| 	} | ||||
| 	])"; | ||||
| 	 | ||||
| 	BOOST_CHECK(checkInterface(sourceCode, interface)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| } | ||||
| } | ||||
| } | ||||
| @ -121,6 +121,44 @@ BOOST_AUTO_TEST_CASE(reference_to_later_declaration) | ||||
| 	BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(struct_definition_directly_recursive) | ||||
| { | ||||
| 	char const* text = "contract test {\n" | ||||
| 					   "  struct MyStructName {\n" | ||||
| 					   "    address addr;\n" | ||||
| 					   "    MyStructName x;\n" | ||||
| 					   "  }\n" | ||||
| 					   "}\n"; | ||||
| 	BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(struct_definition_indirectly_recursive) | ||||
| { | ||||
| 	char const* text = "contract test {\n" | ||||
| 					   "  struct MyStructName1 {\n" | ||||
| 					   "    address addr;\n" | ||||
| 					   "    uint256 count;\n" | ||||
| 					   "    MyStructName2 x;\n" | ||||
| 					   "  }\n" | ||||
| 					   "  struct MyStructName2 {\n" | ||||
| 					   "    MyStructName1 x;\n" | ||||
| 					   "  }\n" | ||||
| 					   "}\n"; | ||||
| 	BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(struct_definition_recursion_via_mapping) | ||||
| { | ||||
| 	char const* text = "contract test {\n" | ||||
| 					   "  struct MyStructName1 {\n" | ||||
| 					   "    address addr;\n" | ||||
| 					   "    uint256 count;\n" | ||||
| 					   "    mapping(uint => MyStructName1) x;\n" | ||||
| 					   "  }\n" | ||||
| 					   "}\n"; | ||||
| 	BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(type_inference_smoke_test) | ||||
| { | ||||
| 	char const* text = "contract test {\n" | ||||
| @ -162,6 +200,22 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call) | ||||
| 	BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(type_conversion_for_comparison) | ||||
| { | ||||
| 	char const* text = "contract test {\n" | ||||
| 					   "  function f() { uint32(2) == int64(2); }" | ||||
| 					   "}\n"; | ||||
| 	BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid) | ||||
| { | ||||
| 	char const* text = "contract test {\n" | ||||
| 					   "  function f() { int32(2) == uint64(2); }" | ||||
| 					   "}\n"; | ||||
| 	BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion) | ||||
| { | ||||
| 	char const* text = "contract test {\n" | ||||
|  | ||||
| @ -211,7 +211,15 @@ BOOST_AUTO_TEST_CASE(else_if_statement) | ||||
| 	BOOST_CHECK_NO_THROW(parseText(text)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion) | ||||
| { | ||||
| 	char const* text = "contract test {\n" | ||||
| 					   "  function fun() {\n" | ||||
| 					   "    uint64(2);\n" | ||||
| 					   "  }\n" | ||||
| 					   "}\n"; | ||||
| 	BOOST_CHECK_NO_THROW(parseText(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
|  | ||||
| @ -97,6 +97,27 @@ BOOST_AUTO_TEST_CASE(hex_numbers) | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(negative_numbers) | ||||
| { | ||||
| 	Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9;")); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-.2"); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-0x78"); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-7.3"); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9"); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(locations) | ||||
| { | ||||
| 	Scanner scanner(CharStream("function_identifier has ; -0x743/*comment*/\n ident //comment")); | ||||
| @ -109,11 +130,8 @@ BOOST_AUTO_TEST_CASE(locations) | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::SUB); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 27); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 27); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32); | ||||
| 	BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); | ||||
| 	BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45); | ||||
|  | ||||
							
								
								
									
										717
									
								
								stPreCompiledContractsFiller.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										717
									
								
								stPreCompiledContractsFiller.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,717 @@ | ||||
| { | ||||
|     "CallEcrecover0": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0))  }", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallEcrecover0_gas500": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 500 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0))  }", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallEcrecover0_Gas499": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 499 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0))  }", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallEcrecover0_0input": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code": "{ [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) }", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallEcrecover1": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 1) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0))  }", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallEcrecover2": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 33 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 65 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 97 97 32) [[ 0 ]] (MOD (MLOAD 97) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0))  }", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallEcrecover3": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code": "{ (MSTORE 0 0x2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9) (MSTORE 32 27) (MSTORE 64 0x6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a) (MSTORE 96 0x37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0))  }", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallSha256_0": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "0x600160005260206000602060006000600260fff1600051600055", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallSha256_1": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ [[ 2 ]] (CALL 500 2 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallSha256_2": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallSha256_3": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallSha256_4": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallSha256_4_gas99": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 99 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallSha256_5": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 500 2 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "10000000", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallRipemd160_0": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "0x600160005260206000602060006000600360fff1600051600055", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallRipemd160_1": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ [[ 2 ]] (CALL 500 3 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallRipemd160_2": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallRipemd160_3": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallRipemd160_4": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallRipemd160_4_gas99": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 99 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "365224", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
|     "CallRipemd160_5": { | ||||
|          "env" : { | ||||
|              "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|              "currentNumber" : "0", | ||||
|              "currentGasLimit" : "10000000", | ||||
|              "currentDifficulty" : "256", | ||||
|              "currentTimestamp" : 1, | ||||
|              "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|          }, | ||||
|          "pre" : { | ||||
|              "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { | ||||
|                  "balance" : "20000000", | ||||
|                  "nonce" : 0, | ||||
|                  "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 500 3 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", | ||||
|                  "storage": {} | ||||
|              }, | ||||
|             "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "transaction" : { | ||||
|             "nonce" : "0", | ||||
|             "gasPrice" : "1", | ||||
|             "gasLimit" : "10000000", | ||||
|             "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", | ||||
|             "value" : "100000", | ||||
|             "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", | ||||
|             "data" : "" | ||||
|         } | ||||
|      }, | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										1334
									
								
								stSystemOperationsTestFiller.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1334
									
								
								stSystemOperationsTestFiller.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										191
									
								
								state.cpp
									
									
									
									
									
								
							
							
						
						
									
										191
									
								
								state.cpp
									
									
									
									
									
								
							| @ -15,81 +15,150 @@ | ||||
| 	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| /** @file state.cpp
 | ||||
|  * @author Gav Wood <i@gavwood.com> | ||||
|  * @author Christoph Jentzsch <cj@ethdev.com> | ||||
|  * @date 2014 | ||||
|  * State test functions. | ||||
|  */ | ||||
| 
 | ||||
| #include <boost/filesystem/operations.hpp> | ||||
| #include <secp256k1/secp256k1.h> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include "JsonSpiritHeaders.h" | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libethereum/BlockChain.h> | ||||
| #include <libethereum/State.h> | ||||
| #include <libethereum/ExtVM.h> | ||||
| #include <libethereum/Defaults.h> | ||||
| #include <libevm/VM.h> | ||||
| #include "TestHelper.h" | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace json_spirit; | ||||
| using namespace dev; | ||||
| using namespace dev::eth; | ||||
| using namespace dev::eth; | ||||
| 
 | ||||
| int stateTest() | ||||
| namespace dev {  namespace test { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void doStateTests(json_spirit::mValue& v, bool _fillin) | ||||
| { | ||||
| 	cnote << "Testing State..."; | ||||
| 
 | ||||
| 	KeyPair me = sha3("Gav Wood"); | ||||
| 	KeyPair myMiner = sha3("Gav's Miner"); | ||||
| //	KeyPair you = sha3("123");
 | ||||
| 
 | ||||
| 	Defaults::setDBPath(boost::filesystem::temp_directory_path().string()); | ||||
| 
 | ||||
| 	OverlayDB stateDB = State::openDB(); | ||||
| 	BlockChain bc; | ||||
| 	State s(myMiner.address(), stateDB); | ||||
| 
 | ||||
| 	cout << bc; | ||||
| 
 | ||||
| 	// Sync up - this won't do much until we use the last state.
 | ||||
| 	s.sync(bc); | ||||
| 
 | ||||
| 	cout << s; | ||||
| 
 | ||||
| 	// Mine to get some ether!
 | ||||
| 	s.commitToMine(bc); | ||||
| 	while (!s.mine(100).completed) {} | ||||
| 	s.completeMine(); | ||||
| 	bc.attemptImport(s.blockData(), stateDB); | ||||
| 
 | ||||
| 	cout << bc; | ||||
| 
 | ||||
| 	s.sync(bc); | ||||
| 
 | ||||
| 	cout << s; | ||||
| 
 | ||||
| 	// Inject a transaction to transfer funds from miner to me.
 | ||||
| 	bytes tx; | ||||
| 	for (auto& i: v.get_obj()) | ||||
| 	{ | ||||
| 		Transaction t; | ||||
| 		t.nonce = s.transactionsFrom(myMiner.address()); | ||||
| 		t.value = 1000;			// 1e3 wei.
 | ||||
| 		t.type = eth::Transaction::MessageCall; | ||||
| 		t.receiveAddress = me.address(); | ||||
| 		t.sign(myMiner.secret()); | ||||
| 		assert(t.sender() == myMiner.address()); | ||||
| 		tx = t.rlp(); | ||||
| 		cnote << i.first; | ||||
| 		mObject& o = i.second.get_obj(); | ||||
| 
 | ||||
| 		BOOST_REQUIRE(o.count("env") > 0); | ||||
| 		BOOST_REQUIRE(o.count("pre") > 0); | ||||
| 		BOOST_REQUIRE(o.count("transaction") > 0); | ||||
| 
 | ||||
| 		ImportTest importer(o, _fillin); | ||||
| 
 | ||||
| 		State theState = importer.m_statePre; | ||||
| 		bytes tx = importer.m_transaction.rlp(); | ||||
| 		bytes output; | ||||
| 
 | ||||
| 		try | ||||
| 		{ | ||||
| 			theState.execute(tx, &output); | ||||
| 		} | ||||
| 	s.execute(tx); | ||||
| 
 | ||||
| 	cout << s; | ||||
| 
 | ||||
| 	// Mine to get some ether and set in stone.
 | ||||
| 	s.commitToMine(bc); | ||||
| 	while (!s.mine(100).completed) {} | ||||
| 	s.completeMine(); | ||||
| 	bc.attemptImport(s.blockData(), stateDB); | ||||
| 
 | ||||
| 	cout << bc; | ||||
| 
 | ||||
| 	s.sync(bc); | ||||
| 
 | ||||
| 	cout << s; | ||||
| 
 | ||||
| 	return 0; | ||||
| 		catch (Exception const& _e) | ||||
| 		{ | ||||
| 			cnote << "state execution did throw an exception: " << diagnostic_information(_e); | ||||
| 		} | ||||
| 		catch (std::exception const& _e) | ||||
| 		{ | ||||
| 			cnote << "state execution did throw an exception: " << _e.what(); | ||||
| 		} | ||||
| 
 | ||||
| 		if (_fillin) | ||||
| 			importer.exportTest(output, theState); | ||||
| 		else | ||||
| 		{ | ||||
| 			BOOST_REQUIRE(o.count("post") > 0); | ||||
| 			BOOST_REQUIRE(o.count("out") > 0); | ||||
| 
 | ||||
| 			// check output
 | ||||
| 			checkOutput(output, o); | ||||
| 
 | ||||
| 			// check addresses
 | ||||
| 			auto expectedAddrs = importer.m_statePost.addresses(); | ||||
| 			auto resultAddrs = theState.addresses(); | ||||
| 			for (auto& expectedPair : expectedAddrs) | ||||
| 			{ | ||||
| 				auto& expectedAddr = expectedPair.first; | ||||
| 				auto resultAddrIt = resultAddrs.find(expectedAddr); | ||||
| 				if (resultAddrIt == resultAddrs.end()) | ||||
| 					BOOST_ERROR("Missing expected address " << expectedAddr); | ||||
| 				else | ||||
| 				{ | ||||
| 					BOOST_CHECK_MESSAGE(importer.m_statePost.balance(expectedAddr) ==  theState.balance(expectedAddr), expectedAddr << ": incorrect balance " << theState.balance(expectedAddr) << ", expected " << importer.m_statePost.balance(expectedAddr)); | ||||
| 					BOOST_CHECK_MESSAGE(importer.m_statePost.transactionsFrom(expectedAddr) ==  theState.transactionsFrom(expectedAddr), expectedAddr << ": incorrect txCount " << theState.transactionsFrom(expectedAddr) << ", expected " << importer.m_statePost.transactionsFrom(expectedAddr)); | ||||
| 					BOOST_CHECK_MESSAGE(importer.m_statePost.code(expectedAddr) == theState.code(expectedAddr), expectedAddr << ": incorrect code"); | ||||
| 
 | ||||
| 					checkStorage(importer.m_statePost.storage(expectedAddr), theState.storage(expectedAddr), expectedAddr); | ||||
| 				} | ||||
| 			} | ||||
| 			checkAddresses<map<Address, u256> >(expectedAddrs, resultAddrs); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| } }// Namespace Close
 | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(StateTests) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(stExample) | ||||
| { | ||||
| 	dev::test::executeTests("stExample", "/StateTests", dev::test::doStateTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(stSystemOperationsTest) | ||||
| { | ||||
| 	dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(stPreCompiledContracts) | ||||
| { | ||||
| 	dev::test::executeTests("stPreCompiledContracts", "/StateTests", dev::test::doStateTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(stCreateTest) | ||||
| { | ||||
| 	for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) | ||||
| 	{ | ||||
| 		string arg = boost::unit_test::framework::master_test_suite().argv[i]; | ||||
| 		if (arg == "--createtest") | ||||
| 		{ | ||||
| 			if (boost::unit_test::framework::master_test_suite().argc <= i + 2) | ||||
| 			{ | ||||
| 				cnote << "usage: ./testeth --createtest <PathToConstructor> <PathToDestiny>\n"; | ||||
| 				return; | ||||
| 			} | ||||
| 			try | ||||
| 			{ | ||||
| 				cnote << "Populating tests..."; | ||||
| 				json_spirit::mValue v; | ||||
| 				string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1])); | ||||
| 				BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty."); | ||||
| 				json_spirit::read_string(s, v); | ||||
| 				dev::test::doStateTests(v, true); | ||||
| 				writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true))); | ||||
| 			} | ||||
| 			catch (Exception const& _e) | ||||
| 			{ | ||||
| 				BOOST_ERROR("Failed state test with Exception: " << diagnostic_information(_e)); | ||||
| 			} | ||||
| 			catch (std::exception const& _e) | ||||
| 			{ | ||||
| 				BOOST_ERROR("Failed state test with Exception: " << _e.what()); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(userDefinedFileState) | ||||
| { | ||||
| 	dev::test::userDefinedTest("--statetest", dev::test::doStateTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
|  | ||||
							
								
								
									
										90
									
								
								stateOriginal.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								stateOriginal.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| /*
 | ||||
| 	This file is part of cpp-ethereum. | ||||
| 
 | ||||
| 	cpp-ethereum is free software: you can redistribute it and/or modify | ||||
| 	it under the terms of the GNU General Public License as published by | ||||
| 	the Free Software Foundation, either version 3 of the License, or | ||||
| 	(at your option) any later version. | ||||
| 
 | ||||
| 	cpp-ethereum is distributed in the hope that it will be useful, | ||||
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| 	GNU General Public License for more details. | ||||
| 
 | ||||
| 	You should have received a copy of the GNU General Public License | ||||
| 	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| /** @file stateOriginal.cpp
 | ||||
|  * @author Gav Wood <i@gavwood.com> | ||||
|  * @date 2014 | ||||
|  * State test functions. | ||||
|  */ | ||||
| 
 | ||||
| #include <boost/filesystem/operations.hpp> | ||||
| #include <secp256k1/secp256k1.h> | ||||
| #include <libethereum/BlockChain.h> | ||||
| #include <libethereum/State.h> | ||||
| #include <libethereum/Defaults.h> | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| using namespace dev::eth; | ||||
| 
 | ||||
| int stateTest() | ||||
| { | ||||
| 	cnote << "Testing State..."; | ||||
| 
 | ||||
| 	KeyPair me = sha3("Gav Wood"); | ||||
| 	KeyPair myMiner = sha3("Gav's Miner"); | ||||
| //	KeyPair you = sha3("123");
 | ||||
| 
 | ||||
| 	Defaults::setDBPath(boost::filesystem::temp_directory_path().string()); | ||||
| 
 | ||||
| 	OverlayDB stateDB = State::openDB(); | ||||
| 	BlockChain bc; | ||||
| 	State s(myMiner.address(), stateDB); | ||||
| 
 | ||||
| 	cout << bc; | ||||
| 
 | ||||
| 	// Sync up - this won't do much until we use the last state.
 | ||||
| 	s.sync(bc); | ||||
| 
 | ||||
| 	cout << s; | ||||
| 
 | ||||
| 	// Mine to get some ether!
 | ||||
| 	s.commitToMine(bc); | ||||
| 	while (!s.mine(100).completed) {} | ||||
| 	s.completeMine(); | ||||
| 	bc.attemptImport(s.blockData(), stateDB); | ||||
| 
 | ||||
| 	cout << bc; | ||||
| 
 | ||||
| 	s.sync(bc); | ||||
| 
 | ||||
| 	cout << s; | ||||
| 
 | ||||
| 	// Inject a transaction to transfer funds from miner to me.
 | ||||
| 	bytes tx; | ||||
| 	{ | ||||
| 		Transaction t(1000, 0, 0, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); | ||||
| 		assert(t.sender() == myMiner.address()); | ||||
| 		tx = t.rlp(); | ||||
| 	} | ||||
| 	s.execute(tx); | ||||
| 
 | ||||
| 	cout << s; | ||||
| 
 | ||||
| 	// Mine to get some ether and set in stone.
 | ||||
| 	s.commitToMine(bc); | ||||
| 	while (!s.mine(100).completed) {} | ||||
| 	s.completeMine(); | ||||
| 	bc.attemptImport(s.blockData(), stateDB); | ||||
| 
 | ||||
| 	cout << bc; | ||||
| 
 | ||||
| 	s.sync(bc); | ||||
| 
 | ||||
| 	cout << s; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										18
									
								
								trie.cpp
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								trie.cpp
									
									
									
									
									
								
							| @ -28,6 +28,7 @@ | ||||
| #include "TrieHash.h" | ||||
| #include "MemTrie.h" | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include "TestHelper.h" | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| @ -47,18 +48,14 @@ static unsigned fac(unsigned _i) | ||||
| } | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(TrieTests) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(trie_tests) | ||||
| { | ||||
| 	const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); | ||||
| 	string testPath; | ||||
| 	string testPath = test::getTestPath(); | ||||
| 
 | ||||
| 	if (ptestPath == NULL) | ||||
| 	{ | ||||
| 		cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; | ||||
| 		testPath = "../../../tests"; | ||||
| 	} | ||||
| 	else | ||||
| 		testPath = ptestPath; | ||||
| 
 | ||||
| 	testPath += "/TrieTests"; | ||||
| 
 | ||||
| 	cnote << "Testing Trie..."; | ||||
| 	js::mValue v; | ||||
| @ -364,3 +361,6 @@ BOOST_AUTO_TEST_CASE(trieStess) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										496
									
								
								vm.cpp
									
									
									
									
									
								
							
							
						
						
									
										496
									
								
								vm.cpp
									
									
									
									
									
								
							| @ -20,11 +20,9 @@ | ||||
|  * vm test functions. | ||||
|  */ | ||||
| 
 | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/filesystem.hpp> | ||||
| #include "vm.h" | ||||
| 
 | ||||
| //#define FILL_TESTS
 | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace json_spirit; | ||||
| using namespace dev; | ||||
| @ -32,140 +30,24 @@ using namespace dev::eth; | ||||
| using namespace dev::test; | ||||
| 
 | ||||
| FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth):			/// TODO: XXX: remove the default argument & fix.
 | ||||
| 	ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _depth) {} | ||||
| 	ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, _depth) {} | ||||
| 
 | ||||
| h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&) | ||||
| { | ||||
| 	Transaction t; | ||||
| 	t.value = _endowment; | ||||
| 	t.gasPrice = gasPrice; | ||||
| 	t.gas = *_gas; | ||||
| 	t.data = _init.toBytes(); | ||||
| 	Address na = right160(sha3(rlpList(myAddress, get<1>(addresses[myAddress])))); | ||||
| 
 | ||||
| 	m_s.noteSending(myAddress); | ||||
| 	m_ms.internal.resize(m_ms.internal.size() + 1); | ||||
| 	auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); | ||||
| 	if (!m_ms.internal.back().from) | ||||
| 		m_ms.internal.pop_back(); | ||||
| 
 | ||||
| 	if (get<0>(addresses[myAddress]) >= _endowment) | ||||
| 	{ | ||||
| 		get<1>(addresses[myAddress])++; | ||||
| 		get<0>(addresses[ret]) = _endowment; | ||||
| 		get<3>(addresses[ret]) = m_s.code(ret); | ||||
| 	} | ||||
| 
 | ||||
| 	t.type = eth::Transaction::ContractCreation; | ||||
| 	Transaction t(_endowment, gasPrice, *_gas, _init.toBytes()); | ||||
| 	callcreates.push_back(t); | ||||
| 	return ret; | ||||
| 	return na; | ||||
| } | ||||
| 
 | ||||
| bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc const&, Address _myAddressOverride, Address _codeAddressOverride) | ||||
| { | ||||
| 	u256 contractgas = 0xffff; | ||||
| 
 | ||||
| 	Transaction t; | ||||
| 	t.value = _value; | ||||
| 	t.gasPrice = gasPrice; | ||||
| 	t.gas = *_gas; | ||||
| 	t.data = _data.toVector(); | ||||
| 	t.type = eth::Transaction::MessageCall; | ||||
| 	t.receiveAddress = _receiveAddress; | ||||
| 	Transaction t(_value, gasPrice, *_gas, _receiveAddress, _data.toVector()); | ||||
| 	callcreates.push_back(t); | ||||
| 
 | ||||
| 	string codeOf_CodeAddress = _codeAddressOverride ? toHex(get<3>(addresses[_codeAddressOverride])) : toHex(get<3>(addresses[_receiveAddress]) ); | ||||
| 	string sizeOfCode = toHex(toCompactBigEndian((codeOf_CodeAddress.size()+1)/2)); | ||||
| 
 | ||||
| 	string codeOf_SenderAddress = toHex(get<3>(addresses[myAddress]) ); | ||||
| 	string sizeOfSenderCode = toHex(toCompactBigEndian((codeOf_SenderAddress.size()+1)/2)); | ||||
| 
 | ||||
| 	if (codeOf_SenderAddress.size()) | ||||
| 	{ | ||||
| 		// create init code that returns given contract code
 | ||||
| 		string initStringHex = "{ (CODECOPY 0 (- (CODESIZE) 0x" + sizeOfSenderCode + "  ) 0x" + sizeOfSenderCode + ") (RETURN 0 0x" + sizeOfSenderCode +")}"; | ||||
| 		bytes initBytes = compileLLL(initStringHex, true, NULL); | ||||
| 		initBytes += fromHex(codeOf_SenderAddress); | ||||
| 		bytesConstRef init(&initBytes); | ||||
| 
 | ||||
| 		if (!m_s.addresses().count(myAddress)) | ||||
| 		{ | ||||
| 			m_ms.internal.resize(m_ms.internal.size() + 1); | ||||
| 			auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1); | ||||
| 			if (!m_ms.internal.back().from) | ||||
| 				m_ms.internal.pop_back(); | ||||
| 			if (na != myAddress) | ||||
| 			{ | ||||
| 				cnote << "not able to call to : " << myAddress << "\n"; | ||||
| 				cnote << "in FakeExtVM you can only make a call to " << na << "\n"; | ||||
| 				BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(myAddress))); | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (codeOf_CodeAddress.size()) | ||||
| 	{ | ||||
| 		// create init code that returns given contract code
 | ||||
| 		string initStringHex = "{ (CODECOPY 0 (- (CODESIZE) 0x" + sizeOfCode + "  ) 0x" + sizeOfCode + ") (RETURN 0 0x" + sizeOfCode +")}"; | ||||
| 		bytes initBytes = compileLLL(initStringHex, true, NULL); | ||||
| 		initBytes += fromHex(codeOf_CodeAddress); | ||||
| 		bytesConstRef init(&initBytes); | ||||
| 
 | ||||
| 		if (!m_s.addresses().count(_codeAddressOverride ? _codeAddressOverride : _receiveAddress)) | ||||
| 		{ | ||||
| 			m_s.noteSending(myAddress); | ||||
| 			m_ms.internal.resize(m_ms.internal.size() + 1); | ||||
| 			auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); | ||||
| 			if (!m_ms.internal.back().from) | ||||
| 				m_ms.internal.pop_back(); | ||||
| 
 | ||||
| 			if (na != (_codeAddressOverride ? _codeAddressOverride : _receiveAddress)) | ||||
| 			{ | ||||
| 				cnote << "not able to call to : " << (_codeAddressOverride ? _codeAddressOverride : _receiveAddress) << "\n"; | ||||
| 				cnote << "in FakeExtVM you can only make a call to " << na << "\n"; | ||||
| 				BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(_codeAddressOverride ? _codeAddressOverride : _receiveAddress))); | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		m_ms.internal.resize(m_ms.internal.size() + 1); | ||||
| 
 | ||||
| 		auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), Executive::simpleTrace(), 1); | ||||
| 
 | ||||
| 		if (!m_ms.internal.back().from) | ||||
| 			m_ms.internal.pop_back(); | ||||
| 
 | ||||
| 		// get correct balances, (also for sucicides in the call function)
 | ||||
| 		for (auto const& f: addresses) | ||||
| 		{ | ||||
| 			if (m_s.addressInUse(f.first)) | ||||
| 				get<0>(addresses[f.first]) = m_s.balance(f.first); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!ret) | ||||
| 			return false; | ||||
| 
 | ||||
| 		// TODO: @CJentzsch refund SSTORE stuff.
 | ||||
| 		// TODO: @CJentzsch test logs.
 | ||||
| 
 | ||||
| 		// do suicides
 | ||||
| 		for (auto const& f: sub.suicides) | ||||
| 			addresses.erase(f); | ||||
| 
 | ||||
| 		// get storage
 | ||||
| 		if ((get<0>(addresses[myAddress]) >= _value) && (sub.suicides.find(_receiveAddress) == sub.suicides.end())) | ||||
| 		{ | ||||
| 			for (auto const& j: m_s.storage(_receiveAddress)) | ||||
| 			{ | ||||
| 				u256 adr(j.first); | ||||
| 				if ((j.second != 0) ) | ||||
| 					get<2>(addresses[_receiveAddress])[adr] = j.second; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 		addresses.erase(_receiveAddress); // for the sake of comparison
 | ||||
| 
 | ||||
| 	(void)_out; | ||||
| 	(void)_myAddressOverride; | ||||
| 	(void)_codeAddressOverride; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| @ -198,45 +80,13 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map<u256, u256> const& _st | ||||
| 	set(myAddress, _myBalance, _myNonce, _storage, get<3>(addresses[myAddress])); | ||||
| } | ||||
| 
 | ||||
| u256 FakeExtVM::toInt(mValue const& _v) | ||||
| { | ||||
| 	switch (_v.type()) | ||||
| 	{ | ||||
| 	case str_type: return u256(_v.get_str()); | ||||
| 	case int_type: return (u256)_v.get_uint64(); | ||||
| 	case bool_type: return (u256)(uint64_t)_v.get_bool(); | ||||
| 	case real_type: return (u256)(uint64_t)_v.get_real(); | ||||
| 	default: cwarn << "Bad type for scalar: " << _v.type(); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| byte FakeExtVM::toByte(mValue const& _v) | ||||
| { | ||||
| 	switch (_v.type()) | ||||
| 	{ | ||||
| 	case str_type: return (byte)stoi(_v.get_str()); | ||||
| 	case int_type: return (byte)_v.get_uint64(); | ||||
| 	case bool_type: return (byte)_v.get_bool(); | ||||
| 	case real_type: return (byte)_v.get_real(); | ||||
| 	default: cwarn << "Bad type for scalar: " << _v.type(); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void FakeExtVM::push(mObject& o, string const& _n, u256 _v) | ||||
| { | ||||
| 	//		if (_v < (u256)1 << 64)
 | ||||
| 	//			o[_n] = (uint64_t)_v;
 | ||||
| 	//		else
 | ||||
| 	o[_n] = toString(_v); | ||||
| } | ||||
| 
 | ||||
| void FakeExtVM::push(mArray& a, u256 _v) | ||||
| { | ||||
| 	//		if (_v < (u256)1 << 64)
 | ||||
| 	//			a.push_back((uint64_t)_v);
 | ||||
| 	//		else
 | ||||
| 	a.push_back(toString(_v)); | ||||
| } | ||||
| 
 | ||||
| @ -309,17 +159,7 @@ void FakeExtVM::importState(mObject& _object) | ||||
| 		for (auto const& j: o["storage"].get_obj()) | ||||
| 			get<2>(a)[toInt(j.first)] = toInt(j.second); | ||||
| 
 | ||||
| 		if (o["code"].type() == str_type) | ||||
| 			if (o["code"].get_str().find_first_of("0x") != 0) | ||||
| 				get<3>(a) = compileLLL(o["code"].get_str(), false); | ||||
| 			else | ||||
| 				get<3>(a) = fromHex(o["code"].get_str().substr(2)); | ||||
| 		else | ||||
| 		{ | ||||
| 			get<3>(a).clear(); | ||||
| 			for (auto const& j: o["code"].get_array()) | ||||
| 				get<3>(a).push_back(toByte(j)); | ||||
| 		} | ||||
| 		get<3>(a) = importCode(o); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -356,27 +196,15 @@ void FakeExtVM::importExec(mObject& _o) | ||||
| 	gas = toInt(_o["gas"]); | ||||
| 
 | ||||
| 	thisTxCode.clear(); | ||||
| 	code = &thisTxCode; | ||||
| 	if (_o["code"].type() == str_type) | ||||
| 		if (_o["code"].get_str().find_first_of("0x") == 0) | ||||
| 			thisTxCode = fromHex(_o["code"].get_str().substr(2)); | ||||
| 		else | ||||
| 			thisTxCode = compileLLL(_o["code"].get_str()); | ||||
| 	else if (_o["code"].type() == array_type) | ||||
| 		for (auto const& j: _o["code"].get_array()) | ||||
| 			thisTxCode.push_back(toByte(j)); | ||||
| 	else | ||||
| 		code.reset(); | ||||
| 	code = thisTxCode; | ||||
| 
 | ||||
| 	thisTxCode = importCode(_o); | ||||
| 	if (_o["code"].type() != str_type && _o["code"].type() != array_type) | ||||
| 		code.clear(); | ||||
| 
 | ||||
| 	thisTxData.clear(); | ||||
| 	if (_o["data"].type() == str_type) | ||||
| 		if (_o["data"].get_str().find_first_of("0x") == 0) | ||||
| 			thisTxData = fromHex(_o["data"].get_str().substr(2)); | ||||
| 		else | ||||
| 			thisTxData = fromHex(_o["data"].get_str()); | ||||
| 	else | ||||
| 		for (auto const& j: _o["data"].get_array()) | ||||
| 			thisTxData.push_back(toByte(j)); | ||||
| 	thisTxData = importData(_o); | ||||
| 
 | ||||
| 	data = &thisTxData; | ||||
| } | ||||
| 
 | ||||
| @ -386,10 +214,10 @@ mArray FakeExtVM::exportCallCreates() | ||||
| 	for (Transaction const& tx: callcreates) | ||||
| 	{ | ||||
| 		mObject o; | ||||
| 		o["destination"] = tx.type == Transaction::ContractCreation ? "" : toString(tx.receiveAddress); | ||||
| 		push(o, "gasLimit", tx.gas); | ||||
| 		push(o, "value", tx.value); | ||||
| 		o["data"] = "0x" + toHex(tx.data); | ||||
| 		o["destination"] = tx.isCreation() ? "" : toString(tx.receiveAddress()); | ||||
| 		push(o, "gasLimit", tx.gas()); | ||||
| 		push(o, "value", tx.value()); | ||||
| 		o["data"] = "0x" + toHex(tx.data()); | ||||
| 		ret.push_back(o); | ||||
| 	} | ||||
| 	return ret; | ||||
| @ -404,19 +232,9 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) | ||||
| 		BOOST_REQUIRE(tx.count("value") > 0); | ||||
| 		BOOST_REQUIRE(tx.count("destination") > 0); | ||||
| 		BOOST_REQUIRE(tx.count("gasLimit") > 0); | ||||
| 		Transaction t; | ||||
| 		t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall; | ||||
| 		t.receiveAddress = Address(tx["destination"].get_str()); | ||||
| 		t.value = toInt(tx["value"]); | ||||
| 		t.gas = toInt(tx["gasLimit"]); | ||||
| 		if (tx["data"].type() == str_type) | ||||
| 			if (tx["data"].get_str().find_first_of("0x") == 0) | ||||
| 				t.data = fromHex(tx["data"].get_str().substr(2)); | ||||
| 			else | ||||
| 				t.data = fromHex(tx["data"].get_str()); | ||||
| 		else | ||||
| 			for (auto const& j: tx["data"].get_array()) | ||||
| 				t.data.push_back(toByte(j)); | ||||
| 		Transaction t = tx["destination"].get_str().empty() ? | ||||
| 			Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), data.toBytes()) : | ||||
| 			Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), Address(tx["destination"].get_str()), data.toBytes()); | ||||
| 		callcreates.push_back(t); | ||||
| 	} | ||||
| } | ||||
| @ -435,9 +253,6 @@ eth::OnOpFunc FakeExtVM::simpleTrace() | ||||
| 		o << "    MEMORY" << std::endl << memDump(vm.memory()); | ||||
| 		o << "    STORAGE" << std::endl; | ||||
| 
 | ||||
| 		for (auto const& i: ext.state().storage(ext.myAddress)) | ||||
| 			o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; | ||||
| 
 | ||||
| 		for (auto const& i: std::get<2>(ext.addresses.find(ext.myAddress)->second)) | ||||
| 			o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; | ||||
| 
 | ||||
| @ -454,74 +269,9 @@ eth::OnOpFunc FakeExtVM::simpleTrace() | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| // THIS IS BROKEN AND NEEDS TO BE REMOVED.
 | ||||
| h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) | ||||
| { | ||||
| 	(void)o_sub; | ||||
| 
 | ||||
| 	if (!_origin) | ||||
| 		_origin = _sender; | ||||
| 
 | ||||
| 	if (o_ms) | ||||
| 	{ | ||||
| 		o_ms->from = _sender; | ||||
| 		o_ms->to = Address(); | ||||
| 		o_ms->value = _endowment; | ||||
| 		o_ms->input = _code.toBytes(); | ||||
| 	} | ||||
| 
 | ||||
| 	// Set up new account...
 | ||||
| 	m_cache[_newAddress] = Account(0, balance(_newAddress) + _endowment, h256(), h256()); | ||||
| 
 | ||||
| 	// Execute init code.
 | ||||
| 	VM vm(*_gas); | ||||
| 	ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level); | ||||
| 	bool revert = false; | ||||
| 	bytesConstRef out; | ||||
| 
 | ||||
| 	try | ||||
| 	{ | ||||
| 		out = vm.go(evm, _onOp); | ||||
| 		if (o_ms) | ||||
| 			o_ms->output = out.toBytes(); | ||||
| 		// TODO: deal with evm.sub
 | ||||
| 	} | ||||
| 	catch (OutOfGas const& /*_e*/) | ||||
| 	{ | ||||
| 		clog(StateChat) << "Out of Gas! Reverting."; | ||||
| 		revert = true; | ||||
| 	} | ||||
| 	catch (VMException const& _e) | ||||
| 	{ | ||||
| 		clog(StateChat) << "VM Exception: " << diagnostic_information(_e); | ||||
| 	} | ||||
| 	catch (Exception const& _e) | ||||
| 	{ | ||||
| 		clog(StateChat) << "Exception in VM: " << diagnostic_information(_e); | ||||
| 	} | ||||
| 	catch (std::exception const& _e) | ||||
| 	{ | ||||
| 		clog(StateChat) << "std::exception in VM: " << _e.what(); | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: CHECK: IS THIS CORRECT?! (esp. given account created prior to revertion init.)
 | ||||
| 
 | ||||
| 	// Write state out only in the case of a non-out-of-gas transaction.
 | ||||
| 	if (revert) | ||||
| 		evm.revert(); | ||||
| 
 | ||||
| 	// Set code.
 | ||||
| 	if (addressInUse(_newAddress)) | ||||
| 		m_cache[_newAddress].setCode(out); | ||||
| 
 | ||||
| 	*_gas = vm.gas(); | ||||
| 
 | ||||
| 	return _newAddress; | ||||
| } | ||||
| 
 | ||||
| namespace dev { namespace test { | ||||
| 
 | ||||
| void doTests(json_spirit::mValue& v, bool _fillin) | ||||
| void doVMTests(json_spirit::mValue& v, bool _fillin) | ||||
| { | ||||
| 	for (auto& i: v.get_obj()) | ||||
| 	{ | ||||
| @ -540,27 +290,35 @@ void doTests(json_spirit::mValue& v, bool _fillin) | ||||
| 			o["pre"] = mValue(fev.exportState()); | ||||
| 
 | ||||
| 		fev.importExec(o["exec"].get_obj()); | ||||
| 		if (!fev.code) | ||||
| 		if (fev.code.empty()) | ||||
| 		{ | ||||
| 			fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); | ||||
| 			fev.code = &fev.thisTxCode; | ||||
| 			fev.code = fev.thisTxCode; | ||||
| 		} | ||||
| 
 | ||||
| 		bytes output; | ||||
| 		VM vm(fev.gas); | ||||
| 
 | ||||
| 		u256 gas; | ||||
| 		try | ||||
| 		{ | ||||
| 			output = vm.go(fev, fev.simpleTrace()).toVector(); | ||||
| 			gas = vm.gas(); | ||||
| 		} | ||||
| 		catch (VMException const& _e) | ||||
| 		{ | ||||
| 			cnote << "VM did throw an exception: " << diagnostic_information(_e); | ||||
| 			gas = 0; | ||||
| 		} | ||||
| 		catch (Exception const& _e) | ||||
| 		{ | ||||
| 			cnote << "VM did throw an exception: " << diagnostic_information(_e); | ||||
| 			//BOOST_ERROR("Failed VM Test with Exception: " << e.what());
 | ||||
| 			BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); | ||||
| 		} | ||||
| 		catch (std::exception const& _e) | ||||
| 		{ | ||||
| 			cnote << "VM did throw an exception: " << _e.what(); | ||||
| 			//BOOST_ERROR("Failed VM Test with Exception: " << e.what());
 | ||||
| 			BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); | ||||
| 		} | ||||
| 
 | ||||
| 		// delete null entries in storage for the sake of comparison
 | ||||
| @ -587,7 +345,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) | ||||
| 			o["post"] = mValue(fev.exportState()); | ||||
| 			o["callcreates"] = fev.exportCallCreates(); | ||||
| 			o["out"] = "0x" + toHex(output); | ||||
| 			fev.push(o, "gas", vm.gas()); | ||||
| 			fev.push(o, "gas", gas); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| @ -599,19 +357,10 @@ void doTests(json_spirit::mValue& v, bool _fillin) | ||||
| 			dev::test::FakeExtVM test; | ||||
| 			test.importState(o["post"].get_obj()); | ||||
| 			test.importCallCreates(o["callcreates"].get_array()); | ||||
| 			int i = 0; | ||||
| 			if (o["out"].type() == array_type) | ||||
| 				for (auto const& d: o["out"].get_array()) | ||||
| 				{ | ||||
| 					BOOST_CHECK_MESSAGE(output[i] == test.toInt(d), "Output byte [" << i << "] different!"); | ||||
| 					++i; | ||||
| 				} | ||||
| 			else if (o["out"].get_str().find("0x") == 0) | ||||
| 				BOOST_CHECK(output == fromHex(o["out"].get_str().substr(2))); | ||||
| 			else | ||||
| 				BOOST_CHECK(output == fromHex(o["out"].get_str())); | ||||
| 
 | ||||
| 			BOOST_CHECK_EQUAL(test.toInt(o["gas"]), vm.gas()); | ||||
| 			checkOutput(output, o); | ||||
| 
 | ||||
| 			BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); | ||||
| 
 | ||||
| 			auto& expectedAddrs = test.addresses; | ||||
| 			auto& resultAddrs = fev.addresses; | ||||
| @ -629,189 +378,96 @@ void doTests(json_spirit::mValue& v, bool _fillin) | ||||
| 					BOOST_CHECK_MESSAGE(std::get<1>(expectedState) == std::get<1>(resultState), expectedAddr << ": incorrect txCount " << std::get<1>(resultState) << ", expected " << std::get<1>(expectedState)); | ||||
| 					BOOST_CHECK_MESSAGE(std::get<3>(expectedState) == std::get<3>(resultState), expectedAddr << ": incorrect code"); | ||||
| 
 | ||||
| 					auto&& expectedStore = std::get<2>(expectedState); | ||||
| 					auto&& resultStore = std::get<2>(resultState); | ||||
| 
 | ||||
| 					for (auto&& expectedStorePair : expectedStore) | ||||
| 					{ | ||||
| 						auto& expectedStoreKey = expectedStorePair.first; | ||||
| 						auto resultStoreIt = resultStore.find(expectedStoreKey); | ||||
| 						if (resultStoreIt == resultStore.end()) | ||||
| 							BOOST_ERROR(expectedAddr << ": missing store key " << expectedStoreKey); | ||||
| 						else | ||||
| 						{ | ||||
| 							auto& expectedStoreValue = expectedStorePair.second; | ||||
| 							auto& resultStoreValue = resultStoreIt->second; | ||||
| 							BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); | ||||
| 						} | ||||
| 					} | ||||
| 					checkStorage(std::get<2>(expectedState), std::get<2>(resultState), expectedAddr); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			BOOST_CHECK(test.addresses == fev.addresses);	// Just to make sure nothing missed
 | ||||
| 			checkAddresses<std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes> > >(test.addresses, fev.addresses); | ||||
| 			BOOST_CHECK(test.callcreates == fev.callcreates); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*string makeTestCase()
 | ||||
| { | ||||
| 	json_spirit::mObject o; | ||||
| 
 | ||||
| 	VM vm; | ||||
| 	BlockInfo pb; | ||||
| 	pb.hash = sha3("previousHash"); | ||||
| 	pb.nonce = sha3("previousNonce"); | ||||
| 	BlockInfo cb = pb; | ||||
| 	cb.difficulty = 256; | ||||
| 	cb.timestamp = 1; | ||||
| 	cb.coinbaseAddress = toAddress(sha3("coinbase")); | ||||
| 	FakeExtVM fev(pb, cb, 0); | ||||
| 	bytes init; | ||||
| 	fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))", false, init), map<u256, u256>()); | ||||
| 	o["env"] = fev.exportEnv(); | ||||
| 	o["pre"] = fev.exportState(); | ||||
| 	fev.setTransaction(toAddress(sha3("sender")), ether, finney, bytes()); | ||||
| 	mArray execs; | ||||
| 	execs.push_back(fev.exportExec()); | ||||
| 	o["exec"] = execs; | ||||
| 	vm.go(fev); | ||||
| 	o["post"] = fev.exportState(); | ||||
| 	o["txs"] = fev.exportTxs(); | ||||
| 
 | ||||
| 	return json_spirit::write_string(json_spirit::mValue(o), true); | ||||
| }*/ | ||||
| 
 | ||||
| void executeTests(const string& _name) | ||||
| { | ||||
| 	const char* ptestPath = getenv("ETHEREUM_TEST_PATH"); | ||||
| 	string testPath; | ||||
| 
 | ||||
| 	if (ptestPath == NULL) | ||||
| 	{ | ||||
| 		cnote << " could not find environment variable ETHEREUM_TEST_PATH \n"; | ||||
| 		testPath = "../../../tests"; | ||||
| 	} | ||||
| 	else | ||||
| 		testPath = ptestPath; | ||||
| 
 | ||||
| 	testPath += "/vmtests"; | ||||
| 
 | ||||
| #ifdef FILL_TESTS | ||||
| 	try | ||||
| 	{ | ||||
| 		cnote << "Populating VM tests..."; | ||||
| 		json_spirit::mValue v; | ||||
| 		boost::filesystem::path p(__FILE__); | ||||
| 		boost::filesystem::path dir = p.parent_path(); | ||||
| 		string s = asString(contents(dir.string() + "/" + _name + "Filler.json")); | ||||
| 		BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + "Filler.json is empty."); | ||||
| 		json_spirit::read_string(s, v); | ||||
| 		dev::test::doTests(v, true); | ||||
| 		writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); | ||||
| 	} | ||||
| 	catch (Exception const& _e) | ||||
| 	{ | ||||
| 		BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); | ||||
| 	} | ||||
| 	catch (std::exception const& _e) | ||||
| 	{ | ||||
| 		BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	try | ||||
| 	{ | ||||
| 		cnote << "Testing VM..." << _name; | ||||
| 		json_spirit::mValue v; | ||||
| 		string s = asString(contents(testPath + "/" + _name + ".json")); | ||||
| 		BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); | ||||
| 		json_spirit::read_string(s, v); | ||||
| 		dev::test::doTests(v, false); | ||||
| 	} | ||||
| 	catch (Exception const& _e) | ||||
| 	{ | ||||
| 		BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); | ||||
| 	} | ||||
| 	catch (std::exception const& _e) | ||||
| 	{ | ||||
| 		BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| } } // Namespace Close
 | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(VMTests) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vm_tests) | ||||
| { | ||||
| 	dev::test::executeTests("vmtests"); | ||||
| 	dev::test::executeTests("vmtests", "/VMTests", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vmArithmeticTest) | ||||
| { | ||||
| 	dev::test::executeTests("vmArithmeticTest"); | ||||
| 	dev::test::executeTests("vmArithmeticTest", "/VMTests", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vmBitwiseLogicOperationTest) | ||||
| { | ||||
| 	dev::test::executeTests("vmBitwiseLogicOperationTest"); | ||||
| 	dev::test::executeTests("vmBitwiseLogicOperationTest", "/VMTests", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vmSha3Test) | ||||
| { | ||||
| 	dev::test::executeTests("vmSha3Test"); | ||||
| 	dev::test::executeTests("vmSha3Test", "/VMTests", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vmEnvironmentalInfoTest) | ||||
| { | ||||
| 	dev::test::executeTests("vmEnvironmentalInfoTest"); | ||||
| 	dev::test::executeTests("vmEnvironmentalInfoTest", "/VMTests", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vmBlockInfoTest) | ||||
| { | ||||
| 	dev::test::executeTests("vmBlockInfoTest"); | ||||
| 	dev::test::executeTests("vmBlockInfoTest", "/VMTests", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vmIOandFlowOperationsTest) | ||||
| { | ||||
| 	dev::test::executeTests("vmIOandFlowOperationsTest"); | ||||
| 	dev::test::executeTests("vmIOandFlowOperationsTest", "/VMTests", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vmPushDupSwapTest) | ||||
| { | ||||
| 	dev::test::executeTests("vmPushDupSwapTest"); | ||||
| 	dev::test::executeTests("vmPushDupSwapTest", "/VMTests", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) | ||||
| BOOST_AUTO_TEST_CASE(vmRandom) | ||||
| { | ||||
| 	dev::test::executeTests("vmSystemOperationsTest"); | ||||
| } | ||||
| 	string testPath = getTestPath(); | ||||
| 	testPath += "/VMTests/RandomTests"; | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(userDefinedFile) | ||||
| { | ||||
| 	vector<boost::filesystem::path> testFiles; | ||||
| 	boost::filesystem::directory_iterator iterator(testPath); | ||||
| 	for(; iterator != boost::filesystem::directory_iterator(); ++iterator) | ||||
| 		if (boost::filesystem::is_regular_file(iterator->path()) && iterator->path().extension() == ".json") | ||||
| 			testFiles.push_back(iterator->path()); | ||||
| 
 | ||||
| 	if (boost::unit_test::framework::master_test_suite().argc == 2) | ||||
| 	for (auto& path: testFiles) | ||||
| 	{ | ||||
| 		string filename = boost::unit_test::framework::master_test_suite().argv[1]; | ||||
| 		int currentVerbosity = g_logVerbosity; | ||||
| 		g_logVerbosity = 12; | ||||
| 		try | ||||
| 		{ | ||||
| 			cnote << "Testing VM..." << "user defined test"; | ||||
| 			cnote << "Testing ..." << path.filename(); | ||||
| 			json_spirit::mValue v; | ||||
| 			string s = asString(contents(filename)); | ||||
| 			BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); | ||||
| 			string s = asString(dev::contents(path.string())); | ||||
| 			BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); | ||||
| 			json_spirit::read_string(s, v); | ||||
| 			dev::test::doTests(v, false); | ||||
| 			doVMTests(v, false); | ||||
| 		} | ||||
| 		catch (Exception const& _e) | ||||
| 		{ | ||||
| 			BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); | ||||
| 			BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); | ||||
| 		} | ||||
| 		catch (std::exception const& _e) | ||||
| 		{ | ||||
| 			BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); | ||||
| 		} | ||||
| 		g_logVerbosity = currentVerbosity; | ||||
| 			BOOST_ERROR("Failed test with Exception: " << _e.what()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(userDefinedFileVM) | ||||
| { | ||||
| 	dev::test::userDefinedTest("--vmtest", dev::test::doVMTests); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
|  | ||||
							
								
								
									
										14
									
								
								vm.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								vm.h
									
									
									
									
									
								
							| @ -29,25 +29,19 @@ along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>. | ||||
| #include "JsonSpiritHeaders.h" | ||||
| #include <libdevcore/Log.h> | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libevmface/Instruction.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevm/ExtVMFace.h> | ||||
| #include <libevm/VM.h> | ||||
| #include <liblll/Compiler.h> | ||||
| #include <libethereum/Transaction.h> | ||||
| #include <libethereum/ExtVM.h> | ||||
| #include <libethereum/State.h> | ||||
| #include "TestHelper.h" | ||||
| 
 | ||||
| namespace dev { namespace test { | ||||
| 
 | ||||
| struct FakeExtVMFailure : virtual Exception {}; | ||||
| 
 | ||||
| class FakeState: public eth::State | ||||
| { | ||||
| public: | ||||
| 	/// Execute a contract-creation transaction.
 | ||||
| 	h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, eth::SubState* o_sub = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0); | ||||
| }; | ||||
| 
 | ||||
| class FakeExtVM: public eth::ExtVMFace | ||||
| { | ||||
| public: | ||||
| @ -67,8 +61,6 @@ public: | ||||
| 	void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code); | ||||
| 	void set(Address _a, u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage, bytes const& _code); | ||||
| 	void reset(u256 _myBalance, u256 _myNonce, std::map<u256, u256> const& _storage); | ||||
| 	u256 toInt(json_spirit::mValue const& _v); | ||||
| 	byte toByte(json_spirit::mValue const& _v); | ||||
| 	void push(json_spirit::mObject& o, std::string const& _n, u256 _v); | ||||
| 	void push(json_spirit::mArray& a, u256 _v); | ||||
| 	u256 doPosts(); | ||||
| @ -82,7 +74,6 @@ public: | ||||
| 	void importCallCreates(json_spirit::mArray& _callcreates); | ||||
| 
 | ||||
| 	eth::OnOpFunc simpleTrace(); | ||||
| 	FakeState state() const { return m_s; } | ||||
| 
 | ||||
| 	std::map<Address, std::tuple<u256, u256, std::map<u256, u256>, bytes>> addresses; | ||||
| 	eth::Transactions callcreates; | ||||
| @ -91,7 +82,6 @@ public: | ||||
| 	u256 gas; | ||||
| 
 | ||||
| private: | ||||
| 	FakeState m_s; | ||||
| 	eth::Manifest m_ms; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -12,7 +12,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x6002600360045057", | ||||
|             "code" : "0x6002600360045055", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -40,7 +40,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x5060026003600457", | ||||
|             "code" : "0x5060026003600455", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -68,7 +68,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x600260035157", | ||||
|             "code" : "0x600260035155", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -96,7 +96,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x600260035257", | ||||
|             "code" : "0x600260035255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -488,7 +488,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x6023600058", | ||||
|             "code" : "0x600056", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -516,7 +516,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x60236007586001600257", | ||||
|             "code" : "0x60236007566001600255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -543,7 +543,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x602360085860015d600257", | ||||
|             "code" : "0x602360075660015b600255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -571,7 +571,91 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x602360075860015d600257", | ||||
|             "code" : "0x602360085660015b600255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
|         "exec" : { | ||||
|             "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", | ||||
|             "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "value" : "1000000000000000000", | ||||
|             "data" : "", | ||||
|             "gasPrice" : "100000000000000", | ||||
|             "gas" : "10000" | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     "jump0_jumpdest2": { | ||||
|         "env" : { | ||||
|         "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|         "currentNumber" : "0", | ||||
|         "currentGasLimit" : "1000000", | ||||
|         "currentDifficulty" : "256", | ||||
|         "currentTimestamp" : 1, | ||||
|         "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|         }, | ||||
|         "pre" : { | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x6023600a6008505660015b600255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
|         "exec" : { | ||||
|             "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", | ||||
|             "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "value" : "1000000000000000000", | ||||
|             "data" : "", | ||||
|             "gasPrice" : "100000000000000", | ||||
|             "gas" : "10000" | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     "jump0_jumpdest3": { | ||||
|         "env" : { | ||||
|         "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|         "currentNumber" : "0", | ||||
|         "currentGasLimit" : "1000000", | ||||
|         "currentDifficulty" : "256", | ||||
|         "currentTimestamp" : 1, | ||||
|         "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|         }, | ||||
|         "pre" : { | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x6023600b6008505660015b600255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
|         "exec" : { | ||||
|             "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", | ||||
|             "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "value" : "1000000000000000000", | ||||
|             "data" : "", | ||||
|             "gasPrice" : "100000000000000", | ||||
|             "gas" : "10000" | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     "jump1": { | ||||
|         "env" : { | ||||
|         "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|         "currentNumber" : "0", | ||||
|         "currentGasLimit" : "1000000", | ||||
|         "currentDifficulty" : "256", | ||||
|         "currentTimestamp" : 1, | ||||
|         "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|         }, | ||||
|         "pre" : { | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x620fffff620fffff0156", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -599,7 +683,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x602360016009596001600257", | ||||
|             "code" : "0x602360016009576001600255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -627,7 +711,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x60236001600a5960015d600257", | ||||
|             "code" : "0x60236001600a5760015b600255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -655,7 +739,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x602360006009596001600257", | ||||
|             "code" : "0x602360006009576001600255", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
| @ -683,7 +767,7 @@ | ||||
|         "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|             "balance" : "1000000000000000000", | ||||
|             "nonce" : 0, | ||||
|             "code" : "0x60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff596002600357", | ||||
|             "code" : "0x60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff576002600355", | ||||
|             "storage": {} | ||||
|         } | ||||
|         }, | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x60ff600357", | ||||
|                 "code" : "0x60ff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -68,7 +68,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x61eeff600357", | ||||
|                 "code" : "0x61eeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -96,7 +96,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x62ddeeff600357", | ||||
|                 "code" : "0x62ddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -124,7 +124,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x63ccddeeff600357", | ||||
|                 "code" : "0x63ccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -152,7 +152,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x64bbccddeeff600357", | ||||
|                 "code" : "0x64bbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -180,7 +180,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x65aabbccddeeff600357", | ||||
|                 "code" : "0x65aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -208,7 +208,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6699aabbccddeeff600357", | ||||
|                 "code" : "0x6699aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -236,7 +236,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x678899aabbccddeeff600357", | ||||
|                 "code" : "0x678899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -264,7 +264,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x68778899aabbccddeeff600357", | ||||
|                 "code" : "0x68778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -292,7 +292,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6966778899aabbccddeeff600357", | ||||
|                 "code" : "0x6966778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -320,7 +320,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6a5566778899aabbccddeeff600357", | ||||
|                 "code" : "0x6a5566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -348,7 +348,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6b445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x6b445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -376,7 +376,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6c33445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x6c33445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -404,7 +404,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6d2233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x6d2233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -432,7 +432,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6e112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x6e112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -460,7 +460,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6f10112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x6f10112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -488,7 +488,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x70ff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x70ff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -516,7 +516,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x71eeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x71eeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -544,7 +544,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x72ddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x72ddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -572,7 +572,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x73ccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x73ccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -600,7 +600,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x74bbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x74bbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -628,7 +628,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x75aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x75aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -656,7 +656,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7699aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7699aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -684,7 +684,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -712,7 +712,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x78778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x78778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -740,7 +740,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7966778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7966778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -769,7 +769,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7a5566778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7a5566778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -797,7 +797,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7b445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7b445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -825,7 +825,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7c33445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7c33445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -853,7 +853,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7d2233445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7d2233445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -881,7 +881,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7e112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7e112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -909,7 +909,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -937,7 +937,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7fff10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600357", | ||||
|                 "code" : "0x7fff10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -965,7 +965,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff80600357", | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff80600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -993,7 +993,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff81600357", | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff81600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1021,7 +1021,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6002600181600357", | ||||
|                 "code" : "0x6002600181600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1049,7 +1049,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x60036002600182600357", | ||||
|                 "code" : "0x60036002600182600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1077,7 +1077,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600460036002600183600357", | ||||
|                 "code" : "0x600460036002600183600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1105,7 +1105,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6005600460036002600184600357", | ||||
|                 "code" : "0x6005600460036002600184600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1133,7 +1133,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x60066005600460036002600185600357", | ||||
|                 "code" : "0x60066005600460036002600185600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1161,7 +1161,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600760066005600460036002600186600357", | ||||
|                 "code" : "0x600760066005600460036002600186600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1189,7 +1189,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6008600760066005600460036002600187600357", | ||||
|                 "code" : "0x6008600760066005600460036002600187600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1217,7 +1217,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x60096008600760066005600460036002600188600357", | ||||
|                 "code" : "0x60096008600760066005600460036002600188600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1245,7 +1245,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600a60096008600760066005600460036002600189600357", | ||||
|                 "code" : "0x600a60096008600760066005600460036002600189600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1273,7 +1273,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600b600a6009600860076006600560046003600260018a600357", | ||||
|                 "code" : "0x600b600a6009600860076006600560046003600260018a600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1301,7 +1301,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600c600b600a6009600860076006600560046003600260018b600357", | ||||
|                 "code" : "0x600c600b600a6009600860076006600560046003600260018b600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1329,7 +1329,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600d600c600b600a6009600860076006600560046003600260018c600357", | ||||
|                 "code" : "0x600d600c600b600a6009600860076006600560046003600260018c600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1357,7 +1357,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600e600d600c600b600a6009600860076006600560046003600260018d600357", | ||||
|                 "code" : "0x600e600d600c600b600a6009600860076006600560046003600260018d600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1385,7 +1385,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600f600e600d600c600b600a6009600860076006600560046003600260018e600357", | ||||
|                 "code" : "0x600f600e600d600c600b600a6009600860076006600560046003600260018e600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1413,7 +1413,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6010600f600e600d600c600b600a6009600860076006600560046003600260018f600357", | ||||
|                 "code" : "0x6010600f600e600d600c600b600a6009600860076006600560046003600260018f600355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1441,7 +1441,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff60039057", | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff60039055", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1469,7 +1469,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff60039157", | ||||
|                 "code" : "0x7f10112233445566778899aabbccddeeff00112233445566778899aabbccddeeff60039155", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1497,7 +1497,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6002600160039157", | ||||
|                 "code" : "0x6002600160039155", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1525,7 +1525,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x60036002600160039257", | ||||
|                 "code" : "0x60036002600160039255", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1553,7 +1553,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600460036002600160039357", | ||||
|                 "code" : "0x600460036002600160039355", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1581,7 +1581,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6005600460036002600160039457", | ||||
|                 "code" : "0x6005600460036002600160039455", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1609,7 +1609,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x60066005600460036002600160039557", | ||||
|                 "code" : "0x60066005600460036002600160039555", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1637,7 +1637,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600760066005600460036002600160039657", | ||||
|                 "code" : "0x600760066005600460036002600160039655", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1665,7 +1665,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6008600760066005600460036002600160039757", | ||||
|                 "code" : "0x6008600760066005600460036002600160039755", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1693,7 +1693,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x60096008600760066005600460036002600160039857", | ||||
|                 "code" : "0x60096008600760066005600460036002600160039855", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1721,7 +1721,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600a60096008600760066005600460036002600160039957", | ||||
|                 "code" : "0x600a60096008600760066005600460036002600160039955", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1749,7 +1749,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600b600a60096008600760066005600460036002600160039a57", | ||||
|                 "code" : "0x600b600a60096008600760066005600460036002600160039a55", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1777,7 +1777,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600c600b600a60096008600760066005600460036002600160039b57", | ||||
|                 "code" : "0x600c600b600a60096008600760066005600460036002600160039b55", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1805,7 +1805,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600d600c600b600a60096008600760066005600460036002600160039c57", | ||||
|                 "code" : "0x600d600c600b600a60096008600760066005600460036002600160039c55", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1833,7 +1833,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600e600d600c600b600a60096008600760066005600460036002600160039d57", | ||||
|                 "code" : "0x600e600d600c600b600a60096008600760066005600460036002600160039d55", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1861,7 +1861,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x600f600e600d600c600b600a60096008600760066005600460036002600160039e57", | ||||
|                 "code" : "0x600f600e600d600c600b600a60096008600760066005600460036002600160039e55", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
| @ -1889,7 +1889,7 @@ | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "0x6010600f600e600d600c600b600a60096008600760066005600460036002600160039f57", | ||||
|                 "code" : "0x6010600f600e600d600c600b600a60096008600760066005600460036002600160039f55", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|  | ||||
| @ -111,7 +111,7 @@ | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     "sha3_3": { | ||||
|     "sha3_4": { | ||||
|         "env" : { | ||||
|             "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|             "currentNumber" : "0", | ||||
| @ -137,8 +137,61 @@ | ||||
|             "gasPrice" : "100000000000000", | ||||
|             "gas" : "10000" | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     "sha3_5": { | ||||
|         "env" : { | ||||
|             "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|             "currentNumber" : "0", | ||||
|             "currentGasLimit" : "1000000", | ||||
|             "currentDifficulty" : "256", | ||||
|             "currentTimestamp" : 1, | ||||
|             "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|         }, | ||||
|         "pre" : { | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "{ [[ 0 ]] (SHA3 10000 0xfffffffff )}", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "exec" : { | ||||
|             "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", | ||||
|             "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "value" : "1000000000000000000", | ||||
|             "data" : "", | ||||
|             "gasPrice" : "100000000000000", | ||||
|             "gas" : "10000" | ||||
|         } | ||||
|     }, | ||||
| 
 | ||||
|     "sha3_6": { | ||||
|         "env" : { | ||||
|             "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", | ||||
|             "currentNumber" : "0", | ||||
|             "currentGasLimit" : "1000000", | ||||
|             "currentDifficulty" : "256", | ||||
|             "currentTimestamp" : 1, | ||||
|             "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" | ||||
|         }, | ||||
|         "pre" : { | ||||
|             "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { | ||||
|                 "balance" : "1000000000000000000", | ||||
|                 "nonce" : 0, | ||||
|                 "code" : "{ [[ 0 ]] (SHA3 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)}", | ||||
|                 "storage": {} | ||||
|             } | ||||
|         }, | ||||
|         "exec" : { | ||||
|             "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", | ||||
|             "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", | ||||
|             "value" : "1000000000000000000", | ||||
|             "data" : "", | ||||
|             "gasPrice" : "100000000000000", | ||||
|             "gas" : "10000" | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -12,444 +12,444 @@ class WebThreeStubClient : public jsonrpc::Client | ||||
|     public: | ||||
|         WebThreeStubClient(jsonrpc::IClientConnector &conn) : jsonrpc::Client(conn) {} | ||||
| 
 | ||||
|         std::string coinbase() throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_coinbase() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("coinbase",p); | ||||
|             Json::Value result = this->CallMethod("eth_coinbase",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool setCoinbase(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool eth_setCoinbase(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("setCoinbase",p); | ||||
|             Json::Value result = this->CallMethod("eth_setCoinbase",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool listening() throw (jsonrpc::JsonRpcException) | ||||
|         bool eth_listening() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("listening",p); | ||||
|             Json::Value result = this->CallMethod("eth_listening",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool setListening(const bool& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool eth_setListening(const bool& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("setListening",p); | ||||
|             Json::Value result = this->CallMethod("eth_setListening",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool mining() throw (jsonrpc::JsonRpcException) | ||||
|         bool eth_mining() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("mining",p); | ||||
|             Json::Value result = this->CallMethod("eth_mining",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool setMining(const bool& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool eth_setMining(const bool& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("setMining",p); | ||||
|             Json::Value result = this->CallMethod("eth_setMining",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string gasPrice() throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_gasPrice() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("gasPrice",p); | ||||
|             Json::Value result = this->CallMethod("eth_gasPrice",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string account() throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value eth_accounts() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("account",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value accounts() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("accounts",p); | ||||
|             Json::Value result = this->CallMethod("eth_accounts",p); | ||||
|             if (result.isArray()) | ||||
|                 return result; | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         int peerCount() throw (jsonrpc::JsonRpcException) | ||||
|         int eth_peerCount() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("peerCount",p); | ||||
|             Json::Value result = this->CallMethod("eth_peerCount",p); | ||||
|             if (result.isInt()) | ||||
|                 return result.asInt(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         int defaultBlock() throw (jsonrpc::JsonRpcException) | ||||
|         int eth_defaultBlock() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("defaultBlock",p); | ||||
|             Json::Value result = this->CallMethod("eth_defaultBlock",p); | ||||
|             if (result.isInt()) | ||||
|                 return result.asInt(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool setDefaultBlock(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool eth_setDefaultBlock(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("setDefaultBlock",p); | ||||
|             Json::Value result = this->CallMethod("eth_setDefaultBlock",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         int number() throw (jsonrpc::JsonRpcException) | ||||
|         int eth_number() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("number",p); | ||||
|             Json::Value result = this->CallMethod("eth_number",p); | ||||
|             if (result.isInt()) | ||||
|                 return result.asInt(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string balanceAt(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_balanceAt(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("balanceAt",p); | ||||
|             Json::Value result = this->CallMethod("eth_balanceAt",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string stateAt(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_stateAt(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("stateAt",p); | ||||
|             Json::Value result = this->CallMethod("eth_stateAt",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         double countAt(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         double eth_countAt(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("countAt",p); | ||||
|             Json::Value result = this->CallMethod("eth_countAt",p); | ||||
|             if (result.isDouble()) | ||||
|                 return result.asDouble(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string codeAt(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_codeAt(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("codeAt",p); | ||||
|             Json::Value result = this->CallMethod("eth_codeAt",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string transact(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_transact(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("transact",p); | ||||
|             Json::Value result = this->CallMethod("eth_transact",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string call(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_call(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("call",p); | ||||
|             Json::Value result = this->CallMethod("eth_call",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value blockByHash(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value eth_blockByHash(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("blockByHash",p); | ||||
|             Json::Value result = this->CallMethod("eth_blockByHash",p); | ||||
|             if (result.isObject()) | ||||
|                 return result; | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value blockByNumber(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value eth_blockByNumber(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("blockByNumber",p); | ||||
|             Json::Value result = this->CallMethod("eth_blockByNumber",p); | ||||
|             if (result.isObject()) | ||||
|                 return result; | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value transactionByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value eth_transactionByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("transactionByHash",p); | ||||
|             Json::Value result = this->CallMethod("eth_transactionByHash",p); | ||||
|             if (result.isObject()) | ||||
|                 return result; | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value transactionByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value eth_transactionByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("transactionByNumber",p); | ||||
|             Json::Value result = this->CallMethod("eth_transactionByNumber",p); | ||||
|             if (result.isObject()) | ||||
|                 return result; | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value uncleByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value eth_uncleByHash(const std::string& param1, const int& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("uncleByHash",p); | ||||
|             Json::Value result = this->CallMethod("eth_uncleByHash",p); | ||||
|             if (result.isObject()) | ||||
|                 return result; | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value uncleByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value eth_uncleByNumber(const int& param1, const int& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("uncleByNumber",p); | ||||
|             Json::Value result = this->CallMethod("eth_uncleByNumber",p); | ||||
|             if (result.isObject()) | ||||
|                 return result; | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string compile(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_lll(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("compile",p); | ||||
|             Json::Value result = this->CallMethod("eth_lll",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         int newFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         std::string eth_compile(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("newFilter",p); | ||||
|             Json::Value result = this->CallMethod("eth_compile",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         int eth_newFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("eth_newFilter",p); | ||||
|             if (result.isInt()) | ||||
|                 return result.asInt(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         int newFilterString(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         int eth_newFilterString(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("newFilterString",p); | ||||
|             Json::Value result = this->CallMethod("eth_newFilterString",p); | ||||
|             if (result.isInt()) | ||||
|                 return result.asInt(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool uninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool eth_uninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("uninstallFilter",p); | ||||
|             Json::Value result = this->CallMethod("eth_uninstallFilter",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool changed(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool eth_changed(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("changed",p); | ||||
|             Json::Value result = this->CallMethod("eth_changed",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value getMessages(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value eth_getMessages(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("getMessages",p); | ||||
|             Json::Value result = this->CallMethod("eth_getMessages",p); | ||||
|             if (result.isArray()) | ||||
|                 return result; | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) | ||||
|         bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             p.append(param3); | ||||
|             Json::Value result = this->CallMethod("put",p); | ||||
|             Json::Value result = this->CallMethod("db_put",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string get(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         std::string db_get(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("get",p); | ||||
|             Json::Value result = this->CallMethod("db_get",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool putString(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) | ||||
|         bool db_putString(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             p.append(param3); | ||||
|             Json::Value result = this->CallMethod("putString",p); | ||||
|             Json::Value result = this->CallMethod("db_putString",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string getString(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         std::string db_getString(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("getString",p); | ||||
|             Json::Value result = this->CallMethod("db_getString",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool post(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool shh_post(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("post",p); | ||||
|             Json::Value result = this->CallMethod("shh_post",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string newIdentity() throw (jsonrpc::JsonRpcException) | ||||
|         std::string shh_newIdentity() throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p = Json::nullValue; | ||||
|             Json::Value result = this->CallMethod("newIdentity",p); | ||||
|             Json::Value result = this->CallMethod("shh_newIdentity",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool haveIdentity(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool shh_haveIdentity(const std::string& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("haveIdentity",p); | ||||
|             Json::Value result = this->CallMethod("shh_haveIdentity",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string newGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         std::string shh_newGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("newGroup",p); | ||||
|             Json::Value result = this->CallMethod("shh_newGroup",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         std::string addToGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         std::string shh_addToGroup(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             p.append(param2); | ||||
|             Json::Value result = this->CallMethod("addToGroup",p); | ||||
|             Json::Value result = this->CallMethod("shh_addToGroup",p); | ||||
|             if (result.isString()) | ||||
|                 return result.asString(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         int shhNewFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         int shh_newFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("shhNewFilter",p); | ||||
|             Json::Value result = this->CallMethod("shh_newFilter",p); | ||||
|             if (result.isInt()) | ||||
|                 return result.asInt(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         bool shhUninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         bool shh_uninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("shhUninstallFilter",p); | ||||
|             Json::Value result = this->CallMethod("shh_uninstallFilter",p); | ||||
|             if (result.isBool()) | ||||
|                 return result.asBool(); | ||||
|             else | ||||
|                 throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); | ||||
|         } | ||||
|         Json::Value shhChanged(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         Json::Value shh_changed(const int& param1) throw (jsonrpc::JsonRpcException) | ||||
|         { | ||||
|             Json::Value p; | ||||
|             p.append(param1); | ||||
|             Json::Value result = this->CallMethod("shhChanged",p); | ||||
|             Json::Value result = this->CallMethod("shh_changed",p); | ||||
|             if (result.isArray()) | ||||
|                 return result; | ||||
|             else | ||||
|  | ||||
							
								
								
									
										84
									
								
								whisperTopic.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								whisperTopic.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| /*
 | ||||
| 	This file is part of cpp-ethereum. | ||||
| 
 | ||||
| 	cpp-ethereum is free software: you can redistribute it and/or modify | ||||
| 	it under the terms of the GNU General Public License as published by | ||||
| 	the Free Software Foundation, either version 3 of the License, or | ||||
| 	(at your option) any later version. | ||||
| 
 | ||||
| 	cpp-ethereum is distributed in the hope that it will be useful, | ||||
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| 	GNU General Public License for more details. | ||||
| 
 | ||||
| 	You should have received a copy of the GNU General Public License | ||||
| 	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| /** @file whisperTopic.cpp
 | ||||
|  * @author Gav Wood <i@gavwood.com> | ||||
|  * @date 2014 | ||||
|  */ | ||||
| #include <functional> | ||||
| #include <boost/test/unit_test.hpp> | ||||
| #include <libp2p/Host.h> | ||||
| #include <libwhisper/WhisperPeer.h> | ||||
| #include <libwhisper/WhisperHost.h> | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| using namespace dev::p2p; | ||||
| using namespace dev::shh; | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(whisper) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(topic) | ||||
| { | ||||
| 	g_logVerbosity = 0; | ||||
| 
 | ||||
| 	bool started = false; | ||||
| 	unsigned result = 0; | ||||
| 	std::thread listener([&]() | ||||
| 	{ | ||||
| 		setThreadName("other"); | ||||
| 
 | ||||
| 		Host ph("Test", NetworkPreferences(30303, "", false, true)); | ||||
| 		auto wh = ph.registerCapability(new WhisperHost()); | ||||
| 		ph.start(); | ||||
| 
 | ||||
| 		started = true; | ||||
| 
 | ||||
| 		/// Only interested in odd packets
 | ||||
| 		auto w = wh->installWatch(BuildTopicMask()("odd")); | ||||
| 
 | ||||
| 		for (int i = 0, last = 0; i < 100 && last < 81; ++i) | ||||
| 		{ | ||||
| 			for (auto i: wh->checkWatch(w)) | ||||
| 			{ | ||||
| 				Message msg = wh->envelope(i).open(); | ||||
| 				last = RLP(msg.payload()).toInt<unsigned>(); | ||||
| 				cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>(); | ||||
| 				result += last; | ||||
| 			} | ||||
| 			this_thread::sleep_for(chrono::milliseconds(50)); | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
| 	while (!started) | ||||
| 		this_thread::sleep_for(chrono::milliseconds(50)); | ||||
| 
 | ||||
| 	Host ph("Test", NetworkPreferences(30300, "", false, true)); | ||||
| 	auto wh = ph.registerCapability(new WhisperHost()); | ||||
| 	ph.start(); | ||||
| 	ph.connect("127.0.0.1", 30303); | ||||
| 
 | ||||
| 	KeyPair us = KeyPair::create(); | ||||
| 	for (int i = 0; i < 10; ++i) | ||||
| 	{ | ||||
| 		wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even")); | ||||
| 		this_thread::sleep_for(chrono::milliseconds(250)); | ||||
| 	} | ||||
| 
 | ||||
| 	listener.join(); | ||||
| 	BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user