From 08d88f1a4aa6151ac626d80b1cf8650d805b73b9 Mon Sep 17 00:00:00 2001
From: arkpar <arkadiy@ethdev.com>
Date: Wed, 4 Feb 2015 01:00:19 +0100
Subject: [PATCH 1/4] mix: Mining and transactions on a real blockchain

---
 mix/ClientModel.cpp     |  39 +++++--
 mix/MixClient.cpp       | 219 ++++++++++++++++++++++++----------------
 mix/MixClient.h         |  30 +++---
 mix/qml/MainContent.qml |   3 +-
 4 files changed, 175 insertions(+), 116 deletions(-)

diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp
index 365dce9a9..ebfd885f1 100644
--- a/mix/ClientModel.cpp
+++ b/mix/ClientModel.cpp
@@ -22,6 +22,7 @@
 #include <QDebug>
 #include <QQmlContext>
 #include <QQmlApplicationEngine>
+#include <QStandardPaths>
 #include <jsonrpccpp/server.h>
 #include <libdevcore/CommonJS.h>
 #include <libethereum/Transaction.h>
@@ -83,7 +84,7 @@ ClientModel::ClientModel(AppContext* _context):
 	qRegisterMetaType<TransactionLogEntry*>("TransactionLogEntry");
 
 	connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection);
-	m_client.reset(new MixClient());
+	m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString()));
 
 	m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), std::vector<dev::KeyPair> { m_client->userAccount() }, m_client.get()));
 	connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection);
@@ -93,6 +94,7 @@ ClientModel::ClientModel(AppContext* _context):
 
 ClientModel::~ClientModel()
 {
+
 }
 
 QString ClientModel::apiCall(QString const& _message)
@@ -111,8 +113,25 @@ QString ClientModel::apiCall(QString const& _message)
 
 void ClientModel::mine()
 {
-	m_client->mine();
-	newBlock();
+	if (m_running)
+		BOOST_THROW_EXCEPTION(ExecutionStateException());
+	m_running = true;
+	emit runStarted();
+	emit runStateChanged();
+	QtConcurrent::run([=]()
+	{
+		try
+		{
+			m_client->mine();
+			newBlock();
+		}
+		catch (...)
+		{
+			std::cerr << boost::current_exception_diagnostic_information();
+			emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information()));
+		}
+		m_running = false;
+	});
 }
 
 QString ClientModel::contractAddress() const
@@ -145,7 +164,7 @@ void ClientModel::setupState(QVariantMap _state)
 			TransactionSettings transactionSettings(functionId, transaction.value("url").toString());
 			transactionSettings.gasPrice = 10000000000000;
 			transactionSettings.gas = 125000;
-			transactionSettings.value = 100;
+			transactionSettings.value = 0;
 			transactionSequence.push_back(transactionSettings);
 		}
 		else
@@ -242,11 +261,13 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
 		}
 		catch(boost::exception const&)
 		{
+			std::cerr << boost::current_exception_diagnostic_information();
 			emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information()));
 		}
 
 		catch(std::exception const& e)
 		{
+			std::cerr << boost::current_exception_diagnostic_information();
 			emit runFailed(e.what());
 		}
 		m_running = false;
@@ -256,7 +277,7 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
 
 void ClientModel::showDebugger()
 {
-	ExecutionResult const& last = m_client->record().back().transactions.back();
+	ExecutionResult const& last = m_client->lastExecution();
 	showDebuggerForTransaction(last);
 }
 
@@ -289,7 +310,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
 
 void ClientModel::debugTransaction(unsigned _block, unsigned _index)
 {
-	auto const& t = m_client->record().at(_block).transactions.at(_index);
+	auto const& t = m_client->execution(_block, _index);
 	showDebuggerForTransaction(t);
 }
 
