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; }