Browse Source

Transaction injection.

cl-refactor
Gav Wood 11 years ago
parent
commit
0f3c3ff609
  1. 6
      alethzero/Main.ui
  2. 21
      alethzero/MainWin.cpp
  3. 1
      alethzero/MainWin.h
  4. 5
      libethcore/TrieDB.h
  5. 7
      libethereum/Client.cpp
  6. 2
      libethereum/Client.h
  7. 5
      libethereum/Executive.cpp
  8. 2
      libethereum/PeerServer.cpp
  9. 13
      libethereum/State.cpp
  10. 4
      libethereum/TransactionQueue.cpp
  11. 5
      libethereum/TransactionQueue.h

6
alethzero/Main.ui

@ -154,6 +154,7 @@
<addaction name="debugStep"/> <addaction name="debugStep"/>
<addaction name="paranoia"/> <addaction name="paranoia"/>
<addaction name="killBlockchain"/> <addaction name="killBlockchain"/>
<addaction name="inject"/>
</widget> </widget>
<addaction name="menu_File"/> <addaction name="menu_File"/>
<addaction name="menu_Network"/> <addaction name="menu_Network"/>
@ -1045,6 +1046,11 @@
<string>&amp;Export Selected Key...</string> <string>&amp;Export Selected Key...</string>
</property> </property>
</action> </action>
<action name="inject">
<property name="text">
<string>&amp;Inject Transaction</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

21
alethzero/MainWin.cpp

@ -673,6 +673,14 @@ void Main::ourAccountsRowsMoved()
m_myKeys = myKeys; 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() void Main::on_blocks_currentItemChanged()
{ {
ui->info->clear(); ui->info->clear();
@ -727,6 +735,10 @@ void Main::on_blocks_currentItemChanged()
s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce << "</b>"; s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce << "</b>";
s << "<br/>Gas price: <b>" << formatBalance(tx.gasPrice) << "</b>"; s << "<br/>Gas price: <b>" << formatBalance(tx.gasPrice) << "</b>";
s << "<br/>Gas: <b>" << tx.gas << "</b>"; s << "<br/>Gas: <b>" << tx.gas << "</b>";
s << "<br/>V: <b>" << hex << (int)tx.vrs.v << "</b>";
s << "<br/>R: <b>" << hex << tx.vrs.r << "</b>";
s << "<br/>S: <b>" << hex << tx.vrs.s << "</b>";
s << "<br/>Msg: <b>" << tx.sha3(false) << "</b>";
if (tx.isCreation()) if (tx.isCreation())
{ {
if (tx.data.size()) if (tx.data.size())
@ -747,7 +759,7 @@ void Main::on_blocks_currentItemChanged()
void Main::on_contracts_currentItemChanged() void Main::on_contracts_currentItemChanged()
{ {
ui->contractInfo->clear(); ui->contractInfo->clear();
m_client->lock(); eth::ClientGuard l(&*m_client);
if (auto item = ui->contracts->currentItem()) if (auto item = ui->contracts->currentItem())
{ {
auto hba = item->data(Qt::UserRole).toByteArray(); auto hba = item->data(Qt::UserRole).toByteArray();
@ -761,7 +773,6 @@ void Main::on_contracts_currentItemChanged()
s << "<h4>Body Code</h4>" << disassemble(state().code(h)); s << "<h4>Body Code</h4>" << disassemble(state().code(h));
ui->contractInfo->appendHtml(QString::fromStdString(s.str())); ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
} }
m_client->unlock();
} }
void Main::on_idealPeers_valueChanged() void Main::on_idealPeers_valueChanged()
@ -1033,7 +1044,7 @@ void Main::on_send_clicked()
{ {
debugFinished(); debugFinished();
u256 totalReq = value() + fee(); u256 totalReq = value() + fee();
m_client->lock(); eth::ClientGuard l(&*m_client);
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq) if (m_client->state().balance(i.address()) >= totalReq)
{ {
@ -1046,7 +1057,6 @@ void Main::on_send_clicked()
refresh(); refresh();
return; return;
} }
m_client->unlock();
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); 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(); debugFinished();
u256 totalReq = value() + fee(); u256 totalReq = value() + fee();
m_client->lock(); eth::ClientGuard l(&*m_client);
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq) if (m_client->state().balance(i.address()) >= totalReq)
{ {
@ -1088,7 +1098,6 @@ void Main::on_debug_clicked()
updateDebugger(); updateDebugger();
return; return;
} }
m_client->unlock();
statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount.");
} }

1
alethzero/MainWin.h

@ -79,6 +79,7 @@ private slots:
void on_killBlockchain_triggered(); void on_killBlockchain_triggered();
void on_importKey_triggered(); void on_importKey_triggered();
void on_exportKey_triggered(); void on_exportKey_triggered();
void on_inject_triggered();
void refresh(bool _override = false); void refresh(bool _override = false);
void refreshNetwork(); void refreshNetwork();

5
libethcore/TrieDB.h

@ -61,6 +61,8 @@ inline std::ostream& operator<<(std::ostream& _out, BasicMap const& _m)
return _out; return _out;
} }
class InvalidTrie: public std::exception {};
class Overlay: public BasicMap class Overlay: public BasicMap
{ {
public: public:
@ -196,8 +198,7 @@ public:
cdebug << rlp; cdebug << rlp;
auto c = rlp.itemCount(); auto c = rlp.itemCount();
cdebug << c; cdebug << c;
m_that = nullptr; throw InvalidTrie();
return;
assert(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17)); assert(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17));
} }
if (rlp.itemCount() == 2) if (rlp.itemCount() == 2)

