Browse Source

Merge branch 'develop' into p2p

cl-refactor
subtly 10 years ago
parent
commit
8aac2eeace
  1. 152
      alethzero/MainWin.cpp
  2. 121
      eth/main.cpp
  3. 54
      libethereum/Client.cpp
  4. 27
      libethereum/Client.h
  5. 39
      libethereum/State.cpp
  6. 55
      libethereum/State.h
  7. 2
      test/blockchain.cpp

152
alethzero/MainWin.cpp

@ -372,28 +372,6 @@ void Main::load(QString _s)
{ {
QString contents = QString::fromStdString(dev::asString(dev::contents(_s.toStdString()))); QString contents = QString::fromStdString(dev::asString(dev::contents(_s.toStdString())));
ui->webView->page()->runJavaScript(contents); ui->webView->page()->runJavaScript(contents);
/*
QFile fin(_s);
if (!fin.open(QFile::ReadOnly))
return;
QString line;
while (!fin.atEnd())
{
QString l = QString::fromUtf8(fin.readLine());
line.append(l);
if (line.count('"') % 2)
{
line.chop(1);
}
else if (line.endsWith("\\\n"))
line.chop(2);
else
{
ui->webView->page()->currentFrame()->evaluateJavaScript(line);
//eval(line);
line.clear();
}
}*/
} }
void Main::on_newTransaction_triggered() void Main::on_newTransaction_triggered()
@ -472,37 +450,17 @@ static Public stringToPublic(QString const& _a)
return Public(); return Public();
} }
//static Address g_newNameReg;
QString Main::pretty(dev::Address _a) const QString Main::pretty(dev::Address _a) const
{ {
/* static map<Address, QString> s_memos;
if (!s_memos.count(_a))
{*/
// if (!g_newNameReg)
auto g_newNameReg = getNameReg(); auto g_newNameReg = getNameReg();
if (g_newNameReg) if (g_newNameReg)
{ {
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a))))); QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)))));
// s_memos[_a] = s;
if (s.size()) if (s.size())
return s; return s;
} }
/* }
else
if (s_memos[_a].size())
return s_memos[_a];*/
h256 n; h256 n;
/*
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
n = ethereum()->stateAt(nameReg, (u160)(_a));
if (!n)
n = ethereum()->stateAt(m_nameReg, (u160)(_a));
*/
return fromRaw(n); return fromRaw(n);
} }
@ -527,41 +485,13 @@ Address Main::fromString(QString const& _n) const
if (_n == "(Create Contract)") if (_n == "(Create Contract)")
return Address(); return Address();
/* static map<QString, Address> s_memos;
if (!s_memos.count(_n))
{*/
// if (!g_newNameReg)
auto g_newNameReg = getNameReg(); auto g_newNameReg = getNameReg();
if (g_newNameReg) if (g_newNameReg)
{ {
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString())))); Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))));
// s_memos[_n] = a;
if (a) if (a)
return a; return a;
} }
/* }
else
if (s_memos[_n])
return s_memos[_n];
string sn = _n.toStdString();
if (sn.size() > 32)
sn.resize(32);
h256 n;
memcpy(n.data(), sn.data(), sn.size());
memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_n.size())
{
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a);
if (h256 a = ethereum()->stateAt(m_nameReg, n))
return right160(a);
}*/
if (_n.size() == 40) if (_n.size() == 40)
{ {
try try
@ -595,13 +525,6 @@ QString Main::lookup(QString const& _a) const
h256 n; h256 n;
memcpy(n.data(), sn.data(), sn.size()); memcpy(n.data(), sn.data(), sn.size());
/* string sn2 = _a.toStdString();
if (sn2.size() > 32)
sn2 = sha3(sn2, false);
h256 n2;
memcpy(n2.data(), sn2.data(), sn2.size());
*/
h256 ret; h256 ret;
// TODO: fix with the new DNSreg contract // TODO: fix with the new DNSreg contract
// if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0)) // if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0))
@ -1038,31 +961,6 @@ void Main::refreshBlockCount()
ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet")); ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet"));
} }
static bool blockMatch(string const& _f, BlockDetails const& _b, h256 _h, CanonBlockChain const& _bc)
{
try
{
if (_f.size() > 1 && _f.size() < 10 && _f[0] == '#' && stoul(_f.substr(1)) == _b.number)
return true;
}
catch (...) {}
if (toHex(_h.ref()).find(_f) != string::npos)
return true;
BlockInfo bi(_bc.block(_h));
string info = toHex(bi.stateRoot.ref()) + " " + toHex(bi.coinbaseAddress.ref()) + " " + toHex(bi.transactionsRoot.ref()) + " " + toHex(bi.sha3Uncles.ref());
if (info.find(_f) != string::npos)
return true;
return false;
}
static bool transactionMatch(string const& _f, Transaction const& _t)
{
string info = toHex(_t.receiveAddress().ref()) + " " + toHex(_t.sha3().ref()) + " " + toHex(_t.sha3(eth::WithoutSignature).ref()) + " " + toHex(_t.sender().ref());
if (info.find(_f) != string::npos)
return true;
return false;
}
void Main::on_turboMining_triggered() void Main::on_turboMining_triggered()
{ {
ethereum()->setTurboMining(ui->turboMining->isChecked()); ethereum()->setTurboMining(ui->turboMining->isChecked());
@ -1072,31 +970,46 @@ void Main::refreshBlockChain()
{ {
cwatch << "refreshBlockChain()"; cwatch << "refreshBlockChain()";
QByteArray oldSelected = ui->blocks->count() ? ui->blocks->currentItem()->data(Qt::UserRole).toByteArray() : QByteArray(); // TODO: keep the same thing highlighted.
ui->blocks->clear(); // TODO: refactor into MVC
// TODO: use get by hash/number
// TODO: transactions, log addresses, log topics
string filter = ui->blockChainFilter->text().toLower().toStdString();
auto const& bc = ethereum()->blockChain(); auto const& bc = ethereum()->blockChain();
unsigned i = (ui->showAll->isChecked() || !filter.empty()) ? (unsigned)-1 : 10; QStringList filters = ui->blockChainFilter->text().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
for (auto h = bc.currentHash(); bc.details(h) && i; h = bc.details(h).parent, --i)
h256Set blocks;
for (QString f: filters)
if (f.size() == 64)
{ {
auto d = bc.details(h); h256 h(f.toStdString());
auto bm = blockMatch(filter, d, h, bc); if (bc.isKnown(h))
if (bm) blocks.insert(h);
}
else if (f.toLongLong() <= bc.number())
blocks.insert(bc.numberHash(u256(f.toLongLong())));
/*else if (f.size() == 40)
{ {
Address h(f[0]);
if (bc.(h))
blocks.insert(h);
}*/
QByteArray oldSelected = ui->blocks->count() ? ui->blocks->currentItem()->data(Qt::UserRole).toByteArray() : QByteArray();
ui->blocks->clear();
auto showBlock = [&](h256 const& h) {
auto d = bc.details(h);
QListWidgetItem* blockItem = new QListWidgetItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), ui->blocks); QListWidgetItem* blockItem = new QListWidgetItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), ui->blocks);
auto hba = QByteArray((char const*)h.data(), h.size); auto hba = QByteArray((char const*)h.data(), h.size);
blockItem->setData(Qt::UserRole, hba); blockItem->setData(Qt::UserRole, hba);
if (oldSelected == hba) if (oldSelected == hba)
blockItem->setSelected(true); blockItem->setSelected(true);
}
int n = 0; int n = 0;
auto b = bc.block(h); auto b = bc.block(h);
for (auto const& i: RLP(b)[1]) for (auto const& i: RLP(b)[1])
{ {
Transaction t(i.data(), CheckSignature::Sender); Transaction t(i.data(), CheckSignature::Sender);
if (bm || transactionMatch(filter, t))
{
QString s = t.receiveAddress() ? QString s = t.receiveAddress() ?
QString(" %2 %5> %3: %1 [%4]") QString(" %2 %5> %3: %1 [%4]")
.arg(formatBalance(t.value()).c_str()) .arg(formatBalance(t.value()).c_str())
@ -1115,12 +1028,23 @@ void Main::refreshBlockChain()
txItem->setData(Qt::UserRole + 1, n); txItem->setData(Qt::UserRole + 1, n);
if (oldSelected == hba) if (oldSelected == hba)
txItem->setSelected(true); txItem->setSelected(true);
}
n++; n++;
} }
};
if (filters.empty())
{
unsigned i = ui->showAll->isChecked() ? (unsigned)-1 : 10;
for (auto h = bc.currentHash(); bc.details(h) && i; h = bc.details(h).parent, --i)
{
showBlock(h);
if (h == bc.genesisHash()) if (h == bc.genesisHash())
break; break;
} }
}
else
for (auto const& h: blocks)
showBlock(h);
if (!ui->blocks->currentItem()) if (!ui->blocks->currentItem())
ui->blocks->setCurrentRow(0); ui->blocks->setCurrentRow(0);

