diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index a1196acae..5886554e3 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -154,6 +154,7 @@
+
@@ -1045,6 +1046,11 @@
&Export Selected Key...
+
+
+ &Inject Transaction
+
+
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 630006698..96ef45e2d 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -673,6 +673,14 @@ void Main::ourAccountsRowsMoved()
m_myKeys = myKeys;
}
+void Main::on_inject_triggered()
+{
+ QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex");
+ bytes b = fromHex(s.toStdString());
+ m_client->inject(&b);
+ refresh();
+}
+
void Main::on_blocks_currentItemChanged()
{
ui->info->clear();
@@ -727,6 +735,10 @@ void Main::on_blocks_currentItemChanged()
s << " #" << tx.nonce << "";
s << "
Gas price: " << formatBalance(tx.gasPrice) << "";
s << "
Gas: " << tx.gas << "";
+ s << "
V: " << hex << (int)tx.vrs.v << "";
+ s << "
R: " << hex << tx.vrs.r << "";
+ s << "
S: " << hex << tx.vrs.s << "";
+ s << "
Msg: " << tx.sha3(false) << "";
if (tx.isCreation())
{
if (tx.data.size())
@@ -747,7 +759,7 @@ void Main::on_blocks_currentItemChanged()
void Main::on_contracts_currentItemChanged()
{
ui->contractInfo->clear();
- m_client->lock();
+ eth::ClientGuard l(&*m_client);
if (auto item = ui->contracts->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
@@ -761,7 +773,6 @@ void Main::on_contracts_currentItemChanged()
s << "Body Code
" << disassemble(state().code(h));
ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
}
- m_client->unlock();
}
void Main::on_idealPeers_valueChanged()
@@ -1033,7 +1044,7 @@ void Main::on_send_clicked()
{
debugFinished();
u256 totalReq = value() + fee();
- m_client->lock();
+ eth::ClientGuard l(&*m_client);
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq)
{
@@ -1046,7 +1057,6 @@ void Main::on_send_clicked()
refresh();
return;
}
- m_client->unlock();
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
}
@@ -1054,7 +1064,7 @@ void Main::on_debug_clicked()
{
debugFinished();
u256 totalReq = value() + fee();
- m_client->lock();
+ eth::ClientGuard l(&*m_client);
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq)
{
@@ -1088,7 +1098,6 @@ void Main::on_debug_clicked()
updateDebugger();
return;
}
- m_client->unlock();
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
}
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index b5a22671e..1258bac67 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -79,6 +79,7 @@ private slots:
void on_killBlockchain_triggered();
void on_importKey_triggered();
void on_exportKey_triggered();
+ void on_inject_triggered();
void refresh(bool _override = false);
void refreshNetwork();
diff --git a/libethcore/TrieDB.h b/libethcore/TrieDB.h
index 35aecdcb7..dd8a36fd5 100644
--- a/libethcore/TrieDB.h
+++ b/libethcore/TrieDB.h
@@ -61,6 +61,8 @@ inline std::ostream& operator<<(std::ostream& _out, BasicMap const& _m)
return _out;
}
+class InvalidTrie: public std::exception {};
+
class Overlay: public BasicMap
{
public:
@@ -196,8 +198,7 @@ public:
cdebug << rlp;
auto c = rlp.itemCount();
cdebug << c;
- m_that = nullptr;
- return;
+ throw InvalidTrie();
assert(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17));
}
if (rlp.itemCount() == 2)
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index 6f9c7e202..99cae63a1 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -174,6 +174,13 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2
return right160(sha3(rlpList(t.sender(), t.nonce)));
}
+void Client::inject(bytesConstRef _rlp)
+{
+ lock_guard l(m_lock);
+ m_tq.attemptImport(_rlp);
+ m_changed = true;
+}
+
void Client::work()
{
bool changed = false;
diff --git a/libethereum/Client.h b/libethereum/Client.h
index e9cc845df..bb3e3a2ce 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -90,6 +90,8 @@ public:
/// @returns the new contract's address (assuming it all goes through).
Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
+ void inject(bytesConstRef _rlp);
+
/// Makes the given call. Nothing is recorded into the state. TODO
// bytes call(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes());
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index d3147cb04..a8bd3a86e 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -108,6 +108,11 @@ void Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
void Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin)
{
+#if ETH_PARANOIA
+
+
+#endif
+
m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1)));
while (m_s.addressInUse(m_newAddress))
m_newAddress = (u160)m_newAddress + 1;
diff --git a/libethereum/PeerServer.cpp b/libethereum/PeerServer.cpp
index 8b3644aa5..6a79f9f35 100644
--- a/libethereum/PeerServer.cpp
+++ b/libethereum/PeerServer.cpp
@@ -363,7 +363,7 @@ bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
if (m_mode == NodeMode::Full)
{
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
- if (_tq.import(*it))
+ if (_tq.import(&*it))
{}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
else
m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on.
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 72ad36346..ac605644f 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -158,14 +158,9 @@ struct CachedAddressState
std::map ret;
if (r)
{
- cdebug << "MemDB: " << r[2].toHash();
TrieDB memdb(const_cast(o), r[2].toHash()); // promise we won't alter the overlay! :)
- cdebug << memdb.root();
for (auto const& j: memdb)
- {
- cdebug << j.first;
ret[j.first] = RLP(j.second).toInt();
- }
}
if (s)
for (auto const& j: s->storage())
@@ -859,13 +854,16 @@ u256 State::execute(bytesConstRef _rlp)
commit(); // get an updated hash
#endif
+ // TODO: CHECK TRIE
+
State old(*this);
auto h = rootHash();
Executive e(*this);
e.setup(_rlp);
- cnote << "Executing " << e.t() << "on" << h;
+ cnote << "Executing" << e.t() << "on" << h;
+ cnote << toHex(e.t().rlp(true));
u256 startGasUsed = gasUsed();
if (startGasUsed + e.t().gas > m_currentBlock.gasLimit)
@@ -882,6 +880,9 @@ u256 State::execute(bytesConstRef _rlp)
cnote << "Executed; now" << rootHash();
cnote << old.diff(*this);
+ // TODO: CHECK TRIE
+ // TODO: CHECK TRIE after level DB flush to make sure exactly the same.
+
// Add to the user-originated transactions that we've executed.
m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed()));
m_transactionSet.insert(e.t().sha3());
diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp
index 3eb6a347b..7ff7a174e 100644
--- a/libethereum/TransactionQueue.cpp
+++ b/libethereum/TransactionQueue.cpp
@@ -27,7 +27,7 @@
using namespace std;
using namespace eth;
-bool TransactionQueue::import(bytes const& _block)
+bool TransactionQueue::import(bytesConstRef _block)
{
// Check if we already know this transaction.
h256 h = sha3(_block);
@@ -44,7 +44,7 @@ bool TransactionQueue::import(bytes const& _block)
m_interestQueue.push_back(t);
// If valid, append to blocks.
- m_data[h] = _block;
+ m_data[h] = _block.toBytes();
}
catch (InvalidTransactionFormat const& _e)
{
diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h
index 3736f392c..e42da52b7 100644
--- a/libethereum/TransactionQueue.h
+++ b/libethereum/TransactionQueue.h
@@ -35,8 +35,9 @@ class BlockChain;
class TransactionQueue
{
public:
- bool attemptImport(bytes const& _block) { try { import(_block); return true; } catch (...) { return false; } }
- bool import(bytes const& _block);
+ bool attemptImport(bytesConstRef _block) { try { import(_block); return true; } catch (...) { return false; } }
+ bool attemptImport(bytes const& _block) { try { import(&_block); return true; } catch (...) { return false; } }
+ bool import(bytesConstRef _block);
void drop(h256 _txHash) { m_data.erase(_txHash); }
std::map const& transactions() const { return m_data; }