7
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))); return right160(sha3(rlpList(t.sender(), t.nonce)));
} }
void Client::inject(bytesConstRef _rlp)
{
lock_guard<recursive_mutex> l(m_lock);
m_tq.attemptImport(_rlp);
m_changed = true;
}
void Client::work() void Client::work()
{ {
bool changed = false; bool changed = false;

2
libethereum/Client.h

@ -90,6 +90,8 @@ public:
/// @returns the new contract's address (assuming it all goes through). /// @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); 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 /// 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()); // bytes call(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes());

5
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) 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))); m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1)));
while (m_s.addressInUse(m_newAddress)) while (m_s.addressInUse(m_newAddress))
m_newAddress = (u160)m_newAddress + 1; m_newAddress = (u160)m_newAddress + 1;

2
libethereum/PeerServer.cpp

@ -363,7 +363,7 @@ bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
if (m_mode == NodeMode::Full) if (m_mode == NodeMode::Full)
{ {
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it) 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... {}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
else else
m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on. m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on.

13
libethereum/State.cpp

@ -158,14 +158,9 @@ struct CachedAddressState
std::map<u256, u256> ret; std::map<u256, u256> ret;
if (r) if (r)
{ {
cdebug << "MemDB: " << r[2].toHash<h256>();
TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(o), r[2].toHash<h256>()); // promise we won't alter the overlay! :) TrieDB<h256, Overlay> memdb(const_cast<Overlay*>(o), r[2].toHash<h256>()); // promise we won't alter the overlay! :)
cdebug << memdb.root();
for (auto const& j: memdb) for (auto const& j: memdb)
{
cdebug << j.first;
ret[j.first] = RLP(j.second).toInt<u256>(); ret[j.first] = RLP(j.second).toInt<u256>();
}
} }
if (s) if (s)
for (auto const& j: s->storage()) for (auto const& j: s->storage())
@ -859,13 +854,16 @@ u256 State::execute(bytesConstRef _rlp)
commit(); // get an updated hash commit(); // get an updated hash
#endif #endif
// TODO: CHECK TRIE
State old(*this); State old(*this);
auto h = rootHash(); auto h = rootHash();
Executive e(*this); Executive e(*this);
e.setup(_rlp); e.setup(_rlp);
cnote << "Executing " << e.t() << "on" << h; cnote << "Executing" << e.t() << "on" << h;
cnote << toHex(e.t().rlp(true));
u256 startGasUsed = gasUsed(); u256 startGasUsed = gasUsed();
if (startGasUsed + e.t().gas > m_currentBlock.gasLimit) if (startGasUsed + e.t().gas > m_currentBlock.gasLimit)
@ -882,6 +880,9 @@ u256 State::execute(bytesConstRef _rlp)
cnote << "Executed; now" << rootHash(); cnote << "Executed; now" << rootHash();
cnote << old.diff(*this); 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. // Add to the user-originated transactions that we've executed.
m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed())); m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed()));
m_transactionSet.insert(e.t().sha3()); m_transactionSet.insert(e.t().sha3());

4
libethereum/TransactionQueue.cpp

@ -27,7 +27,7 @@
using namespace std; using namespace std;
using namespace eth; using namespace eth;
bool TransactionQueue::import(bytes const& _block) bool TransactionQueue::import(bytesConstRef _block)
{ {
// Check if we already know this transaction. // Check if we already know this transaction.
h256 h = sha3(_block); h256 h = sha3(_block);
@ -44,7 +44,7 @@ bool TransactionQueue::import(bytes const& _block)
m_interestQueue.push_back(t); m_interestQueue.push_back(t);
// If valid, append to blocks. // If valid, append to blocks.
m_data[h] = _block; m_data[h] = _block.toBytes();
} }
catch (InvalidTransactionFormat const& _e) catch (InvalidTransactionFormat const& _e)
{ {

5
libethereum/TransactionQueue.h

@ -35,8 +35,9 @@ class BlockChain;
class TransactionQueue class TransactionQueue
{ {
public: public:
bool attemptImport(bytes const& _block) { try { import(_block); return true; } catch (...) { return false; } } bool attemptImport(bytesConstRef _block) { try { import(_block); return true; } catch (...) { return false; } }
bool import(bytes const& _block); 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); } void drop(h256 _txHash) { m_data.erase(_txHash); }
std::map<h256, bytes> const& transactions() const { return m_data; } std::map<h256, bytes> const& transactions() const { return m_data; }

Loading…
Cancel
Save