@@ -320,9 +341,9 @@ void ClientModel::onStateReset()
 
 void ClientModel::onNewTransaction()
 {
-	unsigned block = m_client->number();
-	unsigned index =  m_client->record().back().transactions.size() - 1;
-	ExecutionResult const& tr = m_client->record().back().transactions.back();
+	unsigned block = m_client->number() + 1;
+	unsigned index =  m_client->pendingExecutions().size() - 1;
+	ExecutionResult const& tr = m_client->lastExecution();
 	QString address = QString::fromStdString(toJS(tr.address));
 	QString value =  QString::fromStdString(dev::toString(tr.value));
 	QString contract = address;
diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp
index a6c833532..7cbb8424b 100644
--- a/mix/MixClient.cpp
+++ b/mix/MixClient.cpp
@@ -36,35 +36,49 @@ using namespace dev;
 using namespace dev::eth;
 using namespace dev::mix;
 
-const Secret c_stdSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
+const Secret c_userAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
 
-MixClient::MixClient():
-	m_userAccount(c_stdSecret)
+MixClient::MixClient(std::string const& _dbPath):
+	m_userAccount(c_userAccountSecret), m_bc(_dbPath, true), m_dbPath(_dbPath), m_minigThreads(0)
+{
+	//resetState(10000000 * ether);
+}
+
+MixClient::~MixClient()
 {
-	resetState(10000000 * ether);
 }
 
 void MixClient::resetState(u256 _balance)
 {
-	WriteGuard l(x_state);
-	Guard fl(m_filterLock);
-	m_filters.clear();
-	m_watches.clear();
-	m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Genesis);
-	m_state.addBalance(m_userAccount.address(), _balance);
-	Block genesis;
-	genesis.state = m_state;
-	Block open;
-	m_blocks = Blocks { genesis, open }; //last block contains a list of pending transactions to be finalized
-//	m_lastHashes.clear();
-//	m_lastHashes.resize(256);
-//	m_lastHashes[0] = genesis.hash;
+	(void) _balance;
+	{
+		WriteGuard l(x_state);
+		Guard fl(m_filterLock);
+		m_filters.clear();
+		m_watches.clear();
+		m_bc.reopen(m_dbPath, true);
+		m_state = eth::State();
+		m_stateDB = OverlayDB();
+		m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Genesis);
+		m_state.sync(m_bc);
+		m_startState = m_state;
+		m_pendingExecutions.clear();
+	}
+	mine();
 }
 
 void MixClient::executeTransaction(Transaction const& _t, State& _state)
 {
 	bytes rlp = _t.rlp();
-	Executive execution(_state, LastHashes(), 0);
+
+	// do debugging run first
+	LastHashes lastHashes(256);
+	lastHashes[0] = m_bc.numberHash(m_bc.number());
+	for (unsigned i = 1; i < 256; ++i)
+		lastHashes[i] = lastHashes[i - 1] ? m_bc.details(lastHashes[i - 1]).parent : h256();
+
+	State execState = _state;
+	Executive execution(execState, lastHashes, 0);
 	execution.setup(&rlp);
 	std::vector<MachineState> machineStates;
 	std::vector<unsigned> levels;
@@ -130,21 +144,25 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
 	d.value = _t.value();
 	if (_t.isCreation())
 		d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce())));
-	d.receipt = TransactionReceipt(m_state.rootHash(), execution.gasUsed(), execution.logs()); //TODO: track gas usage
-	m_blocks.back().transactions.emplace_back(d);
+	d.receipt = TransactionReceipt(execState.rootHash(), execution.gasUsed(), execution.logs()); //TODO: track gas usage
+	m_pendingExecutions.emplace_back(std::move(d));
 
+	// execute on a state
+	_state.execute(lastHashes, rlp, nullptr, true);
+
+	// collect watches
 	h256Set changed;
 	Guard l(m_filterLock);
 	for (std::pair<h256 const, eth::InstalledFilter>& i: m_filters)
-		if ((unsigned)i.second.filter.latest() > m_blocks.size() - 1)
+		if ((unsigned)i.second.filter.latest() > m_bc.number())
 		{
 			// acceptable number.
-			auto m = i.second.filter.matches(d.receipt);
+			auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1));
 			if (m.size())
 			{
 				// filter catches them
 				for (LogEntry const& l: m)
-					i.second.changes.push_back(LocalisedLogEntry(l, m_blocks.size()));
+					i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1));
 				changed.insert(i.first);
 			}
 		}
