Browse Source

Thread-safe client and remove old State const&-based APIs.

cl-refactor
Gav Wood 10 years ago
parent
commit
eb360674cf
  1. 78
      alethzero/MainWin.cpp
  2. 2
      alethzero/MainWin.h
  3. 16
      eth/EthStubServer.cpp
  4. 49
      eth/main.cpp
  5. 134
      libethereum/Client.cpp
  6. 76
      libethereum/Client.h
  7. 9
      libethereum/State.h
  8. 30
      libqethereum/QEthereum.cpp
  9. 66
      neth/main.cpp
  10. 19
      walleth/MainWin.cpp

78
alethzero/MainWin.cpp

@ -257,7 +257,7 @@ void Main::installWatches()
void Main::installNameRegWatch() void Main::installNameRegWatch()
{ {
m_client->uninstallWatch(m_nameRegFilter); m_client->uninstallWatch(m_nameRegFilter);
m_nameRegFilter = installWatch(eth::TransactionFilter().altered((u160)state().storage(c_config, 0)), [=](){ onNameRegChange(); }); m_nameRegFilter = installWatch(eth::TransactionFilter().altered((u160)m_client->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
} }
void Main::installCurrenciesWatch() void Main::installCurrenciesWatch()
@ -446,11 +446,11 @@ Address Main::fromString(QString const& _a) const
memset(n.data() + sn.size(), 0, 32 - sn.size()); memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size()) if (_a.size())
{ {
if (h160 nameReg = (u160)state().storage(c_config, 0)) if (h160 nameReg = (u160)m_client->stateAt(c_config, 0))
if (h256 a = state().storage(nameReg, n)) if (h256 a = m_client->stateAt(nameReg, n))
return right160(a); return right160(a);
if (h256 a = state().storage(m_nameReg, n)) if (h256 a = m_client->stateAt(m_nameReg, n))
return right160(a); return right160(a);
} }
if (_a.size() == 40) if (_a.size() == 40)
@ -493,12 +493,9 @@ void Main::writeSettings()
s.setValue("port", ui->port->value()); s.setValue("port", ui->port->value());
s.setValue("url", ui->urlEdit->text()); s.setValue("url", ui->urlEdit->text());
if (m_client->peerServer()) bytes d = m_client->savePeers();
{ if (d.size())
bytes d = m_client->peerServer()->savePeers();
m_peers = QByteArray((char*)d.data(), (int)d.size()); m_peers = QByteArray((char*)d.data(), (int)d.size());
}
s.setValue("peers", m_peers); s.setValue("peers", m_peers);
s.setValue("nameReg", ui->nameReg->text()); s.setValue("nameReg", ui->nameReg->text());
@ -597,7 +594,6 @@ void Main::on_preview_triggered()
void Main::refreshMining() void Main::refreshMining()
{ {
eth::ClientGuard g(m_client.get());
eth::MineProgress p = m_client->miningProgress(); eth::MineProgress p = m_client->miningProgress();
ui->mineStatus->setText(m_client->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining"); ui->mineStatus->setText(m_client->isMining() ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Not mining");
if (!ui->miningView->isVisible()) if (!ui->miningView->isVisible())
@ -652,11 +648,6 @@ void Main::refreshNetwork()
ui->peers->addItem(QString("%3 ms - %1:%2 - %4").arg(i.host.c_str()).arg(i.port).arg(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()).arg(i.clientVersion.c_str())); ui->peers->addItem(QString("%3 ms - %1:%2 - %4").arg(i.host.c_str()).arg(i.port).arg(chrono::duration_cast<chrono::milliseconds>(i.lastPing).count()).arg(i.clientVersion.c_str()));
} }
eth::State const& Main::state() const
{
return ui->preview->isChecked() ? m_client->postState() : m_client->state();
}
void Main::refreshAll() void Main::refreshAll()
{ {
refreshDestination(); refreshDestination();
@ -760,8 +751,6 @@ static bool transactionMatch(string const& _f, Transaction const& _t)
void Main::refreshBlockChain() void Main::refreshBlockChain()
{ {
cwatch << "refreshBlockChain()"; cwatch << "refreshBlockChain()";
eth::ClientGuard g(m_client.get());
auto const& st = state();
QByteArray oldSelected = ui->blocks->count() ? ui->blocks->currentItem()->data(Qt::UserRole).toByteArray() : QByteArray(); QByteArray oldSelected = ui->blocks->count() ? ui->blocks->currentItem()->data(Qt::UserRole).toByteArray() : QByteArray();
ui->blocks->clear(); ui->blocks->clear();
@ -794,7 +783,7 @@ void Main::refreshBlockChain()
.arg(render(t.safeSender())) .arg(render(t.safeSender()))
.arg(render(t.receiveAddress)) .arg(render(t.receiveAddress))
.arg((unsigned)t.nonce) .arg((unsigned)t.nonce)
.arg(st.addressHasCode(t.receiveAddress) ? '*' : '-') : .arg(m_client->codeAt(t.receiveAddress).size() ? '*' : '-') :
QString(" %2 +> %3: %1 [%4]") QString(" %2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str()) .arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender())) .arg(render(t.safeSender()))
@ -933,13 +922,12 @@ string Main::renderDiff(eth::StateDiff const& _d) const
void Main::on_transactionQueue_currentItemChanged() void Main::on_transactionQueue_currentItemChanged()
{ {
ui->pendingInfo->clear(); ui->pendingInfo->clear();
eth::ClientGuard g(m_client.get());
stringstream s; stringstream s;
int i = ui->transactionQueue->currentRow(); int i = ui->transactionQueue->currentRow();
if (i >= 0 && i < (int)m_client->postState().pending().size()) if (i >= 0 && i < (int)m_client->pending().size())
{ {
Transaction tx(m_client->postState().pending()[i]); Transaction tx(m_client->pending()[i]);
auto ss = tx.safeSender(); auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce)); h256 th = sha3(rlpList(ss, tx.nonce));
s << "<h3>" << th << "</h3>"; s << "<h3>" << th << "</h3>";
@ -967,7 +955,7 @@ void Main::on_transactionQueue_currentItemChanged()
// s << "Pre: " << fs.rootHash() << "<br/>"; // s << "Pre: " << fs.rootHash() << "<br/>";
// s << "Post: <b>" << ts.rootHash() << "</b>"; // s << "Post: <b>" << ts.rootHash() << "</b>";
s << renderDiff(m_client->postState().pendingDiff(i)); s << renderDiff(m_client->diff(i, 0));
} }
ui->pendingInfo->setHtml(QString::fromStdString(s.str())); ui->pendingInfo->setHtml(QString::fromStdString(s.str()));
@ -1002,7 +990,6 @@ void Main::on_blocks_currentItemChanged()
ui->debugCurrent->setEnabled(false); ui->debugCurrent->setEnabled(false);
ui->debugDumpState->setEnabled(false); ui->debugDumpState->setEnabled(false);
ui->debugDumpStatePre->setEnabled(false); ui->debugDumpStatePre->setEnabled(false);
eth::ClientGuard g(m_client.get());
if (auto item = ui->blocks->currentItem()) if (auto item = ui->blocks->currentItem())
{ {
auto hba = item->data(Qt::UserRole).toByteArray(); auto hba = item->data(Qt::UserRole).toByteArray();
@ -1069,10 +1056,7 @@ void Main::on_blocks_currentItemChanged()
if (tx.data.size()) if (tx.data.size())
s << eth::memDump(tx.data, 16, true); s << eth::memDump(tx.data, 16, true);
} }
auto st = eth::State(m_client->state().db(), m_client->blockChain(), h); s << renderDiff(m_client->diff(txi, h));
eth::State before = st.fromPending(txi);
eth::State after = st.fromPending(txi + 1);
s << renderDiff(before.diff(after));
ui->debugCurrent->setEnabled(true); ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true); ui->debugDumpState->setEnabled(true);
ui->debugDumpStatePre->setEnabled(true); ui->debugDumpStatePre->setEnabled(true);
@ -1084,7 +1068,6 @@ void Main::on_blocks_currentItemChanged()
void Main::on_debugCurrent_triggered() void Main::on_debugCurrent_triggered()
{ {
eth::ClientGuard g(m_client.get());
if (auto item = ui->blocks->currentItem()) if (auto item = ui->blocks->currentItem())
{ {
auto hba = item->data(Qt::UserRole).toByteArray(); auto hba = item->data(Qt::UserRole).toByteArray();
@ -1093,11 +1076,10 @@ void Main::on_debugCurrent_triggered()
if (!item->data(Qt::UserRole + 1).isNull()) if (!item->data(Qt::UserRole + 1).isNull())
{ {
eth::State st(m_client->state().db(), m_client->blockChain(), h);
unsigned txi = item->data(Qt::UserRole + 1).toInt(); unsigned txi = item->data(Qt::UserRole + 1).toInt();
m_executiveState = st.fromPending(txi); m_executiveState = m_client->state(txi, h);
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState)); m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState));
Transaction t = st.pending()[txi]; Transaction t = m_client->pending()[txi];
auto r = t.rlp(); auto r = t.rlp();
populateDebugger(&r); populateDebugger(&r);
m_currentExecution.reset(); m_currentExecution.reset();
@ -1107,7 +1089,6 @@ void Main::on_debugCurrent_triggered()
void Main::on_debugDumpState_triggered(int _add) void Main::on_debugDumpState_triggered(int _add)
{ {
eth::ClientGuard g(m_client.get());
if (auto item = ui->blocks->currentItem()) if (auto item = ui->blocks->currentItem())
{ {
auto hba = item->data(Qt::UserRole).toByteArray(); auto hba = item->data(Qt::UserRole).toByteArray();
@ -1120,9 +1101,8 @@ void Main::on_debugDumpState_triggered(int _add)
ofstream f(fn.toStdString()); ofstream f(fn.toStdString());
if (f.is_open()) if (f.is_open())
{ {
eth::State st(m_client->state().db(), m_client->blockChain(), h);
unsigned txi = item->data(Qt::UserRole + 1).toInt(); unsigned txi = item->data(Qt::UserRole + 1).toInt();
f << st.fromPending(txi + _add) << endl; f << m_client->state(txi + _add, h) << endl;
} }
} }
} }
@ -1178,20 +1158,19 @@ void Main::populateDebugger(eth::bytesConstRef _r)
void Main::on_contracts_currentItemChanged() void Main::on_contracts_currentItemChanged()
{ {
ui->contractInfo->clear(); ui->contractInfo->clear();
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();
assert(hba.size() == 20); assert(hba.size() == 20);
auto h = h160((byte const*)hba.data(), h160::ConstructFromPointer); auto address = h160((byte const*)hba.data(), h160::ConstructFromPointer);
stringstream s; stringstream s;
try try
{ {
auto storage = state().storage(h); auto storage = m_client->storageAt(address);
for (auto const& i: storage) for (auto const& i: storage)
s << "@" << showbase << hex << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second).toStdString() << "<br/>"; s << "@" << showbase << hex << prettyU256(i.first).toStdString() << "&nbsp;&nbsp;&nbsp;&nbsp;" << showbase << hex << prettyU256(i.second).toStdString() << "<br/>";
s << "<h4>Body Code</h4>" << disassemble(state().code(h)); s << "<h4>Body Code</h4>" << disassemble(m_client->codeAt(address));
ui->contractInfo->appendHtml(QString::fromStdString(s.str())); ui->contractInfo->appendHtml(QString::fromStdString(s.str()));
} }
catch (eth::InvalidTrie) catch (eth::InvalidTrie)
@ -1203,8 +1182,7 @@ void Main::on_contracts_currentItemChanged()
void Main::on_idealPeers_valueChanged() void Main::on_idealPeers_valueChanged()
{ {
if (m_client->peerServer()) m_client->setIdealPeerCount(ui->idealPeers->value());
m_client->peerServer()->setIdealPeerCount(ui->idealPeers->value());
} }
void Main::on_ourAccounts_doubleClicked() void Main::on_ourAccounts_doubleClicked()
@ -1288,7 +1266,7 @@ void Main::on_data_textChanged()
errs.append("<div style=\"border-left: 6px solid #c00; margin-top: 2px\">" + QString::fromStdString(i).toHtmlEscaped() + "</div>"); errs.append("<div style=\"border-left: 6px solid #c00; margin-top: 2px\">" + QString::fromStdString(i).toHtmlEscaped() + "</div>");
} }
ui->code->setHtml(errs + lll + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); ui->code->setHtml(errs + lll + "<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped());
ui->gas->setMinimum((qint64)state().createGas(m_data.size(), 0)); ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 0));
if (!ui->gas->isEnabled()) if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas); ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true); ui->gas->setEnabled(true);
@ -1344,9 +1322,9 @@ void Main::on_data_textChanged()
s = s.mid(1); s = s.mid(1);
} }
ui->code->setHtml(QString::fromStdString(eth::memDump(m_data, 8, true))); ui->code->setHtml(QString::fromStdString(eth::memDump(m_data, 8, true)));
if (m_client->postState().addressHasCode(fromString(ui->destination->currentText()))) if (m_client->codeAt(fromString(ui->destination->currentText()), 0).size())
{ {
ui->gas->setMinimum((qint64)state().callGas(m_data.size(), 1)); ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 1));
if (!ui->gas->isEnabled()) if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas); ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true); ui->gas->setEnabled(true);
@ -1355,7 +1333,7 @@ void Main::on_data_textChanged()
{ {
if (ui->gas->isEnabled()) if (ui->gas->isEnabled())
m_backupGas = ui->gas->value(); m_backupGas = ui->gas->value();
ui->gas->setValue((qint64)state().callGas(m_data.size())); ui->gas->setValue((qint64)Client::txGas(m_data.size()));
ui->gas->setEnabled(false); ui->gas->setEnabled(false);
} }
} }
@ -1412,7 +1390,7 @@ void Main::updateFee()
bool ok = false; bool ok = false;
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (state().balance(i.address()) >= totalReq) if (m_client->balanceAt(i.address()) >= totalReq)
{ {
ok = true; ok = true;
break; break;
@ -1436,7 +1414,7 @@ void Main::on_net_triggered()
{ {
m_client->startNetwork(ui->port->value(), string(), 0, NodeMode::Full, ui->idealPeers->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked()); m_client->startNetwork(ui->port->value(), string(), 0, NodeMode::Full, ui->idealPeers->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked());
if (m_peers.size() && ui->usePast->isChecked()) if (m_peers.size() && ui->usePast->isChecked())
m_client->peerServer()->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size())); m_client->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
} }
else else
m_client->stopNetwork(); m_client->stopNetwork();
@ -1479,9 +1457,8 @@ void Main::on_mine_triggered()
void Main::on_send_clicked() void Main::on_send_clicked()
{ {
u256 totalReq = value() + fee(); u256 totalReq = value() + fee();
eth::ClientGuard l(&*m_client);
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (m_client->postState().balance(i.address()) >= totalReq) if (m_client->balanceAt(i.address(), 0) >= totalReq)
{ {
debugFinished(); debugFinished();
Secret s = i.secret(); Secret s = i.secret();
@ -1500,12 +1477,11 @@ void Main::on_debug_clicked()
try try
{ {
u256 totalReq = value() + fee(); u256 totalReq = value() + fee();
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->balanceAt(i.address()) >= totalReq)
{ {
Secret s = i.secret(); Secret s = i.secret();
m_executiveState = state(); m_executiveState = m_client->postState();
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState)); m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState));
Transaction t; Transaction t;
t.nonce = m_executiveState.transactionsFrom(toAddress(s)); t.nonce = m_executiveState.transactionsFrom(toAddress(s));

2
alethzero/MainWin.h

@ -156,8 +156,6 @@ private:
void alterDebugStateGroup(bool _enable) const; void alterDebugStateGroup(bool _enable) const;
eth::State const& state() const;
void updateFee(); void updateFee();
void readSettings(); void readSettings();
void writeSettings(); void writeSettings();

16
eth/EthStubServer.cpp

@ -60,14 +60,12 @@ Json::Value EthStubServer::procedures()
std::string EthStubServer::coinbase() std::string EthStubServer::coinbase()
{ {
ClientGuard g(&m_client);
return toJS(m_client.address()); return toJS(m_client.address());
} }
std::string EthStubServer::balanceAt(std::string const& _a) std::string EthStubServer::balanceAt(std::string const& _a)
{ {
ClientGuard g(&m_client); return toJS(m_client.balanceAt(jsToAddress(_a), 0));
return toJS(m_client.postState().balance(jsToAddress(_a)));
} }
Json::Value EthStubServer::check(Json::Value const& _as) Json::Value EthStubServer::check(Json::Value const& _as)
@ -85,7 +83,6 @@ Json::Value EthStubServer::check(Json::Value const& _as)
std::string EthStubServer::create(const std::string& _bCode, const std::string& _sec, const std::string& _xEndowment, const std::string& _xGas, const std::string& _xGasPrice) std::string EthStubServer::create(const std::string& _bCode, const std::string& _sec, const std::string& _xEndowment, const std::string& _xGas, const std::string& _xGasPrice)
{ {
ClientGuard g(&m_client);
Address ret = m_client.transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice)); Address ret = m_client.transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice));
return toJS(ret); return toJS(ret);
} }
@ -102,8 +99,7 @@ std::string EthStubServer::gasPrice()
bool EthStubServer::isContractAt(const std::string& _a) bool EthStubServer::isContractAt(const std::string& _a)
{ {
ClientGuard g(&m_client); return m_client.codeAt(jsToAddress(_a), 0).size();
return m_client.postState().addressHasCode(jsToAddress(_a));
} }
bool EthStubServer::isListening() bool EthStubServer::isListening()
@ -133,27 +129,23 @@ Json::Value EthStubServer::keys()
int EthStubServer::peerCount() int EthStubServer::peerCount()
{ {
ClientGuard g(&m_client);
return m_client.peerCount(); return m_client.peerCount();
} }
std::string EthStubServer::storageAt(const std::string& _a, const std::string& x) std::string EthStubServer::storageAt(const std::string& _a, const std::string& x)
{ {
ClientGuard g(&m_client); return toJS(m_client.stateAt(jsToAddress(_a), jsToU256(x), 0));
return toJS(m_client.postState().storage(jsToAddress(_a), jsToU256(x)));
} }
Json::Value EthStubServer::transact(const std::string& _aDest, const std::string& _bData, const std::string& _sec, const std::string& _xGas, const std::string& _xGasPrice, const std::string& _xValue) Json::Value EthStubServer::transact(const std::string& _aDest, const std::string& _bData, const std::string& _sec, const std::string& _xGas, const std::string& _xGasPrice, const std::string& _xValue)
{ {
ClientGuard g(&m_client);
m_client.transact(jsToSecret(_sec), jsToU256(_xValue), jsToAddress(_aDest), jsToBytes(_bData), jsToU256(_xGas), jsToU256(_xGasPrice)); m_client.transact(jsToSecret(_sec), jsToU256(_xValue), jsToAddress(_aDest), jsToBytes(_bData), jsToU256(_xGas), jsToU256(_xGasPrice));
return Json::Value(); return Json::Value();
} }
std::string EthStubServer::txCountAt(const std::string& _a) std::string EthStubServer::txCountAt(const std::string& _a)
{ {
ClientGuard g(&m_client); return toJS(m_client.countAt(jsToAddress(_a), 0));
return toJS(m_client.postState().transactionsFrom(jsToAddress(_a)));
} }
std::string EthStubServer::secretToAddress(const std::string& _a) std::string EthStubServer::secretToAddress(const std::string& _a)