121
eth/main.cpp

@ -74,6 +74,9 @@ void interactiveHelp()
<< " jsonstop Stops the JSON-RPC server." << endl << " jsonstop Stops the JSON-RPC server." << endl
<< " connect <addr> <port> Connects to a specific peer." << endl << " connect <addr> <port> Connects to a specific peer." << endl
<< " verbosity (<level>) Gets or sets verbosity level." << endl << " verbosity (<level>) Gets or sets verbosity level." << endl
<< " setetherprice <p> Resets the ether price." << endl
<< " setpriority <p> Resets the transaction priority." << endl
<< " minestart Starts mining." << endl
<< " minestart Starts mining." << endl << " minestart Starts mining." << endl
<< " minestop Stops mining." << endl << " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl << " mineforce <enable> Forces mining, even when there are no transactions." << endl
@ -85,12 +88,12 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl << " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl << " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl << " peers List the peers that are connected" << endl
<< " listAccounts List the accounts on the network." << endl << " listaccounts List the accounts on the network." << endl
<< " listContracts List the contracts on the network." << endl << " listcontracts List the contracts on the network." << endl
<< " setSecret <secret> Set the secret to the hex secret key." <<endl << " setsecret <secret> Set the secret to the hex secret key." <<endl
<< " setAddress <addr> Set the coinbase (mining payout) address." <<endl << " setaddress <addr> Set the coinbase (mining payout) address." <<endl
<< " exportConfig <path> Export the config (.RLP) to the path provided." <<endl << " exportconfig <path> Export the config (.RLP) to the path provided." <<endl
<< " importConfig <path> Import the config (.RLP) from the path provided." <<endl << " importconfig <path> Import the config (.RLP) from the path provided." <<endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl << " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " dumptrace <block> <index> <filename> <format> Dumps a transaction trace" << endl << "to <filename>. <format> should be one of pretty, standard, standard+." << endl << " dumptrace <block> <index> <filename> <format> Dumps a transaction trace" << endl << "to <filename>. <format> should be one of pretty, standard, standard+." << endl
<< " dumpreceipt <block> <index> Dumps a transation receipt." << endl << " dumpreceipt <block> <index> Dumps a transation receipt." << endl
@ -104,9 +107,11 @@ void help()
<< "Options:" << endl << "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl << " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl << " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (Default: 15)." << endl
<< " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl << " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl << " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl << " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
<< " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << endl
<< " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl << " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl
<< " -h,--help Show this help message and exit." << endl << " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
@ -115,11 +120,12 @@ void help()
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
#endif #endif
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl << " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl << " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl << " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl << " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl << " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl << " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl << " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
@ -212,6 +218,9 @@ int main(int argc, char** argv)
bool structuredLogging = false; bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S"; string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string clientName; string clientName;
TransactionPriority priority = TransactionPriority::Medium;
double etherPrice = 30.679;
double blockFees = 15.0;
// Init defaults // Init defaults
Defaults::get(); Defaults::get();
@ -289,6 +298,48 @@ int main(int argc, char** argv)
structuredLogging = true; structuredLogging = true;
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i]; dbPath = argv[++i];
else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
{
try {
blockFees = stof(argv[++i]);
}
catch (...) {
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
}
else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc)
{
try {
etherPrice = stof(argv[++i]);
}
catch (...) {
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
}
else if ((arg == "-P" || arg == "--priority") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
if (m == "lowest")
priority = TransactionPriority::Lowest;
else if (m == "low")
priority = TransactionPriority::Low;
else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
priority = TransactionPriority::Medium;
else if (m == "high")
priority = TransactionPriority::High;
else if (m == "highest")
priority = TransactionPriority::Highest;
else
try {
priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
}
catch (...) {
cerr << "Unknown " << arg << " option: " << m << endl;
return -1;
}
}
else if ((arg == "-m" || arg == "--mining") && i + 1 < argc) else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
{ {
string m = argv[++i]; string m = argv[++i];
@ -301,7 +352,7 @@ int main(int argc, char** argv)
mining = stoi(m); mining = stoi(m);
} }
catch (...) { catch (...) {
cerr << "Unknown -m/--mining option: " << m << endl; cerr << "Unknown " << arg << " option: " << m << endl;
return -1; return -1;
} }
} }
@ -373,10 +424,12 @@ int main(int argc, char** argv)
miners miners
); );
web3.setIdealPeerCount(peers); web3.setIdealPeerCount(peers);
std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr; eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
StructuredLogger::starting(clientImplString, dev::Version); StructuredLogger::starting(clientImplString, dev::Version);
if (c) if (c)
{ {
c->setGasPricer(gasPricer);
c->setForceMining(forceMining); c->setForceMining(forceMining);
c->setAddress(coinbase); c->setAddress(coinbase);
} }
@ -435,6 +488,7 @@ int main(int argc, char** argv)
istringstream iss(l); istringstream iss(l);
string cmd; string cmd;
iss >> cmd; iss >> cmd;
boost::to_lower(cmd);
if (cmd == "netstart") if (cmd == "netstart")
{ {
iss >> netPrefs.listenPort; iss >> netPrefs.listenPort;
@ -466,6 +520,42 @@ int main(int argc, char** argv)
iss >> enable; iss >> enable;
c->setForceMining(isTrue(enable)); c->setForceMining(isTrue(enable));
} }
else if (c && cmd == "setblockfees")
{
iss >> blockFees;
gasPricer->setRefBlockFees(u256(blockFees * 1000));
cout << "Block fees: " << blockFees << endl;
}
else if (c && cmd == "setetherprice")
{
iss >> etherPrice;
gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice));
cout << "ether Price: " << etherPrice << endl;
}
else if (c && cmd == "setpriority")
{
string m;
iss >> m;
boost::to_lower(m);
if (m == "lowest")
priority = TransactionPriority::Lowest;
else if (m == "low")
priority = TransactionPriority::Low;
else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
priority = TransactionPriority::Medium;
else if (m == "high")
priority = TransactionPriority::High;
else if (m == "highest")
priority = TransactionPriority::Highest;
else
try {
priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
}
catch (...) {
cerr << "Unknown priority: " << m << endl;
}
cout << "Priority: " << (int)priority << "/8" << endl;
}
else if (cmd == "verbosity") else if (cmd == "verbosity")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
@ -536,6 +626,9 @@ int main(int argc, char** argv)
iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata; iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata;
if (!gasPrice)
gasPrice = gasPricer->bid(priority);
cnote << "Data:"; cnote << "Data:";
cnote << sdata; cnote << sdata;
bytes data = dev::eth::parseData(sdata); bytes data = dev::eth::parseData(sdata);
@ -582,7 +675,7 @@ int main(int argc, char** argv)
else else
cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
} }
else if (c && cmd == "listContracts") else if (c && cmd == "listcontracts")
{ {
auto acs =c->addresses(); auto acs =c->addresses();
string ss; string ss;
@ -593,7 +686,7 @@ int main(int argc, char** argv)
cout << ss << endl; cout << ss << endl;
} }
} }
else if (c && cmd == "listAccounts") else if (c && cmd == "listaccounts")
{ {
auto acs =c->addresses(); auto acs =c->addresses();
string ss; string ss;
@ -809,7 +902,7 @@ int main(int argc, char** argv)
} }
} }
} }
else if (cmd == "setSecret") else if (cmd == "setsecret")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
{ {
@ -820,7 +913,7 @@ int main(int argc, char** argv)
else else
cwarn << "Require parameter: setSecret HEXSECRETKEY"; cwarn << "Require parameter: setSecret HEXSECRETKEY";
} }
else if (cmd == "setAddress") else if (cmd == "setaddress")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
{ {
@ -848,7 +941,7 @@ int main(int argc, char** argv)
else else
cwarn << "Require parameter: setAddress HEXADDRESS"; cwarn << "Require parameter: setAddress HEXADDRESS";
} }
else if (cmd == "exportConfig") else if (cmd == "exportconfig")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
{ {
@ -861,7 +954,7 @@ int main(int argc, char** argv)
else else
cwarn << "Require parameter: exportConfig PATH"; cwarn << "Require parameter: exportConfig PATH";
} }
else if (cmd == "importConfig") else if (cmd == "importconfig")
{ {
if (iss.peek() != -1) if (iss.peek() != -1)
{ {

54
libethereum/Client.cpp

@ -60,16 +60,58 @@ void VersionChecker::setOk()
} }
} }
void BasicGasPricer::update(BlockChain const& _bc)
{
unsigned c = 0;
h256 p = _bc.currentHash();
m_gasPerBlock = _bc.info(p).gasLimit;
map<u256, unsigned> dist;
unsigned total;
while (c < 1000 && p)
{
BlockInfo bi = _bc.info(p);
if (bi.transactionsRoot != EmptyTrie)
{
auto bb = _bc.block(p);
RLP r(bb);
BlockReceipts brs(_bc.receipts(bi.hash));
for (unsigned i = 0; i < r[1].size(); ++i)
{
auto gu = brs.receipts[i].gasUsed();
dist[Transaction(r[1][i].data(), CheckSignature::None).gasPrice()] += (unsigned)brs.receipts[i].gasUsed();
total += (unsigned)gu;
}
}
p = bi.parentHash;
++c;
}
if (total > 0)
{
unsigned t = 0;
unsigned q = 1;
m_octiles[0] = dist.begin()->first;
for (auto const& i: dist)
{
for (; t <= total * q / 8 && t + i.second > total * q / 8; ++q)
m_octiles[q] = i.first;
if (q > 7)
break;
}
m_octiles[8] = dist.rbegin()->first;
}
}
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners): Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners):
Worker("eth"), Worker("eth"),
m_vc(_dbPath), m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean), m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_gp(u256("60000000000000")), m_gp(new TrivialGasPricer),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)), m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB), m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB) m_postMine(Address(), m_stateDB)
{ {
m_gp.updateQuartiles(m_bc); m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
@ -85,16 +127,16 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean,
startWorking(); startWorking();
} }
Client::Client(p2p::Host* _extNet, u256 weiPerCent, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners): Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners):
Worker("eth"), Worker("eth"),
m_vc(_dbPath), m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean), m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_gp(weiPerCent), m_gp(_gp),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)), m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB), m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB) m_postMine(Address(), m_stateDB)
{ {
m_gp.updateQuartiles(m_bc); m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
@ -620,7 +662,7 @@ void Client::doWork()
// returns h256s as blooms, once for each transaction. // returns h256s as blooms, once for each transaction.
cwork << "postSTATE <== TQ"; cwork << "postSTATE <== TQ";
TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, m_gp); TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.size()) if (newPendingReceipts.size())
{ {
for (size_t i = 0; i < newPendingReceipts.size(); i++) for (size_t i = 0; i < newPendingReceipts.size(); i++)

27
libethereum/Client.h

@ -160,6 +160,26 @@ private:
State m_state; State m_state;
}; };
class BasicGasPricer: public GasPricer
{
public:
explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {}
void setRefPrice(u256 _weiPerRef) { m_weiPerRef = _weiPerRef; }
void setRefBlockFees(u256 _refsPerBlock) { m_refsPerBlock = _refsPerBlock; }
u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; }
u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); }
void update(BlockChain const& _bc) override;
private:
u256 m_weiPerRef;
u256 m_refsPerBlock;
u256 m_gasPerBlock = 1000000;
std::array<u256, 9> m_octiles;
};
/** /**
* @brief Main API hub for interfacing with Ethereum. * @brief Main API hub for interfacing with Ethereum.
*/ */
@ -179,7 +199,7 @@ public:
explicit Client( explicit Client(
p2p::Host* _host, p2p::Host* _host,
u256 _weiPerCent, std::shared_ptr<GasPricer> _gpForAdoption, // pass it in with new.
std::string const& _dbPath = std::string(), std::string const& _dbPath = std::string(),
bool _forceClean = false, bool _forceClean = false,
u256 _networkId = 0, u256 _networkId = 0,
@ -189,6 +209,9 @@ public:
/// Destructor. /// Destructor.
virtual ~Client(); virtual ~Client();
/// Resets the gas pricer to some other object.
void setGasPricer(std::shared_ptr<GasPricer> _gp) { m_gp = _gp; }
/// Submits the given message-call transaction. /// Submits the given message-call transaction.
virtual void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); virtual void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
@ -361,7 +384,7 @@ private:
CanonBlockChain m_bc; ///< Maintains block database. CanonBlockChain 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).
GasPricer m_gp; ///< The gas pricer. std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine. mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
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.

39
libethereum/State.cpp

@ -464,45 +464,6 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
return ret; return ret;
} }
void GasPricer::updateQuartiles(BlockChain const& _bc)
{
unsigned c = 0;
h256 p = _bc.currentHash();
map<u256, unsigned> dist;
unsigned total;
while (c < 1000 && p)
{
BlockInfo bi = _bc.info(p);
if (bi.transactionsRoot != EmptyTrie)
{
auto bb = _bc.block(p);
RLP r(bb);
BlockReceipts brs(_bc.receipts(bi.hash));
for (unsigned i = 0; i < r[1].size(); ++i)
{
auto gu = brs.receipts[i].gasUsed();
dist[Transaction(r[1][i].data(), CheckSignature::None).gasPrice()] += (unsigned)brs.receipts[i].gasUsed();
total += (unsigned)gu;
}
}
p = bi.parentHash;
++c;
}
if (total > 0)
{
unsigned t = 0;
unsigned q = 1;
for (auto const& i: dist)
{
for (; t <= total * q / 4 && t + i.second > total * q / 4; ++q)
m_quartiles[q - 1] = i.first;
if (q > 3)
break;
}
}
}
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
{ {
// m_currentBlock is assumed to be prepopulated and reset. // m_currentBlock is assumed to be prepopulated and reset.

55
libethereum/State.h

@ -47,6 +47,7 @@ namespace eth
{ {
class BlockChain; class BlockChain;
class State;
struct StateChat: public LogChannel { static const char* name() { return "-S-"; } static const int verbosity = 4; }; struct StateChat: public LogChannel { static const char* name() { return "-S-"; } static const int verbosity = 4; };
struct StateTrace: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 7; }; struct StateTrace: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 7; };
@ -55,7 +56,32 @@ struct StateSafeExceptions: public LogChannel { static const char* name() { retu
enum class BaseState { Empty, CanonGenesis }; enum class BaseState { Empty, CanonGenesis };
class GasPricer; enum class TransactionPriority
{
Lowest = 0,
Low = 2,
Medium = 4,
High = 6,
Highest = 8
};
class GasPricer
{
public:
GasPricer() {}
virtual u256 ask(State const&) const = 0;
virtual u256 bid(TransactionPriority _p = TransactionPriority::Medium) const = 0;
virtual void update(BlockChain const&) {}
};
class TrivialGasPricer: public GasPricer
{
protected:
u256 ask(State const&) const override { return 10 * szabo; }
u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return 10 * szabo; }
};
/** /**
* @brief Model of the current state of the ledger. * @brief Model of the current state of the ledger.
@ -153,6 +179,7 @@ public:
/// Like sync but only operate on _tq, killing the invalid/old ones. /// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const; bool cull(TransactionQueue& _tq) const;
/// Returns the last few block hashes of the current chain.
LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const; LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const;
/// Execute a given transaction. /// Execute a given transaction.
@ -370,32 +397,6 @@ void commit(std::map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Addr
} }
} }
enum class TransactionPriority
{
Low = 0,
Medium = 1,
High = 2
};
class GasPricer
{
public:
explicit GasPricer(u256 _weiPerCent): m_weiPerCent(_weiPerCent) {}
u256 ask(State const&) const { return m_weiPerCent * m_centsPerBlock / m_gasPerBlock; }
u256 bid(TransactionPriority _p = TransactionPriority::Medium) const { return m_quartiles[(int)_p]; }
void updateRefPrice(u256 _weiPerCent) { m_weiPerCent = _weiPerCent; }
void updateRefRequirement(u256 _centsPerBlock) { m_centsPerBlock = _centsPerBlock; }
void updateQuartiles(BlockChain const& _bc);
private:
u256 m_weiPerCent;
u256 m_centsPerBlock = 15;
u256 m_gasPerBlock = 1000000;
std::array<u256, 100> m_quartiles;
};
} }
} }

2
test/blockchain.cpp

@ -87,7 +87,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
// get txs // get txs
TransactionQueue txs; TransactionQueue txs;
GasPricer gp(10000); TrivialGasPricer gp;
BOOST_REQUIRE(blObj.count("transactions")); BOOST_REQUIRE(blObj.count("transactions"));
for (auto const& txObj: blObj["transactions"].get_array()) for (auto const& txObj: blObj["transactions"].get_array())
{ {

Loading…
Cancel
Save