@@ -152,44 +170,56 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
 	noteChanged(changed);
 }
 
-void MixClient::validateBlock(int _block) const
-{
-	if (_block != -1 && _block != 0 && (unsigned)_block >= m_blocks.size() - 1)
-		BOOST_THROW_EXCEPTION(InvalidBlockException() << BlockIndex(_block));
-}
-
 void MixClient::mine()
 {
 	WriteGuard l(x_state);
-	Block& block = m_blocks.back();
-	m_state.mine(0, true);
+	m_state.commitToMine(m_bc);
+	while (!m_state.mine(100, true).completed) {}
 	m_state.completeMine();
-	m_state.commitToMine(BlockChain());
-	m_state.cleanup(true);
-	block.state = m_state;
-	block.info = m_state.info();
-	block.hash = block.info.hash;
-	m_blocks.push_back(Block());
-
+	m_bc.import(m_state.blockData(), m_stateDB);
+	m_state.sync(m_bc);
+	//m_state.cleanup(true);
+	m_startState = m_state;
+	m_executions.emplace_back(std::move(m_pendingExecutions));
 	h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter };
 	noteChanged(changed);
 }
 
-State const& MixClient::asOf(int _block) const
+ExecutionResult const& MixClient::execution(unsigned _block, unsigned _transaction) const
+{
+	if (_block == m_bc.number() + 1)
+		return m_pendingExecutions.at(_transaction);
+	return m_executions.at(_block).at(_transaction);
+}
+
+ExecutionResult const& MixClient::lastExecution() const
+{
+	if (m_pendingExecutions.size() > 0)
+		return m_pendingExecutions.back();
+	return m_executions.back().back();
+}
+
+ExecutionResults const& MixClient::pendingExecutions() const
 {
-	validateBlock(_block);
+	return m_pendingExecutions;
+}
+
+State MixClient::asOf(int _block) const
+{
+	ReadGuard l(x_state);
 	if (_block == 0)
-		return m_blocks[m_blocks.size() - 2].state;
-	else if (_block == -1)
 		return m_state;
+	else if (_block == -1)
+		return m_startState;
 	else
-		return m_blocks[_block].state;
+		return State(m_stateDB, m_bc, m_bc.numberHash(_block));
 }
 
 void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
 {
 	WriteGuard l(x_state);
 	u256 n = m_state.transactionsFrom(toAddress(_secret));
+	_gasPrice = 0; //TODO: remove after fixing setBalance
 	Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
 	executeTransaction(t, m_state);
 }