49
eth/main.cpp

@ -341,7 +341,6 @@ int main(int argc, char** argv)
{ {
eth::uint port; eth::uint port;
iss >> port; iss >> port;
ClientGuard g(&c);
c.startNetwork((short)port); c.startNetwork((short)port);
} }
else if (cmd == "connect") else if (cmd == "connect")
@ -349,12 +348,10 @@ int main(int argc, char** argv)
string addr; string addr;
eth::uint port; eth::uint port;
iss >> addr >> port; iss >> addr >> port;
ClientGuard g(&c);
c.connect(addr, (short)port); c.connect(addr, (short)port);
} }
else if (cmd == "netstop") else if (cmd == "netstop")
{ {
ClientGuard g(&c);
c.stopNetwork(); c.stopNetwork();
} }
else if (cmd == "minestart") else if (cmd == "minestart")
@ -405,12 +402,10 @@ int main(int argc, char** argv)
} }
else if (cmd == "block") else if (cmd == "block")
{ {
ClientGuard g(&c);
cout << "Current block: " << c.blockChain().details().number; cout << "Current block: " << c.blockChain().details().number;
} }
else if (cmd == "peers") else if (cmd == "peers")
{ {
ClientGuard g(&c);
for (auto it: c.peers()) for (auto it: c.peers())
cout << it.host << ":" << it.port << ", " << it.clientVersion << ", " cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms" << std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
@ -418,12 +413,10 @@ int main(int argc, char** argv)
} }
else if (cmd == "balance") else if (cmd == "balance")
{ {
ClientGuard g(&c); cout << "Current balance: " << formatBalance(c.balanceAt(us.address(), 0)) << " = " << c.balanceAt(us.address(), 0) << " wei" << endl;
cout << "Current balance: " << formatBalance(c.postState().balance(us.address())) << " = " << c.postState().balance(us.address()) << " wei" << endl;
} }
else if (cmd == "transact") else if (cmd == "transact")
{ {
ClientGuard g(&c);
auto const& bc = c.blockChain(); auto const& bc = c.blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
@ -450,7 +443,7 @@ int main(int argc, char** argv)
cnote << ssbd.str(); cnote << ssbd.str();
int ssize = sechex.length(); int ssize = sechex.length();
int size = hexAddr.length(); int size = hexAddr.length();
u256 minGas = (u256)c.state().callGas(data.size(), 0); u256 minGas = (u256)Client::txGas(data.size(), 0);
if (size < 40) if (size < 40)
{ {
if (size > 0) if (size > 0)
@ -477,40 +470,28 @@ int main(int argc, char** argv)
} }
else if (cmd == "listContracts") else if (cmd == "listContracts")
{ {
ClientGuard g(&c); auto acs = c.addresses();
auto const& st = c.state();
auto acs = st.addresses();
string ss; string ss;
for (auto const& i: acs) for (auto const& i: acs)
{ if (c.codeAt(i, 0).size())
auto r = i.first;
if (st.addressHasCode(r))
{ {
ss = toString(r) + " : " + toString(formatBalance(i.second)) + " [" + toString((unsigned)st.transactionsFrom(i.first)) + "]"; ss = toString(i) + " : " + toString(c.balanceAt(i, 0)) + " [" + toString((unsigned)c.countAt(i)) + "]";
cout << ss << endl; cout << ss << endl;
} }
}
} }
else if (cmd == "listAccounts") else if (cmd == "listAccounts")
{ {
ClientGuard g(&c); auto acs = c.addresses();
auto const& st = c.state();
auto acs = st.addresses();
string ss; string ss;
for (auto const& i: acs) for (auto const& i: acs)
{ if (c.codeAt(i, 0).empty())
auto r = i.first;
if (!st.addressHasCode(r))
{ {
ss = toString(r) + pretty(r, st) + " : " + toString(formatBalance(i.second)) + " [" + toString((unsigned)st.transactionsFrom(i.first)) + "]"; ss = toString(i) + " : " + toString(c.balanceAt(i, 0)) + " [" + toString((unsigned)c.countAt(i)) + "]";
cout << ss << endl; cout << ss << endl;
} }
}
} }
else if (cmd == "send") else if (cmd == "send")
{ {
ClientGuard g(&c);
if (iss.peek() != -1) if (iss.peek() != -1)
{ {
string hexAddr; string hexAddr;
@ -529,23 +510,22 @@ int main(int argc, char** argv)
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
u256 minGas = (u256)c.state().callGas(0, 0); u256 minGas = (u256)Client::txGas(0, 0);
Address dest = h160(fromHex(hexAddr)); Address dest = h160(fromHex(hexAddr));
c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice);
} }
} }
else else
cwarn << "Require parameters: send ADDRESS AMOUNT"; cwarn << "Require parameters: send ADDRESS AMOUNT";
} }
else if (cmd == "contract") else if (cmd == "contract")
{ {
ClientGuard g(&c);
auto const& bc = c.blockChain(); auto const& bc = c.blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
if(iss.peek() != -1) { if (iss.peek() != -1)
{
u256 endowment; u256 endowment;
u256 gas; u256 gas;
u256 gasPrice; u256 gasPrice;
@ -569,7 +549,7 @@ int main(int argc, char** argv)
cnote << "Init:"; cnote << "Init:";
cnote << ssc.str(); cnote << ssc.str();
} }
u256 minGas = (u256)c.state().createGas(init.size(), 0); u256 minGas = (u256)Client::txGas(init.size(), 0);
if (endowment < 0) if (endowment < 0)
cwarn << "Invalid endowment"; cwarn << "Invalid endowment";
else if (gasPrice < info.minGasPrice) else if (gasPrice < info.minGasPrice)
@ -591,16 +571,15 @@ int main(int argc, char** argv)
cwarn << "Invalid address length"; cwarn << "Invalid address length";
else else
{ {
ClientGuard g(&c);
auto h = h160(fromHex(rechex)); auto h = h160(fromHex(rechex));
stringstream s; stringstream s;
try try
{ {
auto storage = c.state().storage(h); auto storage = c.storageAt(h, 0);
for (auto const& i: storage) for (auto const& i: storage)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl; s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
s << endl << disassemble(c.state().code(h)) << endl; s << endl << disassemble(c.codeAt(h, 0)) << endl;
string outFile = getDataDir() + "/" + rechex + ".evm"; string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs; ofstream ofs;

134
libethereum/Client.cpp

@ -92,6 +92,7 @@ void Client::ensureWorking()
// Synchronise the state according to the head of the block chain. // Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones. // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
WriteGuard l(x_stateDB);
m_preMine.sync(m_bc); m_preMine.sync(m_bc);
m_postMine = m_preMine; m_postMine = m_preMine;
})); }));
@ -109,7 +110,7 @@ void Client::flushTransactions()
void Client::clearPending() void Client::clearPending()
{ {
ClientGuard l(this); WriteGuard l(x_stateDB);
if (!m_postMine.pending().size()) if (!m_postMine.pending().size())
return; return;
h256Set changeds; h256Set changeds;
@ -161,8 +162,10 @@ void Client::uninstallWatch(unsigned _i)
void Client::appendFromNewPending(h256 _bloom, h256Set& o_changed) const void Client::appendFromNewPending(h256 _bloom, h256Set& o_changed) const
{ {
lock_guard<mutex> l(m_filterLock); lock_guard<mutex> l(m_filterLock);
ReadGuard sl(x_stateDB);
for (pair<h256, InstalledFilter> const& i: m_filters) for (pair<h256, InstalledFilter> const& i: m_filters)
if ((unsigned)i.second.filter.latest() >= m_postMine.info().number && i.second.filter.matches(_bloom)) if ((unsigned)i.second.filter.latest() > m_bc.number() && i.second.filter.matches(_bloom))
o_changed.insert(i.first); o_changed.insert(i.first);
} }
@ -204,20 +207,22 @@ void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHo
ensureWorking(); ensureWorking();
{ {
Guard l(x_net); UpgradableGuard l(x_net);
if (m_net.get()) if (m_net.get())
return; return;
try
{
m_net.reset(new PeerServer(m_clientVersion, m_bc, 0, _listenPort, _mode, _publicIP, _upnp));
}
catch (std::exception const&)
{ {
// Probably already have the port open. UpgradeGuard ul(l);
cwarn << "Could not initialize with specified/default port. Trying system-assigned port"; try
m_net.reset(new PeerServer(m_clientVersion, m_bc, 0, _mode, _publicIP, _upnp)); {
m_net.reset(new PeerServer(m_clientVersion, m_bc, 0, _listenPort, _mode, _publicIP, _upnp));
}
catch (std::exception const&)
{
// Probably already have the port open.
cwarn << "Could not initialize with specified/default port. Trying system-assigned port";
m_net.reset(new PeerServer(m_clientVersion, m_bc, 0, _mode, _publicIP, _upnp));
}
} }
m_net->setIdealPeerCount(_peers); m_net->setIdealPeerCount(_peers);
} }
@ -227,19 +232,41 @@ void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHo
std::vector<PeerInfo> Client::peers() std::vector<PeerInfo> Client::peers()
{ {
Guard l(x_net); ReadGuard l(x_net);
return m_net ? m_net->peers() : std::vector<PeerInfo>(); return m_net ? m_net->peers() : std::vector<PeerInfo>();
} }
size_t Client::peerCount() const size_t Client::peerCount() const
{ {
Guard l(x_net); ReadGuard l(x_net);
return m_net ? m_net->peerCount() : 0; return m_net ? m_net->peerCount() : 0;
} }
void Client::setIdealPeerCount(size_t _n) const
{
ReadGuard l(x_net);
if (m_net)
return m_net->setIdealPeerCount(_n);
}
bytes Client::savePeers()
{
ReadGuard l(x_net);
if (m_net)
return m_net->savePeers();
return bytes();
}
void Client::restorePeers(bytesConstRef _saved)
{
ReadGuard l(x_net);
if (m_net)
return m_net->restorePeers(_saved);
}
void Client::connect(std::string const& _seedHost, unsigned short _port) void Client::connect(std::string const& _seedHost, unsigned short _port)
{ {
Guard l(x_net); ReadGuard l(x_net);
if (!m_net.get()) if (!m_net.get())
return; return;
m_net->connect(_seedHost, _port); m_net->connect(_seedHost, _port);
@ -248,7 +275,7 @@ void Client::connect(std::string const& _seedHost, unsigned short _port)
void Client::stopNetwork() void Client::stopNetwork()
{ {
{ {
Guard l(x_net); WriteGuard l(x_net);
m_net.reset(nullptr); m_net.reset(nullptr);
} }
@ -279,10 +306,12 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _
{ {
ensureWorking(); ensureWorking();
ClientGuard l(this);
Transaction t; Transaction t;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); {
ReadGuard l(x_stateDB);
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
}
t.value = _value; t.value = _value;
t.gasPrice = _gasPrice; t.gasPrice = _gasPrice;
t.gas = _gas; t.gas = _gas;
@ -297,9 +326,11 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2
{ {
ensureWorking(); ensureWorking();
ClientGuard l(this);
Transaction t; Transaction t;
t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); {
ReadGuard l(x_stateDB);
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
}
t.value = _endowment; t.value = _endowment;
t.gasPrice = _gasPrice; t.gasPrice = _gasPrice;
t.gas = _gas; t.gas = _gas;
@ -315,7 +346,6 @@ void Client::inject(bytesConstRef _rlp)
{ {
ensureWorking(); ensureWorking();
ClientGuard l(this);
m_tq.attemptImport(_rlp); m_tq.attemptImport(_rlp);
} }
@ -324,7 +354,7 @@ void Client::workNet()
// Process network events. // Process network events.
// Synchronise block chain with network. // Synchronise block chain with network.
// Will broadcast any of our (new) transactions and blocks, and collect & add any of their (new) transactions and blocks. // Will broadcast any of our (new) transactions and blocks, and collect & add any of their (new) transactions and blocks.
Guard l(x_net); ReadGuard l(x_net);
if (m_net) if (m_net)
{ {
cwork << "NETWORK"; cwork << "NETWORK";
@ -355,7 +385,7 @@ void Client::work(bool _justQueue)
m_mineProgress.best = (double)-1; m_mineProgress.best = (double)-1;
m_mineProgress.hashes = 0; m_mineProgress.hashes = 0;
m_mineProgress.ms = 0; m_mineProgress.ms = 0;
ClientGuard l(this); WriteGuard l(x_stateDB);
if (m_paranoia) if (m_paranoia)
{ {
if (m_postMine.amIJustParanoid(m_bc)) if (m_postMine.amIJustParanoid(m_bc))
@ -387,7 +417,7 @@ void Client::work(bool _justQueue)
m_mineProgress.requirement = mineInfo.requirement; m_mineProgress.requirement = mineInfo.requirement;
m_mineProgress.ms += 100; m_mineProgress.ms += 100;
m_mineProgress.hashes += mineInfo.hashes; m_mineProgress.hashes += mineInfo.hashes;
ClientGuard l(this); WriteGuard l(x_stateDB);
m_mineHistory.push_back(mineInfo); m_mineHistory.push_back(mineInfo);
if (mineInfo.completed) if (mineInfo.completed)
{ {
@ -420,7 +450,7 @@ void Client::work(bool _justQueue)
// all blocks. // all blocks.
// Resynchronise state with block chain & trans // Resynchronise state with block chain & trans
{ {
ClientGuard l(this); WriteGuard l(x_stateDB);
cwork << "BQ ==> CHAIN ==> STATE"; cwork << "BQ ==> CHAIN ==> STATE";
OverlayDB db = m_stateDB; OverlayDB db = m_stateDB;
@ -466,16 +496,6 @@ void Client::work(bool _justQueue)
cworkout << "WORK"; cworkout << "WORK";
} }
void Client::lock() const
{
x_stateDB.lock();
}
void Client::unlock() const
{
x_stateDB.unlock();
}
unsigned Client::numberOf(int _n) const unsigned Client::numberOf(int _n) const
{ {
if (_n > 0) if (_n > 0)
@ -488,6 +508,7 @@ unsigned Client::numberOf(int _n) const
State Client::asOf(int _h) const State Client::asOf(int _h) const
{ {
ReadGuard l(x_stateDB);
if (_h == 0) if (_h == 0)
return m_postMine; return m_postMine;
else if (_h == -1) else if (_h == -1)
@ -496,9 +517,38 @@ State Client::asOf(int _h) const
return State(m_stateDB, m_bc, m_bc.numberHash(numberOf(_h))); return State(m_stateDB, m_bc, m_bc.numberHash(numberOf(_h)));
} }
State Client::state(unsigned _txi, h256 _block) const
{
ReadGuard l(x_stateDB);
return State(m_stateDB, m_bc, _block).fromPending(_txi);
}
eth::State Client::state(h256 _block) const
{
ReadGuard l(x_stateDB);
return State(m_stateDB, m_bc, _block);
}
eth::State Client::state(unsigned _txi) const
{
ReadGuard l(x_stateDB);
return m_postMine.fromPending(_txi);
}
StateDiff Client::diff(unsigned _txi, int _block) const
{
State st = state(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
StateDiff Client::diff(unsigned _txi, h256 _block) const
{
State st = state(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1));
}
std::vector<Address> Client::addresses(int _block) const std::vector<Address> Client::addresses(int _block) const
{ {
ClientGuard l(this);
vector<Address> ret; vector<Address> ret;
for (auto const& i: asOf(_block).addresses()) for (auto const& i: asOf(_block).addresses())
ret.push_back(i.first); ret.push_back(i.first);
@ -507,25 +557,26 @@ std::vector<Address> Client::addresses(int _block) const
u256 Client::balanceAt(Address _a, int _block) const u256 Client::balanceAt(Address _a, int _block) const
{ {
ClientGuard l(this);
return asOf(_block).balance(_a); return asOf(_block).balance(_a);
} }
std::map<u256, u256> Client::storageAt(Address _a, int _block) const
{
return asOf(_block).storage(_a);
}
u256 Client::countAt(Address _a, int _block) const u256 Client::countAt(Address _a, int _block) const
{ {
ClientGuard l(this);
return asOf(_block).transactionsFrom(_a); return asOf(_block).transactionsFrom(_a);
} }
u256 Client::stateAt(Address _a, u256 _l, int _block) const u256 Client::stateAt(Address _a, u256 _l, int _block) const
{ {
ClientGuard l(this);
return asOf(_block).storage(_a, _l); return asOf(_block).storage(_a, _l);
} }
bytes Client::codeAt(Address _a, int _block) const bytes Client::codeAt(Address _a, int _block) const
{ {
ClientGuard l(this);
return asOf(_block).code(_a); return asOf(_block).code(_a);
} }
@ -642,8 +693,6 @@ bool TransactionFilter::matches(Manifest const& _m, vector<unsigned> _p, Address
PastMessages Client::transactions(TransactionFilter const& _f) const PastMessages Client::transactions(TransactionFilter const& _f) const
{ {
ClientGuard l(this);
PastMessages ret; PastMessages ret;
unsigned begin = min<unsigned>(m_bc.number(), (unsigned)_f.latest()); unsigned begin = min<unsigned>(m_bc.number(), (unsigned)_f.latest());
unsigned end = min(begin, (unsigned)_f.earliest()); unsigned end = min(begin, (unsigned)_f.earliest());
@ -653,6 +702,7 @@ PastMessages Client::transactions(TransactionFilter const& _f) const
// Handle pending transactions differently as they're not on the block chain. // Handle pending transactions differently as they're not on the block chain.
if (begin == m_bc.number()) if (begin == m_bc.number())
{ {
ReadGuard l(x_stateDB);
for (unsigned i = 0; i < m_postMine.pending().size(); ++i) for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
{ {
// Might have a transaction that contains a matching message. // Might have a transaction that contains a matching message.

76
libethereum/Client.h

@ -27,7 +27,9 @@
#include <atomic> #include <atomic>
#include <libethential/Common.h> #include <libethential/Common.h>
#include <libethential/CommonIO.h> #include <libethential/CommonIO.h>
#include <libevm/FeeStructure.h>
#include <libethcore/Dagger.h> #include <libethcore/Dagger.h>
#include "Guards.h"
#include "BlockChain.h" #include "BlockChain.h"
#include "TransactionQueue.h" #include "TransactionQueue.h"
#include "State.h" #include "State.h"
@ -47,16 +49,6 @@ struct MineProgress
class Client; class Client;
class ClientGuard
{
public:
inline ClientGuard(Client const* _c);
inline ~ClientGuard();
private:
Client const* m_client;
};
enum ClientWorkState enum ClientWorkState
{ {
Active = 0, Active = 0,
@ -198,19 +190,6 @@ public:
// Informational stuff // Informational stuff
// [OLD API]:
/// Locks/unlocks the state/blockChain/transactionQueue for access.
void lock() const;
void unlock() const;
/// Get the object representing the current state of Ethereum.
State const& state() const { return m_preMine; }
/// Get the object representing the current state of Ethereum.
State const& postState() const { return m_postMine; }
/// Get the object representing the current canonical blockchain.
BlockChain const& blockChain() const { return m_bc; }
// [NEW API] // [NEW API]
void setDefault(int _block) { m_default = _block; } void setDefault(int _block) { m_default = _block; }
@ -219,29 +198,52 @@ public:
u256 countAt(Address _a) const { return countAt(_a, m_default); } u256 countAt(Address _a) const { return countAt(_a, m_default); }
u256 stateAt(Address _a, u256 _l) const { return stateAt(_a, _l, m_default); } u256 stateAt(Address _a, u256 _l) const { return stateAt(_a, _l, m_default); }
bytes codeAt(Address _a) const { return codeAt(_a, m_default); } bytes codeAt(Address _a) const { return codeAt(_a, m_default); }
std::map<u256, u256> storageAt(Address _a) const { return storageAt(_a, m_default); }
u256 balanceAt(Address _a, int _block) const; u256 balanceAt(Address _a, int _block) const;
u256 countAt(Address _a, int _block) const; u256 countAt(Address _a, int _block) const;
u256 stateAt(Address _a, u256 _l, int _block) const; u256 stateAt(Address _a, u256 _l, int _block) const;
bytes codeAt(Address _a, int _block) const; bytes codeAt(Address _a, int _block) const;
PastMessages transactions(TransactionFilter const& _filter) const; std::map<u256, u256> storageAt(Address _a, int _block) const;
PastMessages transactions(unsigned _watchId) const { try { std::lock_guard<std::mutex> l(m_filterLock); return transactions(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return PastMessages(); } }
unsigned installWatch(TransactionFilter const& _filter); unsigned installWatch(TransactionFilter const& _filter);
unsigned installWatch(h256 _filterId); unsigned installWatch(h256 _filterId);
void uninstallWatch(unsigned _watchId); void uninstallWatch(unsigned _watchId);
bool peekWatch(unsigned _watchId) const { std::lock_guard<std::mutex> l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } } bool peekWatch(unsigned _watchId) const { std::lock_guard<std::mutex> l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } }
bool checkWatch(unsigned _watchId) { std::lock_guard<std::mutex> l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; } bool checkWatch(unsigned _watchId) { std::lock_guard<std::mutex> l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; }
PastMessages transactions(unsigned _watchId) const { try { std::lock_guard<std::mutex> l(m_filterLock); return transactions(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return PastMessages(); } }
PastMessages transactions(TransactionFilter const& _filter) const;
// [EXTRA API]: // [EXTRA API]:
/// Get a map containing each of the pending transactions. /// Get a map containing each of the pending transactions.
/// @TODO: Remove in favour of transactions(). /// @TODO: Remove in favour of transactions().
Transactions pending() const { return m_postMine.pending(); } Transactions pending() const { return m_postMine.pending(); }
/// Differences between transactions.
StateDiff diff(unsigned _txi) const { return diff(_txi, m_default); }
StateDiff diff(unsigned _txi, h256 _block) const;
StateDiff diff(unsigned _txi, int _block) const;
/// Get a list of all active addresses. /// Get a list of all active addresses.
std::vector<Address> addresses() const { return addresses(m_default); } std::vector<Address> addresses() const { return addresses(m_default); }
std::vector<Address> addresses(int _block) const; std::vector<Address> addresses(int _block) const;
/// Get the fee associated for a transaction with the given data.
static u256 txGas(uint _dataCount, u256 _gas = 0) { return c_txDataGas * _dataCount + c_txGas + _gas; }
// [PRIVATE API - only relevant for base clients, not available in general]
eth::State state(unsigned _txi, h256 _block) const;
eth::State state(h256 _block) const;
eth::State state(unsigned _txi) const;
/// Get the object representing the current state of Ethereum.
eth::State postState() const { ReadGuard l(x_stateDB); return m_postMine; }
/// Get the object representing the current canonical blockchain.
BlockChain const& blockChain() const { return m_bc; }
// Misc stuff: // Misc stuff:
void setClientVersion(std::string const& _name) { m_clientVersion = _name; } void setClientVersion(std::string const& _name) { m_clientVersion = _name; }
@ -252,6 +254,8 @@ public:
std::vector<PeerInfo> peers(); std::vector<PeerInfo> peers();
/// Same as peers().size(), but more efficient. /// Same as peers().size(), but more efficient.
size_t peerCount() const; size_t peerCount() const;
/// Same as peers().size(), but more efficient.
void setIdealPeerCount(size_t _n) const;
/// Start the network subsystem. /// Start the network subsystem.
void startNetwork(unsigned short _listenPort = 30303, std::string const& _remoteHost = std::string(), unsigned short _remotePort = 30303, NodeMode _mode = NodeMode::Full, unsigned _peers = 5, std::string const& _publicIP = std::string(), bool _upnp = true); void startNetwork(unsigned short _listenPort = 30303, std::string const& _remoteHost = std::string(), unsigned short _remotePort = 30303, NodeMode _mode = NodeMode::Full, unsigned _peers = 5, std::string const& _publicIP = std::string(), bool _upnp = true);
@ -260,9 +264,11 @@ public:
/// Stop the network subsystem. /// Stop the network subsystem.
void stopNetwork(); void stopNetwork();
/// Is the network subsystem up? /// Is the network subsystem up?
bool haveNetwork() { Guard l(x_net); return !!m_net; } bool haveNetwork() { ReadGuard l(x_net); return !!m_net; }
/// Get access to the peer server object. This will be null if the network isn't online. DANGEROUS! DO NOT USE! /// Save peers
PeerServer* peerServer() const { Guard l(x_net); return m_net.get(); } bytes savePeers();
/// Restore peers
void restorePeers(bytesConstRef _saved);
// Mining stuff: // Mining stuff:
@ -324,14 +330,14 @@ private:
BlockChain m_bc; ///< Maintains block database. BlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
mutable std::recursive_mutex x_stateDB; // TODO: remove in favour of copying m_stateDB as required and thread-safing/copying State. Have a good think about what state objects there should be. Probably want 4 (pre, post, mining, user-visible). mutable boost::shared_mutex x_stateDB; // TODO: remove in favour of copying m_stateDB as required and thread-safing/copying State. Have a good think about what state objects there should be. Probably want 4 (pre, post, mining, user-visible).
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it. OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_preMine; ///< The present state of the client. State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
std::unique_ptr<std::thread> m_workNet; ///< The network thread. std::unique_ptr<std::thread> m_workNet; ///< The network thread.
std::atomic<ClientWorkState> m_workNetState; std::atomic<ClientWorkState> m_workNetState;
mutable std::mutex x_net; ///< Lock for the network. // TODO: make network thread-safe. mutable boost::shared_mutex x_net; ///< Lock for the network existance.
std::unique_ptr<PeerServer> m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required. std::unique_ptr<PeerServer> m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
std::unique_ptr<std::thread> m_work; ///< The work thread. std::unique_ptr<std::thread> m_work; ///< The work thread.
@ -350,14 +356,4 @@ private:
int m_default = -1; int m_default = -1;
}; };
inline ClientGuard::ClientGuard(Client const* _c): m_client(_c)
{
m_client->lock();
}
inline ClientGuard::~ClientGuard()
{
m_client->unlock();
}
} }

9
libethereum/State.h

@ -264,15 +264,6 @@ public:
/// @return the difference between this state (origin) and @a _c (destination). /// @return the difference between this state (origin) and @a _c (destination).
StateDiff diff(State const& _c) const; StateDiff diff(State const& _c) const;
/// Get the fee associated for a transaction with the given data.
u256 txGas(uint _dataCount, u256 _gas = 0) const { return c_txDataGas * _dataCount + c_txGas + _gas; }
/// Get the fee associated for a contract created with the given data.
u256 createGas(uint _dataCount, u256 _gas = 0) const { return txGas(_dataCount, _gas); }
/// Get the fee associated for a normal transaction.
u256 callGas(uint _dataCount, u256 _gas = 0) const { return txGas(_dataCount, _gas); }
/// Sync our state with the block chain. /// Sync our state with the block chain.
/// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue. /// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue.
bool sync(BlockChain const& _bc); bool sync(BlockChain const& _bc);

30
libqethereum/QEthereum.cpp

@ -187,50 +187,32 @@ QString QEthereum::balanceAt(QString _a) const
QString QEthereum::storageAt(QString _a, QString _p) const QString QEthereum::storageAt(QString _a, QString _p) const
{ {
if (!m_client) return m_client ? toQJS(client()->stateAt(toAddress(_a), toU256(_p))) : "";
return "";
eth::ClientGuard l(const_cast<Client*>(m_client));
return toQJS(client()->postState().storage(toAddress(_a), toU256(_p)));
} }
double QEthereum::txCountAt(QString _a) const double QEthereum::txCountAt(QString _a) const
{ {
if (!m_client) return m_client ? (double)client()->countAt(toAddress(_a)) : 0.0;
return 0.0;
eth::ClientGuard l(const_cast<Client*>(m_client));
return (double)client()->postState().transactionsFrom(toAddress(_a));
} }
bool QEthereum::isContractAt(QString _a) const bool QEthereum::isContractAt(QString _a) const
{ {
if (!m_client) return m_client ? client()->codeAt(toAddress(_a)).size() : false;
return false;
eth::ClientGuard l(const_cast<Client*>(m_client));
return client()->postState().addressHasCode(toAddress(_a));
} }
u256 QEthereum::balanceAt(Address _a) const u256 QEthereum::balanceAt(Address _a) const
{ {
if (!m_client) return m_client ? client()->balanceAt(_a) : 0;
return 0;
eth::ClientGuard l(const_cast<Client*>(m_client));
return client()->postState().balance(_a);
} }
double QEthereum::txCountAt(Address _a) const double QEthereum::txCountAt(Address _a) const
{ {
if (!m_client) return m_client ? (double)client()->countAt(_a) : 0.0;
return 0.0;
eth::ClientGuard l(const_cast<Client*>(m_client));
return (double)client()->postState().transactionsFrom(_a);
} }
bool QEthereum::isContractAt(Address _a) const bool QEthereum::isContractAt(Address _a) const
{ {
if (!m_client) return m_client ? client()->codeAt(_a).size() : false;
return false;
eth::ClientGuard l(const_cast<Client*>(m_client));
return client()->postState().addressHasCode(_a);
} }
QString QEthereum::balanceAt(QString _a, int _block) const QString QEthereum::balanceAt(QString _a, int _block) const

66
neth/main.cpp

@ -481,10 +481,7 @@ int main(int argc, char** argv)
if (!remoteHost.empty()) if (!remoteHost.empty())
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp); c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
if (mining) if (mining)
{
ClientGuard g(&c);
c.startMining(); c.startMining();
}
#if ETH_JSONRPC #if ETH_JSONRPC
auto_ptr<EthStubServer> jsonrpcServer; auto_ptr<EthStubServer> jsonrpcServer;
@ -531,7 +528,6 @@ int main(int argc, char** argv)
{ {
eth::uint port; eth::uint port;
iss >> port; iss >> port;
ClientGuard g(&c);
c.startNetwork((short)port); c.startNetwork((short)port);
} }
else if (cmd == "connect") else if (cmd == "connect")
@ -539,22 +535,18 @@ int main(int argc, char** argv)
string addr; string addr;
eth::uint port; eth::uint port;
iss >> addr >> port; iss >> addr >> port;
ClientGuard g(&c);
c.connect(addr, (short)port); c.connect(addr, (short)port);
} }
else if (cmd == "netstop") else if (cmd == "netstop")
{ {
ClientGuard g(&c);
c.stopNetwork(); c.stopNetwork();
} }
else if (cmd == "minestart") else if (cmd == "minestart")
{ {
ClientGuard g(&c);
c.startMining(); c.startMining();
} }
else if (cmd == "minestop") else if (cmd == "minestop")
{ {
ClientGuard g(&c);
c.stopMining(); c.stopMining();
} }
#if ETH_JSONRPC #if ETH_JSONRPC
@ -604,13 +596,12 @@ int main(int argc, char** argv)
} }
else if (cmd == "balance") else if (cmd == "balance")
{ {
u256 balance = c.state().balance(us.address()); u256 balance = c.balanceAt(us.address(), 0);
ccout << "Current balance:" << endl; ccout << "Current balance:" << endl;
ccout << toString(balance) << endl; ccout << toString(balance) << endl;
} }
else if (cmd == "transact") else if (cmd == "transact")
{ {
ClientGuard g(&c);
auto const& bc = c.blockChain(); auto const& bc = c.blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
@ -663,7 +654,7 @@ int main(int argc, char** argv)
ssbd << bbd; ssbd << bbd;
cnote << ssbd.str(); cnote << ssbd.str();
int ssize = fields[4].length(); int ssize = fields[4].length();
u256 minGas = (u256)c.state().callGas(data.size(), 0); u256 minGas = (u256)Client::txGas(data.size(), 0);
if (size < 40) if (size < 40)
{ {
if (size > 0) if (size > 0)
@ -688,7 +679,6 @@ int main(int argc, char** argv)
} }
else if (cmd == "send") else if (cmd == "send")
{ {
ClientGuard g(&c);
vector<string> s; vector<string> s;
s.push_back("Address"); s.push_back("Address");
vector<string> l; vector<string> l;
@ -720,7 +710,7 @@ int main(int argc, char** argv)
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
BlockInfo info(blockData); BlockInfo info(blockData);
u256 minGas = (u256)c.state().callGas(0, 0); u256 minGas = (u256)Client::txGas(0, 0);
Address dest = h160(fromHex(fields[0])); Address dest = h160(fromHex(fields[0]));
c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice);
} }
@ -728,7 +718,6 @@ int main(int argc, char** argv)
} }
else if (cmd == "contract") else if (cmd == "contract")
{ {
ClientGuard g(&c);
auto const& bc = c.blockChain(); auto const& bc = c.blockChain();
auto h = bc.currentHash(); auto h = bc.currentHash();
auto blockData = bc.block(h); auto blockData = bc.block(h);
@ -782,7 +771,7 @@ int main(int argc, char** argv)
cnote << "Init:"; cnote << "Init:";
cnote << ssc.str(); cnote << ssc.str();
} }
u256 minGas = (u256)c.state().createGas(init.size(), 0); u256 minGas = (u256)Client::txGas(init.size(), 0);
if (endowment < 0) if (endowment < 0)
cwarn << "Invalid endowment"; cwarn << "Invalid endowment";
else if (gasPrice < info.minGasPrice) else if (gasPrice < info.minGasPrice)
@ -804,16 +793,15 @@ int main(int argc, char** argv)
cwarn << "Invalid address length"; cwarn << "Invalid address length";
else else
{ {
ClientGuard g(&c); auto address = h160(fromHex(rechex));
auto h = h160(fromHex(rechex));
stringstream s; stringstream s;
try try
{ {
auto storage = c.state().storage(h); auto storage = c.storageAt(address);
for (auto const& i: storage) for (auto const& i: storage)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl; s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
s << endl << disassemble(c.state().code(h)) << endl; s << endl << disassemble(c.codeAt(address)) << endl;
string outFile = getDataDir() + "/" + rechex + ".evm"; string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs; ofstream ofs;
@ -848,9 +836,6 @@ int main(int argc, char** argv)
// Lock to prevent corrupt block-chain errors // Lock to prevent corrupt block-chain errors
ClientGuard g(&c);
auto const& st = c.state();
auto const& bc = c.blockChain(); auto const& bc = c.blockChain();
ccout << "Genesis hash: " << bc.genesisHash() << endl; ccout << "Genesis hash: " << bc.genesisHash() << endl;
@ -869,7 +854,7 @@ int main(int argc, char** argv)
auto s = t.receiveAddress ? auto s = t.receiveAddress ?
boost::format(" %1% %2%> %3%: %4% [%5%]") % boost::format(" %1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) % toString(t.safeSender()) %
(st.addressHasCode(t.receiveAddress) ? '*' : '-') % (c.codeAt(t.receiveAddress, 0).size() ? '*' : '-') %
toString(t.receiveAddress) % toString(t.receiveAddress) %
toString(formatBalance(t.value)) % toString(formatBalance(t.value)) %
toString((unsigned)t.nonce) : toString((unsigned)t.nonce) :
@ -894,7 +879,7 @@ int main(int argc, char** argv)
auto s = t.receiveAddress ? auto s = t.receiveAddress ?
boost::format("%1% %2%> %3%: %4% [%5%]") % boost::format("%1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) % toString(t.safeSender()) %
(st.addressHasCode(t.receiveAddress) ? '*' : '-') % (c.codeAt(t.receiveAddress, 0).size() ? '*' : '-') %
toString(t.receiveAddress) % toString(t.receiveAddress) %
toString(formatBalance(t.value)) % toString(formatBalance(t.value)) %
toString((unsigned)t.nonce) : toString((unsigned)t.nonce) :
@ -912,38 +897,29 @@ int main(int argc, char** argv)
// Contracts and addresses // Contracts and addresses
y = 1; y = 1;
int cc = 1; int cc = 1;
auto acs = st.addresses(); auto acs = c.addresses();
for (auto const& i: acs) for (auto const& i: acs)
{ if (c.codeAt(i, 0).size())
auto r = i.first;
if (st.addressHasCode(r))
{ {
auto s = boost::format("%1%%2% : %3% [%4%]") % auto s = boost::format("%1%%2% : %3% [%4%]") %
toString(r) % toString(i) %
pretty(r, st) % toString(formatBalance(c.balanceAt(i, 0))) %
toString(formatBalance(i.second)) % toString((unsigned)c.countAt(i, 0));
toString((unsigned)st.transactionsFrom(i.first));
mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth); mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth);
if (cc > qheight - 2) if (cc > qheight - 2)
break; break;
} }
}
for (auto const& i: acs) for (auto const& i: acs)
{ if (c.codeAt(i, 0).empty())
auto r = i.first; {
if (!st.addressHasCode(r)) {
auto s = boost::format("%1%%2% : %3% [%4%]") % auto s = boost::format("%1%%2% : %3% [%4%]") %
toString(r) % toString(i) %
pretty(r, st) % toString(formatBalance(c.balanceAt(i, 0))) %
toString(formatBalance(i.second)) % toString((unsigned)c.countAt(i, 0));
toString((unsigned)st.transactionsFrom(i.first));
mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4); mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4);
if (y > height * 3 / 5 - 4) if (y > height * 3 / 5 - 4)
break; break;
} }
}
// Peers // Peers
y = 1; y = 1;
for (PeerInfo const& i: c.peers()) for (PeerInfo const& i: c.peers())
@ -968,9 +944,9 @@ int main(int argc, char** argv)
// Balance // Balance
stringstream ssb; stringstream ssb;
u256 balance = c.state().balance(us.address()); u256 balance = c.balanceAt(us.address(), 0);
Address gavCoin("0115554959f43bf1d04cd7e3749d00fb0623ce1f"); Address gavCoin("0115554959f43bf1d04cd7e3749d00fb0623ce1f");
u256 totalGavCoinBalance = st.storage(gavCoin, (u160)us.address()); u256 totalGavCoinBalance = c.stateAt(gavCoin, (u160)us.address());
ssb << "Balance: " << formatBalance(balance) << " | " << totalGavCoinBalance << " GAV"; ssb << "Balance: " << formatBalance(balance) << " | " << totalGavCoinBalance << " GAV";
mvwprintw(consolewin, 0, x, ssb.str().c_str()); mvwprintw(consolewin, 0, x, ssb.str().c_str());

19
walleth/MainWin.cpp

@ -158,12 +158,9 @@ void Main::writeSettings()
s.setValue("idealPeers", m_idealPeers); s.setValue("idealPeers", m_idealPeers);
s.setValue("port", m_port); s.setValue("port", m_port);
if (client()->peerServer()) bytes d = client()->savePeers();
{ if (d.size())
bytes d = client()->peerServer()->savePeers();
m_peers = QByteArray((char*)d.data(), (int)d.size()); m_peers = QByteArray((char*)d.data(), (int)d.size());
}
s.setValue("peers", m_peers); s.setValue("peers", m_peers);
s.setValue("geometry", saveGeometry()); s.setValue("geometry", saveGeometry());
@ -203,16 +200,8 @@ void Main::refreshNetwork()
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)"); ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
} }
eth::State const& Main::state() const
{
return ui->preview->isChecked() ? client()->postState() : client()->state();
}
void Main::refresh() void Main::refresh()
{ {
eth::ClientGuard l(client());
auto const& st = state();
auto d = client()->blockChain().details(); auto d = client()->blockChain().details();
auto diff = BlockInfo(client()->blockChain().block()).difficulty; auto diff = BlockInfo(client()->blockChain().block()).difficulty;
ui->blockCount->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)));
@ -221,7 +210,7 @@ void Main::refresh()
u256 totalBalance = 0; u256 totalBalance = 0;
for (auto i: m_myKeys) for (auto i: m_myKeys)
{ {
u256 b = st.balance(i.address()); u256 b = m_client->balanceAt(i.address());
totalBalance += b; totalBalance += b;
} }
ui->balance->setText(QString::fromStdString(formatBalance(totalBalance))); ui->balance->setText(QString::fromStdString(formatBalance(totalBalance)));
@ -244,7 +233,7 @@ void Main::on_net_triggered(bool _auto)
else else
client()->startNetwork(m_port, string(), 0, NodeMode::Full, m_idealPeers, "", ui->upnp->isChecked()); client()->startNetwork(m_port, string(), 0, NodeMode::Full, m_idealPeers, "", ui->upnp->isChecked());
if (m_peers.size()) if (m_peers.size())
client()->peerServer()->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size())); client()->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
} }
else else
client()->stopNetwork(); client()->stopNetwork();

Loading…
Cancel
Save