From 39c7e8f2eec0a68835904b79dd438b90ce88e180 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 18 Feb 2014 20:03:45 +0000 Subject: [PATCH] Assembler & disassembler. Additional info in block chain. --- CMakeLists.txt | 2 +- alethzero/Main.ui | 23 +++++---- alethzero/MainWin.cpp | 94 +++++++++++++++++++++++++++++++------ alethzero/MainWin.h | 1 + libethereum/Client.cpp | 10 ++-- libethereum/Client.h | 2 +- libethereum/Common.h | 2 +- libethereum/Instruction.cpp | 25 +++++++++- libethereum/Instruction.h | 68 ++++++++++++++++++++++++++- libethereum/State.cpp | 4 +- libethereum/Transaction.cpp | 12 +++++ libethereum/Transaction.h | 11 ++++- 12 files changed, 218 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b85033c42..9affafc0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_AUTOMOC ON) cmake_policy(SET CMP0015 NEW) -set(ETH_VERSION 0.3.0) +set(ETH_VERSION 0.3.1) set(ETH_BUILD_TYPE ${CMAKE_BUILD_TYPE}) # Default HEADLESS to 0. diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 690a0049f..d2589f815 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -20,18 +20,25 @@ true - - - 4 - + 0 - - - QFrame::NoFrame + + + Qt::Vertical + + + QFrame::NoFrame + + + + + QFrame::NoFrame + + @@ -51,7 +58,7 @@ - + 1 block diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index cefa1b9e3..5fe09d5e6 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -53,7 +53,7 @@ Main::Main(QWidget *parent) : initUnits(ui->valueUnits); statusBar()->addPermanentWidget(ui->balance); statusBar()->addPermanentWidget(ui->peerCount); - statusBar()->addPermanentWidget(ui->blockChain); + statusBar()->addPermanentWidget(ui->blockCount); } Main::~Main() @@ -126,7 +126,7 @@ void Main::readSettings() void Main::refresh() { m_client->lock(); - //if (m_client->changed()) + if (m_client->changed()) { ui->peerCount->setText(QString::fromStdString(toString(m_client->peerCount())) + " peer(s)"); ui->peers->clear(); @@ -135,37 +135,42 @@ void Main::refresh() auto d = m_client->blockChain().details(); auto diff = BlockInfo(m_client->blockChain().block()).difficulty; - ui->blockChain->setText(QString("#%1 @%3 T%2").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff))); + ui->blockCount->setText(QString("#%1 @%3 T%2").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff))); auto acs = m_client->state().addresses(); ui->accounts->clear(); for (auto i: acs) - ui->accounts->addItem(QString("%1 @ %2").arg(formatBalance(i.second).c_str()).arg(asHex(i.first.asArray()).c_str())); + ui->accounts->addItem(QString("%1 @ %2").arg(formatBalance(i.second).c_str()).arg(i.first.abridged().c_str())); ui->transactionQueue->clear(); for (pair const& i: m_client->pending()) { ui->transactionQueue->addItem(QString("%1 [%4] @ %2 <- %3") .arg(formatBalance(i.second.value).c_str()) - .arg(asHex(i.second.receiveAddress.asArray()).c_str()) - .arg(asHex(i.second.sender().asArray()).c_str()) + .arg(i.second.receiveAddress.abridged().c_str()) + .arg(i.second.safeSender().abridged().c_str()) .arg((unsigned)i.second.nonce)); } - ui->transactions->clear(); + ui->blocks->clear(); auto const& bc = m_client->blockChain(); for (auto h = bc.currentHash(); h != bc.genesisHash(); h = bc.details(h).parent) { auto d = bc.details(h); - ui->transactions->addItem(QString("# %1 ==== %2").arg(d.number).arg(asHex(h.asArray()).c_str())); + QListWidgetItem* blockItem = new QListWidgetItem(QString("# %1 ==== %2").arg(d.number).arg(h.abridged().c_str()), ui->blocks); + blockItem->setData(Qt::UserRole, QByteArray((char const*)h.data(), h.size)); + int n = 0; for (auto const& i: RLP(bc.block(h))[1]) { Transaction t(i.data()); - ui->transactions->addItem(QString("%1 [%4] @ %2 <- %3") - .arg(formatBalance(t.value).c_str()) - .arg(asHex(t.receiveAddress.asArray()).c_str()) - .arg(asHex(t.sender().asArray()).c_str()) - .arg((unsigned)t.nonce)); + QListWidgetItem* txItem = new QListWidgetItem(QString("%1 [%4] @ %2 <- %3") + .arg(formatBalance(t.value).c_str()) + .arg(t.receiveAddress.abridged().c_str()) + .arg(t.safeSender().abridged().c_str()) + .arg((unsigned)t.nonce), ui->blocks); + txItem->setData(Qt::UserRole, QByteArray((char const*)h.data(), h.size)); + txItem->setData(Qt::UserRole + 1, n); + n++; } } } @@ -175,13 +180,74 @@ void Main::refresh() for (auto i: m_myKeys) { u256 b = m_client->state().balance(i.address()); - ui->ourAccounts->addItem(QString("%1 @ %2").arg(formatBalance(b).c_str()).arg(asHex(i.address().asArray()).c_str())); + ui->ourAccounts->addItem(QString("%1 @ %2").arg(formatBalance(b).c_str()).arg(i.address().abridged().c_str())); totalBalance += b; } ui->balance->setText(QString::fromStdString(formatBalance(totalBalance))); m_client->unlock(); } +void Main::on_blocks_currentItemChanged() +{ + ui->info->clear(); + m_client->lock(); + if (auto item = ui->blocks->currentItem()) + { + auto hba = item->data(Qt::UserRole).toByteArray(); + assert(hba.size() == 32); + auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer); + auto details = m_client->blockChain().details(h); + auto blockData = m_client->blockChain().block(h); + auto block = RLP(blockData); + BlockInfo info(blockData); + + stringstream s; + + if (item->data(Qt::UserRole + 1).isNull()) + { + char timestamp[64]; + time_t rawTime = (time_t)(uint64_t)info.timestamp; + strftime(timestamp, 64, "%c", localtime(&rawTime)); + s << "" << timestamp << ": " << h; + s << "   #" << details.number << ""; + s << "   D/TD: 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
Coinbase: " << info.coinbaseAddress << ""; + s << "   TXs: " << block[1].itemCount() << ""; + s << "   Children: " << details.children.size() << ""; + s << "
State: " << info.stateRoot << ""; + s << "
nonce: " << info.nonce << ""; + s << "
Transactions: " << block[1].itemCount() << " @" << info.sha3Transactions << ""; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << ""; + } + else + { + unsigned txi = item->data(Qt::UserRole + 1).toInt(); + Transaction tx(block[1][txi].data()); + h256 th = tx.sha3(); + s << "" << th << "
"; + s << h << "[" << txi << "]"; + s << "
From: " << tx.safeSender() << ""; + if (tx.receiveAddress) + s << "   To: " << tx.receiveAddress << ""; + else + s << "   Creates: " << right160(th) << ""; + s << "
Value: " << formatBalance(tx.value) << ""; + s << "   #" << tx.nonce << ""; + if (tx.data.size()) + { + s << "
Data:   "; +// for (auto i: tx.data) +// s << "0x" << hex << i << " "; + s << "
" << disassemble(tx.data); + } + } + + + ui->info->appendHtml(QString::fromStdString(s.str())); + } + m_client->unlock(); +} + void Main::on_idealPeers_valueChanged() { if (m_client->peerServer()) diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 0a76c6c75..2fec721c8 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -38,6 +38,7 @@ private slots: void on_value_valueChanged() { updateFee(); } void on_valueUnits_currentIndexChanged() { updateFee(); } void on_log_doubleClicked(); + void on_blocks_currentItemChanged(); void on_about_triggered(); void on_quit_triggered() { close(); } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 99565a316..5f811d1bc 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -96,7 +96,7 @@ void Client::stopMining() void Client::transact(Secret _secret, Address _dest, u256 _amount, u256s _data) { - lock_guard l(m_lock); + lock_guard l(m_lock); Transaction t; t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); t.receiveAddress = _dest; @@ -119,7 +119,7 @@ void Client::work() { m_net->process(); - lock_guard l(m_lock); + lock_guard l(m_lock); if (m_net->sync(m_bc, m_tq, m_stateDB)) changed = true; } @@ -132,7 +132,7 @@ void Client::work() // all blocks. // Resynchronise state with block chain & trans { - lock_guard l(m_lock); + lock_guard l(m_lock); if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) { if (m_doMine) @@ -154,7 +154,7 @@ void Client::work() { if (m_restartMining) { - lock_guard l(m_lock); + lock_guard l(m_lock); m_postMine.commitToMine(m_bc); } @@ -169,7 +169,7 @@ void Client::work() if (mineInfo.completed) { // Import block. - lock_guard l(m_lock); + lock_guard l(m_lock); m_bc.attemptImport(m_postMine.blockData(), m_stateDB); m_mineProgress.best = 0; m_changed = true; diff --git a/libethereum/Client.h b/libethereum/Client.h index c67b41e75..5c9b64b0f 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -140,7 +140,7 @@ private: std::thread* m_work; ///< The work thread. - std::mutex m_lock; + std::recursive_mutex m_lock; enum { Active = 0, Deleting, Deleted } m_workState = Active; bool m_doMine = false; ///< Are we supposed to be mining? MineProgress m_mineProgress; diff --git a/libethereum/Common.h b/libethereum/Common.h index d2fee7121..24fb8540c 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -118,7 +118,7 @@ public: FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; } FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; } - std::string abridged() const { return asHex(ref().cropped(0, 4)); } + std::string abridged() const { return asHex(ref().cropped(0, 4)) + ".."; } byte& operator[](unsigned _i) { return m_data[_i]; } byte operator[](unsigned _i) const { return m_data[_i]; } diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index 19700aa25..7ae74b150 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -52,7 +52,30 @@ u256s eth::assemble(std::string const& _code) else cwarn << "Unknown assembler token" << t; } - } return ret; } + +string eth::disassemble(u256s const& _mem) +{ + stringstream ret; + uint numerics = 0; + for (auto it = _mem.begin(); it != _mem.end(); ++it) + { + u256 n = *it; + auto iit = c_instructionInfo.find((Instruction)(uint)n); + if (numerics || iit == c_instructionInfo.end() || (u256)(uint)iit->first != n) // not an instruction or expecting an argument... + { + if (numerics) + numerics--; + ret << " 0x" << hex << n; + } + else + { + auto const& ii = iit->second; + ret << " " << ii.name; + numerics = ii.additional; + } + } + return ret.str(); +} diff --git a/libethereum/Instruction.h b/libethereum/Instruction.h index fe5e37edc..2fbaf3376 100644 --- a/libethereum/Instruction.h +++ b/libethereum/Instruction.h @@ -33,8 +33,8 @@ enum class Instruction: uint8_t { STOP = 0x00, ///< halts execution ADD, - SUB, MUL, + SUB, DIV, SDIV, MOD, @@ -47,6 +47,7 @@ enum class Instruction: uint8_t GE, EQ, NOT, + MYADDRESS, ///< pushes the transaction sender TXSENDER, ///< pushes the transaction sender TXVALUE , ///< pushes the transaction value TXDATAN, ///< pushes the number of data items @@ -83,6 +84,69 @@ enum class Instruction: uint8_t SUICIDE = 0x3f }; +struct InstructionInfo +{ + std::string name; + int additional; + int args; + int ret; +}; + +static const std::map c_instructionInfo = +{ + { Instruction::STOP, { "STOP", 0, 0, 0 } }, + { Instruction::ADD, { "ADD", 0, 2, 1 } }, + { Instruction::SUB, { "SUB", 0, 2, 1 } }, + { Instruction::MUL, { "MUL", 0, 2, 1 } }, + { Instruction::DIV, { "DIV", 0, 2, 1 } }, + { Instruction::SDIV, { "SDIV", 0, 2, 1 } }, + { Instruction::MOD, { "MOD", 0, 2, 1 } }, + { Instruction::SMOD, { "SMOD", 0, 2, 1 } }, + { Instruction::EXP, { "EXP", 0, 2, 1 } }, + { Instruction::NEG, { "NEG", 0, 1, 1 } }, + { Instruction::LT, { "LT", 0, 2, 1 } }, + { Instruction::LE, { "LE", 0, 2, 1 } }, + { Instruction::GT, { "GT", 0, 2, 1 } }, + { Instruction::GE, { "GE", 0, 2, 1 } }, + { Instruction::EQ, { "EQ", 0, 2, 1 } }, + { Instruction::NOT, { "NOT", 0, 1, 1 } }, + { Instruction::MYADDRESS, { "MYADDRESS", 0, 0, 1 } }, + { Instruction::TXSENDER, { "TXSENDER", 0, 0, 1 } }, + { Instruction::TXVALUE, { "TXVALUE", 0, 0, 1 } }, + { Instruction::TXDATAN, { "TXDATAN", 0, 0, 1 } }, + { Instruction::TXDATA, { "TXDATA", 0, 1, 1 } }, + { Instruction::BLK_PREVHASH, { "BLK_PREVHASH", 0, 0, 1 } }, + { Instruction::BLK_COINBASE, { "BLK_COINBASE", 0, 0, 1 } }, + { Instruction::BLK_TIMESTAMP, { "BLK_TIMESTAMP", 0, 0, 1 } }, + { Instruction::BLK_NUMBER, { "BLK_NUMBER", 0, 0, 1 } }, + { Instruction::BLK_DIFFICULTY, { "BLK_DIFFICULTY", 0, 0, 1 } }, + { Instruction::BLK_NONCE, { "BLK_NONCE", 0, 0, 1 } }, + { Instruction::BASEFEE, { "BASEFEE", 0, 0, 1 } }, + { Instruction::SHA256, { "SHA256", 0, -1, 1 } }, + { Instruction::RIPEMD160, { "RIPEMD160", 0, -1, 1 } }, + { Instruction::ECMUL, { "ECMUL", 0, 3, 1 } }, + { Instruction::ECADD, { "ECADD", 0, 4, 1 } }, + { Instruction::ECSIGN, { "ECSIGN", 0, 2, 1 } }, + { Instruction::ECRECOVER, { "ECRECOVER", 0, 4, 1 } }, + { Instruction::ECVALID, { "ECVALID", 0, 2, 1 } }, + { Instruction::SHA3, { "SHA3", 0, -1, 1 } }, + { Instruction::PUSH, { "PUSH", 1, 0, 1 } }, + { Instruction::POP, { "POP", 0, 1, 0 } }, + { Instruction::DUP, { "DUP", 0, 1, 2 } }, + { Instruction::SWAP, { "SWAP", 0, 2, 2 } }, + { Instruction::MLOAD, { "MLOAD", 0, 1, 1 } }, + { Instruction::MSTORE, { "MSTORE", 0, 2, 0 } }, + { Instruction::SLOAD, { "SLOAD", 0, 1, 1 } }, + { Instruction::SSTORE, { "SSTORE", 0, 2, 0 } }, + { Instruction::JMP, { "JMP", 0, 1, 0 } }, + { Instruction::JMPI, { "JMPI", 0, 2, 0 } }, + { Instruction::IND, { "IND", 0, 0, 1 } }, + { Instruction::EXTRO, { "EXTRO", 0, 2, 1 } }, + { Instruction::BALANCE, { "BALANCE", 0, 1, 1 } }, + { Instruction::MKTX, { "MKTX", 0, 4, 0 } }, + { Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} } +}; + static const std::map c_instructions = { { "STOP", Instruction::STOP }, @@ -101,6 +165,7 @@ static const std::map c_instructions = { "GE", Instruction::GE }, { "EQ", Instruction::EQ }, { "NOT", Instruction::NOT }, + { "MYADDRESS", Instruction::MYADDRESS }, { "TXSENDER", Instruction::TXSENDER }, { "TXVALUE", Instruction::TXVALUE }, { "TXDATAN", Instruction::TXDATAN }, @@ -138,5 +203,6 @@ static const std::map c_instructions = }; u256s assemble(std::string const& _code); +std::string disassemble(u256s const& _mem); } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index b02c0d604..a493f4417 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -897,9 +897,9 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s stack.back() = stack.back() ? 0 : 1; stack.pop_back(); break; - /*case Instruction::MYADDRESS: + case Instruction::MYADDRESS: stack.push_back((u160)_myAddress); - break;*/ + break; case Instruction::TXSENDER: stack.push_back((u160)_txSender); break; diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 893433cc7..cf8ff3140 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -40,6 +40,18 @@ Transaction::Transaction(bytesConstRef _rlpData) vrs = Signature{ rlp[4].toInt(), rlp[5].toInt(), rlp[6].toInt() }; } +Address Transaction::safeSender() const noexcept +{ + try + { + return sender(); + } + catch (...) + { + return Address(); + } +} + Address Transaction::sender() const { secp256k1_start(); diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 4f769d8c4..d593335cf 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -47,6 +47,7 @@ struct Transaction u256s data; Signature vrs; + Address safeSender() const noexcept; Address sender() const; void sign(Secret _priv); @@ -63,11 +64,17 @@ using Transactions = std::vector; inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) { - _out << "{" << _t.receiveAddress << "/" << _t.nonce << "*" << _t.value; + _out << "{"; + if (_t.receiveAddress) + _out << _t.receiveAddress.abridged(); + else + _out << "[CREATE]"; + + _out << "/" << _t.nonce << "*" << _t.value; Address s; try { - _out << "<-" << _t.sender(); + _out << "<-" << _t.sender().abridged(); } catch (...) {} _out << "}";