@@ -198,6 +228,7 @@ Address MixClient::transact(Secret _secret, u256 _endowment, bytes const& _init,
 {
 	WriteGuard l(x_state);
 	u256 n = m_state.transactionsFrom(toAddress(_secret));
+	_gasPrice = 0; //TODO: remove after fixing setBalance
 	eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
 	executeTransaction(t, m_state);
 	Address address = right160(sha3(rlpList(t.sender(), t.nonce())));
@@ -228,36 +259,31 @@ bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _
 	bytes rlp = t.rlp();
 	WriteGuard lw(x_state); //TODO: lock is required only for last execution state
 	executeTransaction(t, temp);
-	return m_blocks.back().transactions.back().returnValue;
+	return m_pendingExecutions.back().returnValue;
 }
 
 u256 MixClient::balanceAt(Address _a, int _block) const
 {
-	ReadGuard l(x_state);
 	return asOf(_block).balance(_a);
 }
 
 u256 MixClient::countAt(Address _a, int _block) const
 {
-	ReadGuard l(x_state);
 	return asOf(_block).transactionsFrom(_a);
 }
 
 u256 MixClient::stateAt(Address _a, u256 _l, int _block) const
 {
-	ReadGuard l(x_state);
 	return asOf(_block).storage(_a, _l);
 }
 
 bytes MixClient::codeAt(Address _a, int _block) const
 {
-	ReadGuard l(x_state);
 	return asOf(_block).code(_a);
 }
 
 std::map<u256, u256> MixClient::storageAt(Address _a, int _block) const
 {
-	ReadGuard l(x_state);
 	return asOf(_block).storage(_a);
 }
 
@@ -274,23 +300,40 @@ eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const
 eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const
 {
 	LocalisedLogEntries ret;
-	unsigned lastBlock = m_blocks.size() - 1; //last block contains pending transactions
+	unsigned lastBlock = m_bc.number();
 	unsigned block = std::min<unsigned>(lastBlock, (unsigned)_f.latest());
 	unsigned end = std::min(lastBlock, std::min(block, (unsigned)_f.earliest()));
-	for (; ret.size() != _f.max() && block != end; block--)
+	unsigned skip = _f.skip();
+	// Pending transactions
+	if (block > m_bc.number())
 	{
-		bool pendingBlock = (block == lastBlock);
-		if (pendingBlock || _f.matches(m_blocks[block].info.logBloom))
-			for (ExecutionResult const& t: m_blocks[block].transactions)
-				if (pendingBlock || _f.matches(t.receipt.bloom()))
+		ReadGuard l(x_state);
+		for (unsigned i = 0; i < m_state.pending().size(); ++i)
+		{
+			// Might have a transaction that contains a matching log.
+			TransactionReceipt const& tr = m_state.receipt(i);
+			LogEntries logEntries = _f.matches(tr);
+			for (unsigned entry = 0; entry < logEntries.size() && ret.size() != _f.max(); ++entry)
+				ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block));
+			skip -= std::min(skip, static_cast<unsigned>(logEntries.size()));
+		}
+		block = m_bc.number();
+	}
+
+	// The rest
+	auto h = m_bc.numberHash(block);
+	for (; ret.size() != block && block != end; block--)
+	{
+		if (_f.matches(m_bc.info(h).logBloom))
+			for (TransactionReceipt receipt: m_bc.receipts(h).receipts)
+				if (_f.matches(receipt.bloom()))
 				{
-					LogEntries logEntries = _f.matches(t.receipt);
-					if (logEntries.size())
-					{
-						for (unsigned entry = _f.skip(); entry < logEntries.size() && ret.size() != _f.max(); ++entry)
-							ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block));
-					}
+					LogEntries logEntries = _f.matches(receipt);
+					for (unsigned entry = skip; entry < logEntries.size() && ret.size() != _f.max(); ++entry)
+						ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block));
+					skip -= std::min(skip, static_cast<unsigned>(logEntries.size()));
 				}
+		h = m_bc.details(h).parent;
 	}
 	return ret;
 }
@@ -372,66 +415,65 @@ LocalisedLogEntries MixClient::checkWatch(unsigned _watchId)
 
 h256 MixClient::hashFromNumber(unsigned _number) const
 {
-	validateBlock(_number);
-	return m_blocks[_number].hash;
+	return m_bc.numberHash(_number);
 }
 
 eth::BlockInfo MixClient::blockInfo(h256 _hash) const
 {
-	(void)_hash;
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::blockInfo"));
+	return BlockInfo(m_bc.block(_hash));
 }
 
 eth::BlockDetails MixClient::blockDetails(h256 _hash) const
 {
-	(void)_hash;
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::blockDetails"));
+	return m_bc.details(_hash);
 }
 
 eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const
 {
-	(void)_blockHash;
-	(void)_i;
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::transaction"));
+	auto bl = m_bc.block(_blockHash);
+	RLP b(bl);
+	if (_i < b[1].itemCount())
+		return Transaction(b[1][_i].data(), CheckSignature::Range);
+	else
+		return Transaction();
 }
 
 eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const
 {
-	(void)_blockHash;
-	(void)_i;
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::uncle"));
+	auto bl = m_bc.block(_blockHash);
+	RLP b(bl);
+	if (_i < b[2].itemCount())
+		return BlockInfo::fromHeader(b[2][_i].data());
+	else
+		return BlockInfo();
 }
 
 unsigned MixClient::number() const
 {
-	return m_blocks.size() - 1;
+	return m_bc.number();
 }
 
 eth::Transactions MixClient::pending() const
 {
-	return eth::Transactions();
+	return m_state.pending();
 }
 
 eth::StateDiff MixClient::diff(unsigned _txi, h256 _block) const
 {
-	(void)_txi;
-	(void)_block;
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::diff"));
+	State st(m_stateDB, m_bc, _block);
+	return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
 }
 
 eth::StateDiff MixClient::diff(unsigned _txi, int _block) const
 {
-	(void)_txi;
-	(void)_block;
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::diff"));
+	State st = asOf(_block);
+	return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
 }
 
 Addresses MixClient::addresses(int _block) const
 {
-	validateBlock(_block);
-	ReadGuard l(x_state);
 	Addresses ret;
-	for (auto const& i: m_state.addresses())
+	for (auto const& i: asOf(_block).addresses())
 		ret.push_back(i.first);
 	return ret;
 }
