diff --git a/alephzero/Main.cpp b/alephzero/Main.cpp index bad35c382..55cd3fe91 100644 --- a/alephzero/Main.cpp +++ b/alephzero/Main.cpp @@ -51,6 +51,8 @@ void Main::readSettings() } m_client.setAddress(m_myKey.address()); + writeSettings(); + /*for (uint i = 0; !s.value(QString("peer%1").arg(i)).isNull(); ++i) { s.value(QString("peer%1").arg(i)).toString(); @@ -59,6 +61,7 @@ void Main::readSettings() void Main::refresh() { + m_client.lock(); ui->balance->setText(QString::fromStdString(toString(m_client.state().balance(m_myKey.address()))) + " wei"); ui->peerCount->setText(QString::fromStdString(toString(m_client.peerCount())) + " peer(s)"); ui->address->setText(QString::fromStdString(asHex(m_client.state().address().asArray()))); @@ -68,7 +71,42 @@ void Main::refresh() auto d = m_client.blockChain().details(); auto diff = BlockInfo(m_client.blockChain().block()).difficulty; - ui->blockChain->setText(QString("%1 blocks @ (%3) - %2").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff))); + ui->blockChain->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 wei @ %2").arg(toString(i.second).c_str()).arg(asHex(i.first.asArray()).c_str())); + + ui->transactionQueue->clear(); + for (pair const& i: m_client.transactionQueue().transactions()) + { + Transaction t(i.second); + ui->transactionQueue->addItem(QString("%1 wei (%2 fee) @ %3 <- %4") + .arg(toString(t.value).c_str()) + .arg(toString(t.fee).c_str()) + .arg(asHex(t.receiveAddress.asArray()).c_str()) + .arg(asHex(t.sender().asArray()).c_str()) ); + } + + ui->transactions->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())); + for (auto const& i: RLP(bc.block(h))[1]) + { + Transaction t(i.data()); + ui->transactions->addItem(QString("%1 wei (%2 fee) @ %3 <- %4") + .arg(toString(t.value).c_str()) + .arg(toString(t.fee).c_str()) + .arg(asHex(t.receiveAddress.asArray()).c_str()) + .arg(asHex(t.sender().asArray()).c_str()) ); + } + } + + m_client.unlock(); } void Main::on_net_toggled() @@ -81,7 +119,7 @@ void Main::on_net_toggled() void Main::on_connect_clicked() { - QString s = QInputDialog::getText(this, "Enter first peer", "Enter a peer to which a connection may be made", QLineEdit::Normal, "127.0.0.1:30303"); + QString s = QInputDialog::getText(this, "Connect to a Network Peer", "Enter a peer to which a connection may be made:", QLineEdit::Normal, "127.0.0.1:30303"); string host = s.section(":", 0, 0).toStdString(); short port = s.section(":", 1).toInt(); m_client.connect(host, port); @@ -97,7 +135,7 @@ void Main::on_mine_toggled() void Main::on_send_clicked() { - Secret s = Secret(fromUserHex(ui->address->text().toStdString())); + Secret s = m_myKey.secret(); Address r = Address(fromUserHex(ui->destination->text().toStdString())); m_client.transact(s, r, ui->value->value(), ui->fee->value()); refresh(); @@ -106,6 +144,6 @@ void Main::on_send_clicked() void Main::on_create_clicked() { KeyPair p = KeyPair::create(); - QString s = QString::fromStdString("New key:\n" + asHex(p.secret().asArray()) + "\nAddress: " + asHex(p.address().asArray())); - QMessageBox::information(this, "New Key", s, QMessageBox::Ok); + QString s = QString::fromStdString("The new secret key is:\n" + asHex(p.secret().asArray()) + "\n\nAddress:\n" + asHex(p.address().asArray())); + QMessageBox::information(this, "Create Key", s, QMessageBox::Ok); } diff --git a/alephzero/Main.h b/alephzero/Main.h index 0ee36c273..cd44f5fe1 100644 --- a/alephzero/Main.h +++ b/alephzero/Main.h @@ -3,6 +3,7 @@ #include #include +#include #include namespace Ui { @@ -37,6 +38,7 @@ private: eth::KeyPair m_myKey; std::vector m_peers; + QMutex m_guiLock; QTimer* m_refresh; }; diff --git a/alephzero/Main.ui b/alephzero/Main.ui index fd91b0df1..9afb19d59 100644 --- a/alephzero/Main.ui +++ b/alephzero/Main.ui @@ -11,7 +11,7 @@ - Main + AlephZero Etherium Client true @@ -158,17 +158,14 @@ Qt::Horizontal - - - true - - QFrame::NoFrame + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 014ef16af..3dbda439c 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -100,6 +100,8 @@ public: Address coinbaseAddress(h256 _hash) const; Address coinbaseAddress() const { return coinbaseAddress(currentHash()); } + h256 genesisHash() const { return m_genesisHash; } + private: /// Get fully populated from disk DB. mutable std::map m_details; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 2b71aeb5c..c6a486a70 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -83,6 +83,7 @@ void Client::stopMining() void Client::transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u256s _data) { + m_lock.lock(); Transaction t; t.nonce = m_s.transactionsFrom(toAddress(_secret)); t.receiveAddress = _dest; @@ -91,10 +92,12 @@ void Client::transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u2 t.data = _data; t.sign(_secret); m_tq.attemptImport(t.rlp()); + m_lock.unlock(); } void Client::work() { + m_lock.lock(); // Process network events. // Synchronise block chain with network. // Will broadcast any of our (new) transactions and blocks, and collect & add any of their (new) transactions and blocks. @@ -110,9 +113,11 @@ void Client::work() m_s.sync(m_bc); // Resynchronise state with block chain & trans m_s.sync(m_tq); + m_lock.unlock(); if (m_doMine) { // Mine for a while. + m_s.commitToMine(m_bc); MineInfo mineInfo = m_s.mine(100); m_mineProgress.best = max(m_mineProgress.best, mineInfo.best); m_mineProgress.current = mineInfo.best; @@ -121,10 +126,22 @@ void Client::work() if (mineInfo.completed()) { // Import block. + m_lock.lock(); m_bc.attemptImport(m_s.blockData(), m_stateDB); m_mineProgress.best = 0; + m_lock.unlock(); } } else usleep(100000); } + +void Client::lock() +{ + m_lock.lock(); +} + +void Client::unlock() +{ + m_lock.unlock(); +} diff --git a/libethereum/Client.h b/libethereum/Client.h index 12f341cdc..abba4540d 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -48,6 +48,9 @@ public: void transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u256s _data = u256s()); + void lock(); + void unlock(); + State const& state() const { return m_s; } BlockChain const& blockChain() const { return m_bc; } TransactionQueue const& transactionQueue() const { return m_tq; } @@ -74,6 +77,7 @@ private: State m_s; ///< The present state of the client. PeerServer* m_net = nullptr; ///< Should run in background and send us events when blocks found and allow us to send blocks as required. std::thread* m_work; ///< The work thread. + std::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.cpp b/libethereum/Common.cpp index 94ac77247..5f539012b 100644 --- a/libethereum/Common.cpp +++ b/libethereum/Common.cpp @@ -175,7 +175,7 @@ KeyPair KeyPair::create() static std::mt19937_64 s_eng(time(0)); std::uniform_int_distribution d(0, 255); KeyPair ret; - for (uint i = 0; i < 20; ++i) + for (uint i = 0; i < 32; ++i) ret.m_secret[i] = d(s_eng); ret.m_address = toAddress(ret.m_secret); return ret; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e1f782d49..3d55e228f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -157,10 +157,6 @@ void State::sync(BlockChain const& _bc, h256 _block) exit(1); } - // TODO: why are the hashes different when the essentials are the same? -// cout << bi << endl; -// cout << m_currentBlock << endl; - if (bi == m_currentBlock) { // We mined the last block. @@ -199,6 +195,18 @@ void State::sync(BlockChain const& _bc, h256 _block) } } +map State::addresses() const +{ + map ret; + for (auto i: m_cache) + if (i.second.type() != AddressType::Dead) + ret[i.first] = i.second.balance(); + for (auto const& i: m_state) + if (m_cache.find(i.first) == m_cache.end()) + ret[i.first] = RLP(i.second)[0].toInt(); + return ret; +} + void State::resetCurrent() { m_transactions.clear(); @@ -221,8 +229,7 @@ void State::sync(TransactionQueue& _tq) // don't have it yet! Execute it now. try { - Transaction t(i.second); - execute(t, t.sender()); + execute(i.second); } catch (InvalidNonce in) { @@ -291,11 +298,11 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _ // Commit all cached state changes to the state trie. commit(); -// cout << m_state << endl << TrieDB(&m_db, m_currentBlock.stateRoot); - // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != rootHash()) { + cout << "*** BAD STATE ROOT!" << endl; + cout << m_state << endl << TrieDB(&m_db, m_currentBlock.stateRoot); // Rollback the trie. m_db.rollback(); throw InvalidStateRoot(); @@ -322,6 +329,9 @@ u256 State::playback(bytesConstRef _block, BlockInfo const& _grandParent, bool _ // (i.e. all the transactions we executed). void State::commitToMine(BlockChain const& _bc) { + if (m_currentBlock.sha3Transactions != h256() || m_currentBlock.sha3Uncles != h256()) + return; + RLPStream uncles; Addresses uncleAddresses; @@ -483,7 +493,7 @@ bool State::execute(bytesConstRef _rlp) try { Transaction t(_rlp); - execute(t, t.sender()); + executeBare(t, t.sender()); // Add to the user-originated transactions that we've executed. // NOTE: Here, contract-originated transactions will not get added to the transaction list. @@ -510,7 +520,7 @@ void State::applyRewards(Addresses const& _uncleAddresses) addBalance(m_currentBlock.coinbaseAddress, r); } -void State::execute(Transaction const& _t, Address _sender) +void State::executeBare(Transaction const& _t, Address _sender) { // Entry point for a contract-originated transaction. @@ -1050,7 +1060,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _ } t.nonce = transactionsFrom(_myAddress); - execute(t, _myAddress); + executeBare(t, _myAddress); break; } diff --git a/libethereum/State.h b/libethereum/State.h index 32e413614..1edb7cf71 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -59,6 +59,9 @@ public: static Overlay openDB(std::string _path, bool _killExisting = false); static Overlay openDB(bool _killExisting = false) { return openDB(std::string(), _killExisting); } + /// @returns the set containing all addresses currently in use in Ethereum. + std::map addresses() const; + /// Cancels transactions and rolls back the state to the end of the previous block. /// @warning This will only work for on any transactions after you called the last commitToMine(). /// It's one or the other. @@ -68,7 +71,9 @@ public: /// Commits all transactions into the trie, compiles uncles and transactions list, applies all /// rewards and populates the current block header with the appropriate hashes. /// The only thing left to do after this is to actually mine(). - /// @warning Only call this once! + /// + /// This may be called multiple times and without issue, however, until the current state is cleared, + /// calls after the first are ignored. void commitToMine(BlockChain const& _bc); /// Attempt to find valid nonce for block that this state represents. @@ -166,7 +171,7 @@ private: /// Execute a decoded transaction object, given a sender. /// This will append @a _t to the transaction list and change the state accordingly. - void execute(Transaction const& _t, Address _sender); + void executeBare(Transaction const& _t, Address _sender); /// Execute a contract transaction. void execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* o_totalFee);