Browse Source

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

cl-refactor
Gav Wood 11 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. 114
      libethereum/Client.cpp
  6. 76
      libethereum/Client.h
  7. 9
      libethereum/State.h
  8. 30
      libqethereum/QEthereum.cpp
  9. 64
      neth/main.cpp
  10. 19
      walleth/MainWin.cpp

78
alethzero/MainWin.cpp

@ -257,7 +257,7 @@ void Main::installWatches()
void Main::installNameRegWatch()
{
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()
@ -446,11 +446,11 @@ Address Main::fromString(QString const& _a) const
memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_a.size())
{
if (h160 nameReg = (u160)state().storage(c_config, 0))
if (h256 a = state().storage(nameReg, n))
if (h160 nameReg = (u160)m_client->stateAt(c_config, 0))
if (h256 a = m_client->stateAt(nameReg, n))
return right160(a);
if (h256 a = state().storage(m_nameReg, n))
if (h256 a = m_client->stateAt(m_nameReg, n))
return right160(a);
}
if (_a.size() == 40)
@ -493,12 +493,9 @@ void Main::writeSettings()
s.setValue("port", ui->port->value());
s.setValue("url", ui->urlEdit->text());
if (m_client->peerServer())
{
bytes d = m_client->peerServer()->savePeers();
bytes d = m_client->savePeers();
if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size());
}
s.setValue("peers", m_peers);
s.setValue("nameReg", ui->nameReg->text());
@ -597,7 +594,6 @@ void Main::on_preview_triggered()
void Main::refreshMining()
{
eth::ClientGuard g(m_client.get());
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");
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()));
}
eth::State const& Main::state() const
{
return ui->preview->isChecked() ? m_client->postState() : m_client->state();
}
void Main::refreshAll()
{
refreshDestination();
@ -760,8 +751,6 @@ static bool transactionMatch(string const& _f, Transaction const& _t)
void Main::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();
ui->blocks->clear();
@ -794,7 +783,7 @@ void Main::refreshBlockChain()
.arg(render(t.safeSender()))
.arg(render(t.receiveAddress))
.arg((unsigned)t.nonce)
.arg(st.addressHasCode(t.receiveAddress) ? '*' : '-') :
.arg(m_client->codeAt(t.receiveAddress).size() ? '*' : '-') :
QString(" %2 +> %3: %1 [%4]")
.arg(formatBalance(t.value).c_str())
.arg(render(t.safeSender()))
@ -933,13 +922,12 @@ string Main::renderDiff(eth::StateDiff const& _d) const
void Main::on_transactionQueue_currentItemChanged()
{
ui->pendingInfo->clear();
eth::ClientGuard g(m_client.get());
stringstream s;
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();
h256 th = sha3(rlpList(ss, tx.nonce));
s << "<h3>" << th << "</h3>";
@ -967,7 +955,7 @@ void Main::on_transactionQueue_currentItemChanged()
// s << "Pre: " << fs.rootHash() << "<br/>";
// 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()));
@ -1002,7 +990,6 @@ void Main::on_blocks_currentItemChanged()
ui->debugCurrent->setEnabled(false);
ui->debugDumpState->setEnabled(false);
ui->debugDumpStatePre->setEnabled(false);
eth::ClientGuard g(m_client.get());
if (auto item = ui->blocks->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
@ -1069,10 +1056,7 @@ void Main::on_blocks_currentItemChanged()
if (tx.data.size())
s << eth::memDump(tx.data, 16, true);
}
auto st = eth::State(m_client->state().db(), m_client->blockChain(), h);
eth::State before = st.fromPending(txi);
eth::State after = st.fromPending(txi + 1);
s << renderDiff(before.diff(after));
s << renderDiff(m_client->diff(txi, h));
ui->debugCurrent->setEnabled(true);
ui->debugDumpState->setEnabled(true);
ui->debugDumpStatePre->setEnabled(true);
@ -1084,7 +1068,6 @@ void Main::on_blocks_currentItemChanged()
void Main::on_debugCurrent_triggered()
{
eth::ClientGuard g(m_client.get());
if (auto item = ui->blocks->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
@ -1093,11 +1076,10 @@ void Main::on_debugCurrent_triggered()
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();
m_executiveState = st.fromPending(txi);
m_executiveState = m_client->state(txi, h);
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState));
Transaction t = st.pending()[txi];
Transaction t = m_client->pending()[txi];
auto r = t.rlp();
populateDebugger(&r);
m_currentExecution.reset();
@ -1107,7 +1089,6 @@ void Main::on_debugCurrent_triggered()
void Main::on_debugDumpState_triggered(int _add)
{
eth::ClientGuard g(m_client.get());
if (auto item = ui->blocks->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
@ -1120,9 +1101,8 @@ void Main::on_debugDumpState_triggered(int _add)
ofstream f(fn.toStdString());
if (f.is_open())
{
eth::State st(m_client->state().db(), m_client->blockChain(), h);
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()
{
ui->contractInfo->clear();
eth::ClientGuard l(&*m_client);
if (auto item = ui->contracts->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
assert(hba.size() == 20);
auto h = h160((byte const*)hba.data(), h160::ConstructFromPointer);
auto address = h160((byte const*)hba.data(), h160::ConstructFromPointer);
stringstream s;
try
{
auto storage = state().storage(h);
auto storage = m_client->storageAt(address);
for (auto const& i: storage)
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()));
}
catch (eth::InvalidTrie)
@ -1203,8 +1182,7 @@ void Main::on_contracts_currentItemChanged()
void Main::on_idealPeers_valueChanged()
{
if (m_client->peerServer())
m_client->peerServer()->setIdealPeerCount(ui->idealPeers->value());
m_client->setIdealPeerCount(ui->idealPeers->value());
}
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>");
}
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())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
@ -1344,9 +1322,9 @@ void Main::on_data_textChanged()
s = s.mid(1);
}
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())
ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true);
@ -1355,7 +1333,7 @@ void Main::on_data_textChanged()
{
if (ui->gas->isEnabled())
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);
}
}
@ -1412,7 +1390,7 @@ void Main::updateFee()
bool ok = false;
for (auto i: m_myKeys)
if (state().balance(i.address()) >= totalReq)
if (m_client->balanceAt(i.address()) >= totalReq)
{
ok = true;
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());
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
m_client->stopNetwork();
@ -1479,9 +1457,8 @@ void Main::on_mine_triggered()
void Main::on_send_clicked()
{
u256 totalReq = value() + fee();
eth::ClientGuard l(&*m_client);
for (auto i: m_myKeys)
if (m_client->postState().balance(i.address()) >= totalReq)
if (m_client->balanceAt(i.address(), 0) >= totalReq)
{
debugFinished();
Secret s = i.secret();
@ -1500,12 +1477,11 @@ void Main::on_debug_clicked()
try
{
u256 totalReq = value() + fee();
eth::ClientGuard l(&*m_client);
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq)
if (m_client->balanceAt(i.address()) >= totalReq)
{
Secret s = i.secret();
m_executiveState = state();
m_executiveState = m_client->postState();
m_currentExecution = unique_ptr<Executive>(new Executive(m_executiveState));
Transaction t;
t.nonce = m_executiveState.transactionsFrom(toAddress(s));

2
alethzero/MainWin.h

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

16
eth/EthStubServer.cpp

@ -60,14 +60,12 @@ Json::Value EthStubServer::procedures()
std::string EthStubServer::coinbase()
{
ClientGuard g(&m_client);
return toJS(m_client.address());
}
std::string EthStubServer::balanceAt(std::string const& _a)
{
ClientGuard g(&m_client);
return toJS(m_client.postState().balance(jsToAddress(_a)));
return toJS(m_client.balanceAt(jsToAddress(_a), 0));
}
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)
{
ClientGuard g(&m_client);
Address ret = m_client.transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice));
return toJS(ret);
}
@ -102,8 +99,7 @@ std::string EthStubServer::gasPrice()
bool EthStubServer::isContractAt(const std::string& _a)
{
ClientGuard g(&m_client);
return m_client.postState().addressHasCode(jsToAddress(_a));
return m_client.codeAt(jsToAddress(_a), 0).size();
}
bool EthStubServer::isListening()
@ -133,27 +129,23 @@ Json::Value EthStubServer::keys()
int EthStubServer::peerCount()
{
ClientGuard g(&m_client);
return m_client.peerCount();
}
std::string EthStubServer::storageAt(const std::string& _a, const std::string& x)
{
ClientGuard g(&m_client);
return toJS(m_client.postState().storage(jsToAddress(_a), jsToU256(x)));
return toJS(m_client.stateAt(jsToAddress(_a), jsToU256(x), 0));
}
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));
return Json::Value();
}
std::string EthStubServer::txCountAt(const std::string& _a)
{
ClientGuard g(&m_client);
return toJS(m_client.postState().transactionsFrom(jsToAddress(_a)));
return toJS(m_client.countAt(jsToAddress(_a), 0));
}
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;
iss >> port;
ClientGuard g(&c);
c.startNetwork((short)port);
}
else if (cmd == "connect")
@ -349,12 +348,10 @@ int main(int argc, char** argv)
string addr;
eth::uint port;
iss >> addr >> port;
ClientGuard g(&c);
c.connect(addr, (short)port);
}
else if (cmd == "netstop")
{
ClientGuard g(&c);
c.stopNetwork();
}
else if (cmd == "minestart")
@ -405,12 +402,10 @@ int main(int argc, char** argv)
}
else if (cmd == "block")
{
ClientGuard g(&c);
cout << "Current block: " << c.blockChain().details().number;
}
else if (cmd == "peers")
{
ClientGuard g(&c);
for (auto it: c.peers())
cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
<< 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")
{
ClientGuard g(&c);
cout << "Current balance: " << formatBalance(c.postState().balance(us.address())) << " = " << c.postState().balance(us.address()) << " wei" << endl;
cout << "Current balance: " << formatBalance(c.balanceAt(us.address(), 0)) << " = " << c.balanceAt(us.address(), 0) << " wei" << endl;
}
else if (cmd == "transact")
{
ClientGuard g(&c);
auto const& bc = c.blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
@ -450,7 +443,7 @@ int main(int argc, char** argv)
cnote << ssbd.str();
int ssize = sechex.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 > 0)
@ -477,40 +470,28 @@ int main(int argc, char** argv)
}
else if (cmd == "listContracts")
{
ClientGuard g(&c);
auto const& st = c.state();
auto acs = st.addresses();
auto acs = c.addresses();
string ss;
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;
}
}
}
else if (cmd == "listAccounts")
{
ClientGuard g(&c);
auto const& st = c.state();
auto acs = st.addresses();
auto acs = c.addresses();
string ss;
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;
}
}
}
else if (cmd == "send")
{
ClientGuard g(&c);
if (iss.peek() != -1)
{
string hexAddr;
@ -529,23 +510,22 @@ int main(int argc, char** argv)
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
u256 minGas = (u256)c.state().callGas(0, 0);
u256 minGas = (u256)Client::txGas(0, 0);
Address dest = h160(fromHex(hexAddr));
c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice);
}
}
else
cwarn << "Require parameters: send ADDRESS AMOUNT";
}
else if (cmd == "contract")
{
ClientGuard g(&c);
auto const& bc = c.blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
if(iss.peek() != -1) {
if (iss.peek() != -1)
{
u256 endowment;
u256 gas;
u256 gasPrice;
@ -569,7 +549,7 @@ int main(int argc, char** argv)
cnote << "Init:";
cnote << ssc.str();
}
u256 minGas = (u256)c.state().createGas(init.size(), 0);
u256 minGas = (u256)Client::txGas(init.size(), 0);
if (endowment < 0)
cwarn << "Invalid endowment";
else if (gasPrice < info.minGasPrice)
@ -591,16 +571,15 @@ int main(int argc, char** argv)
cwarn << "Invalid address length";
else
{
ClientGuard g(&c);
auto h = h160(fromHex(rechex));
stringstream s;
try
{
auto storage = c.state().storage(h);
auto storage = c.storageAt(h, 0);
for (auto const& i: storage)
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";
ofstream ofs;

114
libethereum/Client.cpp

@ -92,6 +92,7 @@ void Client::ensureWorking()
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
WriteGuard l(x_stateDB);
m_preMine.sync(m_bc);
m_postMine = m_preMine;
}));
@ -109,7 +110,7 @@ void Client::flushTransactions()
void Client::clearPending()
{
ClientGuard l(this);
WriteGuard l(x_stateDB);
if (!m_postMine.pending().size())
return;
h256Set changeds;
@ -161,8 +162,10 @@ void Client::uninstallWatch(unsigned _i)
void Client::appendFromNewPending(h256 _bloom, h256Set& o_changed) const
{
lock_guard<mutex> l(m_filterLock);
ReadGuard sl(x_stateDB);
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);
}
@ -204,9 +207,11 @@ void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHo
ensureWorking();
{
Guard l(x_net);
UpgradableGuard l(x_net);
if (m_net.get())
return;
{
UpgradeGuard ul(l);
try
{
m_net.reset(new PeerServer(m_clientVersion, m_bc, 0, _listenPort, _mode, _publicIP, _upnp));
@ -217,7 +222,7 @@ void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHo
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);
}
@ -227,19 +232,41 @@ void Client::startNetwork(unsigned short _listenPort, std::string const& _seedHo
std::vector<PeerInfo> Client::peers()
{
Guard l(x_net);
ReadGuard l(x_net);
return m_net ? m_net->peers() : std::vector<PeerInfo>();
}
size_t Client::peerCount() const
{
Guard l(x_net);
ReadGuard l(x_net);
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)
{
Guard l(x_net);
ReadGuard l(x_net);
if (!m_net.get())
return;
m_net->connect(_seedHost, _port);
@ -248,7 +275,7 @@ void Client::connect(std::string const& _seedHost, unsigned short _port)
void Client::stopNetwork()
{
{
Guard l(x_net);
WriteGuard l(x_net);
m_net.reset(nullptr);
}
@ -279,10 +306,12 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _
{
ensureWorking();
ClientGuard l(this);
Transaction t;
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
{
ReadGuard l(x_stateDB);
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
}
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
@ -297,9 +326,11 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2
{
ensureWorking();
ClientGuard l(this);
Transaction t;
{
ReadGuard l(x_stateDB);
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
}
t.value = _endowment;
t.gasPrice = _gasPrice;
t.gas = _gas;
@ -315,7 +346,6 @@ void Client::inject(bytesConstRef _rlp)
{
ensureWorking();
ClientGuard l(this);
m_tq.attemptImport(_rlp);
}
@ -324,7 +354,7 @@ void Client::workNet()
// 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.
Guard l(x_net);
ReadGuard l(x_net);
if (m_net)
{
cwork << "NETWORK";
@ -355,7 +385,7 @@ void Client::work(bool _justQueue)
m_mineProgress.best = (double)-1;
m_mineProgress.hashes = 0;
m_mineProgress.ms = 0;
ClientGuard l(this);
WriteGuard l(x_stateDB);
if (m_paranoia)
{
if (m_postMine.amIJustParanoid(m_bc))
@ -387,7 +417,7 @@ void Client::work(bool _justQueue)
m_mineProgress.requirement = mineInfo.requirement;
m_mineProgress.ms += 100;
m_mineProgress.hashes += mineInfo.hashes;
ClientGuard l(this);
WriteGuard l(x_stateDB);
m_mineHistory.push_back(mineInfo);
if (mineInfo.completed)
{
@ -420,7 +450,7 @@ void Client::work(bool _justQueue)
// all blocks.
// Resynchronise state with block chain & trans
{
ClientGuard l(this);
WriteGuard l(x_stateDB);
cwork << "BQ ==> CHAIN ==> STATE";
OverlayDB db = m_stateDB;
@ -466,16 +496,6 @@ void Client::work(bool _justQueue)
cworkout << "WORK";
}
void Client::lock() const
{
x_stateDB.lock();
}
void Client::unlock() const
{
x_stateDB.unlock();
}
unsigned Client::numberOf(int _n) const
{
if (_n > 0)
@ -488,6 +508,7 @@ unsigned Client::numberOf(int _n) const
State Client::asOf(int _h) const
{
ReadGuard l(x_stateDB);
if (_h == 0)
return m_postMine;
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)));
}
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
{
ClientGuard l(this);
vector<Address> ret;
for (auto const& i: asOf(_block).addresses())
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
{
ClientGuard l(this);
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
{
ClientGuard l(this);
return asOf(_block).transactionsFrom(_a);
}
u256 Client::stateAt(Address _a, u256 _l, int _block) const
{
ClientGuard l(this);
return asOf(_block).storage(_a, _l);
}
bytes Client::codeAt(Address _a, int _block) const
{
ClientGuard l(this);
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
{
ClientGuard l(this);
PastMessages ret;
unsigned begin = min<unsigned>(m_bc.number(), (unsigned)_f.latest());
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.
if (begin == m_bc.number())
{
ReadGuard l(x_stateDB);
for (unsigned i = 0; i < m_postMine.pending().size(); ++i)
{
// Might have a transaction that contains a matching message.

76
libethereum/Client.h

@ -27,7 +27,9 @@
#include <atomic>
#include <libethential/Common.h>
#include <libethential/CommonIO.h>
#include <libevm/FeeStructure.h>
#include <libethcore/Dagger.h>
#include "Guards.h"
#include "BlockChain.h"
#include "TransactionQueue.h"
#include "State.h"
@ -47,16 +49,6 @@ struct MineProgress
class Client;
class ClientGuard
{
public:
inline ClientGuard(Client const* _c);
inline ~ClientGuard();
private:
Client const* m_client;
};
enum ClientWorkState
{
Active = 0,
@ -198,19 +190,6 @@ public:
// 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]
void setDefault(int _block) { m_default = _block; }
@ -219,29 +198,52 @@ public:
u256 countAt(Address _a) const { return countAt(_a, 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); }
std::map<u256, u256> storageAt(Address _a) const { return storageAt(_a, m_default); }
u256 balanceAt(Address _a, int _block) const;
u256 countAt(Address _a, int _block) const;
u256 stateAt(Address _a, u256 _l, int _block) const;
bytes codeAt(Address _a, int _block) const;
PastMessages transactions(TransactionFilter const& _filter) 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(); } }
std::map<u256, u256> storageAt(Address _a, int _block) const;
unsigned installWatch(TransactionFilter const& _filter);
unsigned installWatch(h256 _filterId);
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 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]:
/// Get a map containing each of the pending transactions.
/// @TODO: Remove in favour of transactions().
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.
std::vector<Address> addresses() const { return addresses(m_default); }
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:
void setClientVersion(std::string const& _name) { m_clientVersion = _name; }
@ -252,6 +254,8 @@ public:
std::vector<PeerInfo> peers();
/// Same as peers().size(), but more efficient.
size_t peerCount() const;
/// Same as peers().size(), but more efficient.
void setIdealPeerCount(size_t _n) const;
/// 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);
@ -260,9 +264,11 @@ public:
/// Stop the network subsystem.
void stopNetwork();
/// Is the network subsystem up?
bool haveNetwork() { Guard 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!
PeerServer* peerServer() const { Guard l(x_net); return m_net.get(); }
bool haveNetwork() { ReadGuard l(x_net); return !!m_net; }
/// Save peers
bytes savePeers();
/// Restore peers
void restorePeers(bytesConstRef _saved);
// Mining stuff:
@ -324,14 +330,14 @@ private:
BlockChain m_bc; ///< Maintains block database.
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).
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.
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).
std::unique_ptr<std::thread> m_workNet; ///< The network thread.
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<std::thread> m_work; ///< The work thread.
@ -350,14 +356,4 @@ private:
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).
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.
/// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue.
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
{
if (!m_client)
return "";
eth::ClientGuard l(const_cast<Client*>(m_client));
return toQJS(client()->postState().storage(toAddress(_a), toU256(_p)));
return m_client ? toQJS(client()->stateAt(toAddress(_a), toU256(_p))) : "";
}
double QEthereum::txCountAt(QString _a) const
{
if (!m_client)
return 0.0;
eth::ClientGuard l(const_cast<Client*>(m_client));
return (double)client()->postState().transactionsFrom(toAddress(_a));
return m_client ? (double)client()->countAt(toAddress(_a)) : 0.0;
}
bool QEthereum::isContractAt(QString _a) const
{
if (!m_client)
return false;
eth::ClientGuard l(const_cast<Client*>(m_client));
return client()->postState().addressHasCode(toAddress(_a));
return m_client ? client()->codeAt(toAddress(_a)).size() : false;
}
u256 QEthereum::balanceAt(Address _a) const
{
if (!m_client)
return 0;
eth::ClientGuard l(const_cast<Client*>(m_client));
return client()->postState().balance(_a);
return m_client ? client()->balanceAt(_a) : 0;
}
double QEthereum::txCountAt(Address _a) const
{
if (!m_client)
return 0.0;
eth::ClientGuard l(const_cast<Client*>(m_client));
return (double)client()->postState().transactionsFrom(_a);
return m_client ? (double)client()->countAt(_a) : 0.0;
}
bool QEthereum::isContractAt(Address _a) const
{
if (!m_client)
return false;
eth::ClientGuard l(const_cast<Client*>(m_client));
return client()->postState().addressHasCode(_a);
return m_client ? client()->codeAt(_a).size() : false;
}
QString QEthereum::balanceAt(QString _a, int _block) const

64
neth/main.cpp

@ -481,10 +481,7 @@ int main(int argc, char** argv)
if (!remoteHost.empty())
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
if (mining)
{
ClientGuard g(&c);
c.startMining();
}
#if ETH_JSONRPC
auto_ptr<EthStubServer> jsonrpcServer;
@ -531,7 +528,6 @@ int main(int argc, char** argv)
{
eth::uint port;
iss >> port;
ClientGuard g(&c);
c.startNetwork((short)port);
}
else if (cmd == "connect")
@ -539,22 +535,18 @@ int main(int argc, char** argv)
string addr;
eth::uint port;
iss >> addr >> port;
ClientGuard g(&c);
c.connect(addr, (short)port);
}
else if (cmd == "netstop")
{
ClientGuard g(&c);
c.stopNetwork();
}
else if (cmd == "minestart")
{
ClientGuard g(&c);
c.startMining();
}
else if (cmd == "minestop")
{
ClientGuard g(&c);
c.stopMining();
}
#if ETH_JSONRPC
@ -604,13 +596,12 @@ int main(int argc, char** argv)
}
else if (cmd == "balance")
{
u256 balance = c.state().balance(us.address());
u256 balance = c.balanceAt(us.address(), 0);
ccout << "Current balance:" << endl;
ccout << toString(balance) << endl;
}
else if (cmd == "transact")
{
ClientGuard g(&c);
auto const& bc = c.blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
@ -663,7 +654,7 @@ int main(int argc, char** argv)
ssbd << bbd;
cnote << ssbd.str();
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 > 0)
@ -688,7 +679,6 @@ int main(int argc, char** argv)
}
else if (cmd == "send")
{
ClientGuard g(&c);
vector<string> s;
s.push_back("Address");
vector<string> l;
@ -720,7 +710,7 @@ int main(int argc, char** argv)
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
u256 minGas = (u256)c.state().callGas(0, 0);
u256 minGas = (u256)Client::txGas(0, 0);
Address dest = h160(fromHex(fields[0]));
c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice);
}
@ -728,7 +718,6 @@ int main(int argc, char** argv)
}
else if (cmd == "contract")
{
ClientGuard g(&c);
auto const& bc = c.blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
@ -782,7 +771,7 @@ int main(int argc, char** argv)
cnote << "Init:";
cnote << ssc.str();
}
u256 minGas = (u256)c.state().createGas(init.size(), 0);
u256 minGas = (u256)Client::txGas(init.size(), 0);
if (endowment < 0)
cwarn << "Invalid endowment";
else if (gasPrice < info.minGasPrice)
@ -804,16 +793,15 @@ int main(int argc, char** argv)
cwarn << "Invalid address length";
else
{
ClientGuard g(&c);
auto h = h160(fromHex(rechex));
auto address = h160(fromHex(rechex));
stringstream s;
try
{
auto storage = c.state().storage(h);
auto storage = c.storageAt(address);
for (auto const& i: storage)
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";
ofstream ofs;
@ -848,9 +836,6 @@ int main(int argc, char** argv)
// Lock to prevent corrupt block-chain errors
ClientGuard g(&c);
auto const& st = c.state();
auto const& bc = c.blockChain();
ccout << "Genesis hash: " << bc.genesisHash() << endl;
@ -869,7 +854,7 @@ int main(int argc, char** argv)
auto s = t.receiveAddress ?
boost::format(" %1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) %
(st.addressHasCode(t.receiveAddress) ? '*' : '-') %
(c.codeAt(t.receiveAddress, 0).size() ? '*' : '-') %
toString(t.receiveAddress) %
toString(formatBalance(t.value)) %
toString((unsigned)t.nonce) :
@ -894,7 +879,7 @@ int main(int argc, char** argv)
auto s = t.receiveAddress ?
boost::format("%1% %2%> %3%: %4% [%5%]") %
toString(t.safeSender()) %
(st.addressHasCode(t.receiveAddress) ? '*' : '-') %
(c.codeAt(t.receiveAddress, 0).size() ? '*' : '-') %
toString(t.receiveAddress) %
toString(formatBalance(t.value)) %
toString((unsigned)t.nonce) :
@ -912,38 +897,29 @@ int main(int argc, char** argv)
// Contracts and addresses
y = 1;
int cc = 1;
auto acs = st.addresses();
auto acs = c.addresses();
for (auto const& i: acs)
{
auto r = i.first;
if (st.addressHasCode(r))
if (c.codeAt(i, 0).size())
{
auto s = boost::format("%1%%2% : %3% [%4%]") %
toString(r) %
pretty(r, st) %
toString(formatBalance(i.second)) %
toString((unsigned)st.transactionsFrom(i.first));
toString(i) %
toString(formatBalance(c.balanceAt(i, 0))) %
toString((unsigned)c.countAt(i, 0));
mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth);
if (cc > qheight - 2)
break;
}
}
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%]") %
toString(r) %
pretty(r, st) %
toString(formatBalance(i.second)) %
toString((unsigned)st.transactionsFrom(i.first));
toString(i) %
toString(formatBalance(c.balanceAt(i, 0))) %
toString((unsigned)c.countAt(i, 0));
mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4);
if (y > height * 3 / 5 - 4)
break;
}
}
// Peers
y = 1;
for (PeerInfo const& i: c.peers())
@ -968,9 +944,9 @@ int main(int argc, char** argv)
// Balance
stringstream ssb;
u256 balance = c.state().balance(us.address());
u256 balance = c.balanceAt(us.address(), 0);
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";
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("port", m_port);
if (client()->peerServer())
{
bytes d = client()->peerServer()->savePeers();
bytes d = client()->savePeers();
if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size());
}
s.setValue("peers", m_peers);
s.setValue("geometry", saveGeometry());
@ -203,16 +200,8 @@ void Main::refreshNetwork()
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()
{
eth::ClientGuard l(client());
auto const& st = state();
auto d = client()->blockChain().details();
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)));
@ -221,7 +210,7 @@ void Main::refresh()
u256 totalBalance = 0;
for (auto i: m_myKeys)
{
u256 b = st.balance(i.address());
u256 b = m_client->balanceAt(i.address());
totalBalance += b;
}
ui->balance->setText(QString::fromStdString(formatBalance(totalBalance)));
@ -244,7 +233,7 @@ void Main::on_net_triggered(bool _auto)
else
client()->startNetwork(m_port, string(), 0, NodeMode::Full, m_idealPeers, "", ui->upnp->isChecked());
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
client()->stopNetwork();

Loading…
Cancel
Save