@@ -456,23 +498,22 @@ Address MixClient::address() const
 
 void MixClient::setMiningThreads(unsigned _threads)
 {
-	(void)_threads;
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::setMiningThreads"));
+	m_minigThreads = _threads;
 }
 
 unsigned MixClient::miningThreads() const
 {
-	return 0;
+	return m_minigThreads;
 }
 
 void MixClient::startMining()
 {
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::startMining"));
+	//no-op
 }
 
 void MixClient::stopMining()
 {
-	BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::stopMining"));
+	//no-op
 }
 
 bool MixClient::isMining()
diff --git a/mix/MixClient.h b/mix/MixClient.h
index c34fff60b..ca0101680 100644
--- a/mix/MixClient.h
+++ b/mix/MixClient.h
@@ -24,8 +24,10 @@
 #pragma once
 
 #include <vector>
+#include <string>
 #include <libethereum/Interface.h>
 #include <libethereum/Client.h>
+#include <libethereum/BlockChain.h>
 #include "MachineStates.h"
 
 namespace dev
@@ -33,26 +35,18 @@ namespace dev
 namespace mix
 {
 
-struct Block
-{
-	ExecutionResults transactions;
-	h256 hash;
-	dev::eth::State state;
-	dev::eth::BlockInfo info;
-};
-
-using Blocks = std::vector<Block>;
-
-
 class MixClient: public dev::eth::Interface
 {
 public:
-	MixClient();
+	MixClient(std::string const& _dbPath);
+	virtual ~MixClient();
 	/// Reset state to the empty state with given balance.
 	void resetState(u256 _balance);
 	KeyPair const& userAccount() const { return m_userAccount; }
 	void mine();
-	Blocks const& record() const { return m_blocks; }
+	ExecutionResult const& execution(unsigned _block, unsigned _transaction) const;
+	ExecutionResult const& lastExecution() const;
+	ExecutionResults const& pendingExecutions() const;
 
 	//dev::eth::Interface
 	void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override;
@@ -94,18 +88,22 @@ public:
 
 private:
 	void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state);
-	void validateBlock(int _block) const;
 	void noteChanged(h256Set const& _filters);
-	dev::eth::State const& asOf(int _block) const;
+	dev::eth::State asOf(int _block) const;
 
 	KeyPair m_userAccount;
 	eth::State m_state;
+	eth::State m_startState;
 	OverlayDB m_stateDB;
+	eth::BlockChain m_bc;
 	mutable boost::shared_mutex x_state;
 	mutable std::mutex m_filterLock;
 	std::map<h256, dev::eth::InstalledFilter> m_filters;
 	std::map<unsigned, dev::eth::ClientWatch> m_watches;
-	Blocks m_blocks;
+	std::vector<ExecutionResults> m_executions;
+	ExecutionResults m_pendingExecutions;
+	std::string m_dbPath;
+	unsigned m_minigThreads;
 };
 
 }
diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml
index 247de143f..e6c636514 100644
--- a/mix/qml/MainContent.qml
+++ b/mix/qml/MainContent.qml
@@ -59,8 +59,7 @@ Rectangle {
 	}
 
 	function hideRightView() {
-		if (rightView.visible)
-			rightView.hide();
+		rightView.visible = false;
 	}
 
 	function toggleWebPreview() {

From b9584c5f211c6dcdabeb1dc356e9190b857fd3a6 Mon Sep 17 00:00:00 2001
From: arkpar <arkadiy@ethdev.com>
Date: Wed, 4 Feb 2015 17:41:56 +0100
Subject: [PATCH 2/4] style

---
 mix/ClientModel.cpp | 1 -
 mix/MixClient.cpp   | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp
index ebfd885f1..2eb207576 100644
--- a/mix/ClientModel.cpp
+++ b/mix/ClientModel.cpp
@@ -94,7 +94,6 @@ ClientModel::ClientModel(AppContext* _context):
 
 ClientModel::~ClientModel()
 {
-
 }
 
 QString ClientModel::apiCall(QString const& _message)
diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp
index 7cbb8424b..82b5c01d7 100644
--- a/mix/MixClient.cpp
+++ b/mix/MixClient.cpp
@@ -41,6 +41,7 @@ const Secret c_userAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4d
 MixClient::MixClient(std::string const& _dbPath):
 	m_userAccount(c_userAccountSecret), m_bc(_dbPath, true), m_dbPath(_dbPath), m_minigThreads(0)
 {
+	//TODO: put this into genesis block somehow
 	//resetState(10000000 * ether);
 }
 

From 1252ed3b881030a6e98222a526cb5be383dd34d4 Mon Sep 17 00:00:00 2001
From: Lu Guanqun <guanqun.lu@gmail.com>
Date: Thu, 5 Feb 2015 00:58:20 +0800
Subject: [PATCH 3/4] add several type error test cases

---
 test/SolidityNameAndTypeResolution.cpp | 36 ++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp
index 1a087592c..ae6c374b4 100644
--- a/test/SolidityNameAndTypeResolution.cpp
+++ b/test/SolidityNameAndTypeResolution.cpp
@@ -868,6 +868,42 @@ BOOST_AUTO_TEST_CASE(access_to_protected_state_variable)
 	BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
 }
 
+BOOST_AUTO_TEST_CASE(error_count_in_named_args)
+{
+	char const* sourceCode = "contract test {\n"
+							 "  function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
+							 "  function b() returns (uint r) { r = a({a: 1}); }\n"
+							 "}\n";
+	BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(empty_in_named_args)
+{
+	char const* sourceCode = "contract test {\n"
+							 "  function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
+							 "  function b() returns (uint r) { r = a({}); }\n"
+							 "}\n";
+	BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(duplicate_parameter_names_in_named_args)
+{
+	char const* sourceCode = "contract test {\n"
+							 "  function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
+							 "  function b() returns (uint r) { r = a({a: 1, a: 2}); }\n"
+							 "}\n";
+	BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_parameter_names_in_named_args)
+{
+	char const* sourceCode = "contract test {\n"
+							 "  function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
+							 "  function b() returns (uint r) { r = a({a: 1, c: 2}); }\n"
+							 "}\n";
+	BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 }

From 0a25d83f27e484bfe0329ee15929aee2ae7da479 Mon Sep 17 00:00:00 2001
From: Lu Guanqun <guanqun.lu@gmail.com>
Date: Thu, 5 Feb 2015 01:11:53 +0800
Subject: [PATCH 4/4] fix string comparision bug revealed by previous test case

This is due to refactoring of m_names using ASTPointer.
---
 libsolidity/AST.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp
index 6028c07cf..dfb677f7e 100644
--- a/libsolidity/AST.cpp
+++ b/libsolidity/AST.cpp
@@ -505,7 +505,7 @@ void FunctionCall::checkTypeRequirements()
 			// check duplicate names
 			for (size_t i = 0; i < m_names.size(); i++) {
 				for (size_t j = i + 1; j < m_names.size(); j++) {
-					if (m_names[i] == m_names[j])
+					if (*m_names[i] == *m_names[j])
 						BOOST_THROW_EXCEPTION(createTypeError("Duplicate named argument."));
 				}
 			}