Browse Source

First draft at splitting State.

Continuation of State split.

libethereum building again.

Compile fixes galore.
Remove a lot of code redundancy.

mix using new state/block classes
cl-refactor
Gav Wood 9 years ago
parent
commit
9f756124b0
  1. 11
      alethzero/MainWin.cpp
  2. 8
      alethzero/Transact.cpp
  3. 780
      eth/main.cpp
  4. 16
      ethvm/main.cpp
  5. 2
      evmjit/libevmjit-cpp/Env.cpp
  6. 2
      evmjit/libevmjit-cpp/JitVM.cpp
  7. 2
      evmjit/libevmjit/Compiler.cpp
  8. 12
      exp/main.cpp
  9. 2
      libdevcore/Exceptions.h
  10. 6
      libethcore/BlockInfo.h
  11. 55
      libethereum/Account.cpp
  12. 37
      libethereum/Account.h
  13. 2
      libethereum/BasicGasPricer.h
  14. 810
      libethereum/Block.cpp
  15. 310
      libethereum/Block.h
  16. 22
      libethereum/BlockChain.cpp
  17. 14
      libethereum/BlockChain.h
  18. 29
      libethereum/CanonBlockChain.cpp
  19. 4
      libethereum/CanonBlockChain.h
  20. 65
      libethereum/Client.cpp
  21. 28
      libethereum/Client.h
  22. 23
      libethereum/ClientBase.cpp
  23. 15
      libethereum/ClientBase.h
  24. 37
      libethereum/Executive.cpp
  25. 39
      libethereum/Executive.h
  26. 10
      libethereum/ExtVM.cpp
  27. 4
      libethereum/ExtVM.h
  28. 6
      libethereum/GasPricer.h
  29. 2
      libethereum/Interface.h
  30. 4
      libethereum/LogFilter.cpp
  31. 3
      libethereum/LogFilter.h
  32. 794
      libethereum/State.cpp
  33. 153
      libethereum/State.h
  34. 6
      libevm/ExtVMFace.cpp
  35. 66
      libevm/ExtVMFace.h
  36. 12
      libevm/VM.cpp
  37. 16
      libtestutils/BlockChainLoader.cpp
  38. 7
      libtestutils/BlockChainLoader.h
  39. 4
      libtestutils/FixedClient.cpp
  40. 12
      libtestutils/FixedClient.h
  41. 57
      libtestutils/StateLoader.cpp
  42. 49
      libtestutils/StateLoader.h
  43. 2
      libweb3jsonrpc/JsonHelper.cpp
  44. 11
      libweb3jsonrpc/WebThreeStubServer.cpp
  45. 71
      mix/MixClient.cpp
  46. 17
      mix/MixClient.h
  47. 128
      test/TestHelper.cpp
  48. 21
      test/TestHelper.h
  49. 2
      test/libethereum/ClientBase.cpp
  50. 20
      test/libethereum/blockchain.cpp
  51. 2
      test/libethereum/gaspricer.cpp
  52. 12
      test/libethereum/stateOriginal.cpp
  53. 2
      test/libevm/vm.cpp
  54. 2
      test/libsolidity/solidityExecutionFramework.h
  55. 6
      test/libweb3jsonrpc/jsonrpc.cpp
  56. 4
      third/MainWin.cpp

11
alethzero/MainWin.cpp

@ -1149,7 +1149,7 @@ void Main::setBeneficiary(Address const& _b)
ui->ourAccounts->item(i)->setCheckState(h == _b ? Qt::Checked : Qt::Unchecked);
}
m_beneficiary = _b;
ethereum()->setAddress(_b);
ethereum()->setBeneficiary(_b);
}
void Main::on_ourAccounts_itemClicked(QListWidgetItem* _i)
@ -1664,7 +1664,7 @@ void Main::on_blocks_currentItemChanged()
s << "<div>D/TD: <b>" << info.difficulty() << "</b>/<b>" << details.totalDifficulty << "</b> = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "</div>";
s << "&nbsp;&emsp;&nbsp;Children: <b>" << details.children.size() << "</b></div>";
s << "<div>Gas used/limit: <b>" << info.gasUsed() << "</b>/<b>" << info.gasLimit() << "</b>" << "</div>";
s << "<div>Beneficiary: <b>" << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "</b>" << "</div>";
s << "<div>Beneficiary: <b>" << htmlEscaped(pretty(info.beneficiary())) << " " << info.beneficiary() << "</b>" << "</div>";
s << "<div>Seed hash: <b>" << info.seedHash() << "</b>" << "</div>";
s << "<div>Mix hash: <b>" << info.mixHash() << "</b>" << "</div>";
s << "<div>Nonce: <b>" << info.nonce() << "</b>" << "</div>";
@ -1697,7 +1697,7 @@ void Main::on_blocks_currentItemChanged()
s << line << "Hash: <b>" << uncle.hash() << "</b>" << "</div>";
s << line << "Parent: <b>" << uncle.parentHash() << "</b>" << "</div>";
s << line << "Number: <b>" << uncle.number() << "</b>" << "</div>";
s << line << "Coinbase: <b>" << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "</b>" << "</div>";
s << line << "Coinbase: <b>" << htmlEscaped(pretty(uncle.beneficiary())) << " " << uncle.beneficiary() << "</b>" << "</div>";
s << line << "Seed hash: <b>" << uncle.seedHash() << "</b>" << "</div>";
s << line << "Mix hash: <b>" << uncle.mixHash() << "</b>" << "</div>";
s << line << "Nonce: <b>" << uncle.nonce() << "</b>" << "</div>";
@ -1787,7 +1787,8 @@ void Main::on_debugCurrent_triggered()
unsigned txi = item->data(Qt::UserRole + 1).toInt();
bytes t = ethereum()->blockChain().transaction(h, txi);
State s(ethereum()->state(txi, h));
Executive e(s, ethereum()->blockChain());
BlockInfo bi(ethereum()->blockChain().info(h));
Executive e(s, ethereum()->blockChain(), EnvInfo(bi));
Debugger dw(this, this);
dw.populate(e, Transaction(t, CheckTransaction::Everything));
dw.exec();
@ -2020,7 +2021,7 @@ void Main::on_mine_triggered()
if (ui->mine->isChecked())
{
// EthashAux::computeFull(ethereum()->blockChain().number());
ethereum()->setAddress(m_beneficiary);
ethereum()->setBeneficiary(m_beneficiary);
ethereum()->startMining();
}
else

8
alethzero/Transact.cpp

@ -522,13 +522,13 @@ void Transact::on_debug_clicked()
try
{
State st(ethereum()->postState());
Block postState(ethereum()->postState());
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, st.transactionsFrom(from)) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, st.transactionsFrom(from));
Transaction(value(), gasPrice(), ui->gas->value(), m_data, postState.transactionsFrom(from)) :
Transaction(value(), gasPrice(), ui->gas->value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, postState.transactionsFrom(from));
t.forceSender(from);
Debugger dw(m_context, this);
Executive e(st, ethereum()->blockChain(), 0);
Executive e(postState, ethereum()->blockChain(), 0);
dw.populate(e, t);
dw.exec();
}

780
eth/main.cpp

@ -302,783 +302,7 @@ void stopMiningAfterXBlocks(eth::Client* _c, unsigned _start, unsigned& io_minin
this_thread::sleep_for(chrono::milliseconds(100));
}
void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasPricer, WebThreeDirect& web3, KeyManager& keyManager, string& logbuf, string& additional, function<string(string const&)> getPassword, function<string(Address const&)> getAccountPassword, NetworkPreferences netPrefs, Address beneficiary, Address signingKey, TransactionPriority priority)
{
additional = "Press Enter";
string l;
while (!g_exit)
{
g_silence = false;
cout << logbuf << "Press Enter" << flush;
std::getline(cin, l);
logbuf.clear();
g_silence = true;
#if ETH_READLINE
if (l.size())
add_history(l.c_str());
if (auto c = readline("> "))
{
l = c;
free(c);
}
else
break;
#else
string l;
cout << "> " << flush;
std::getline(cin, l);
#endif
istringstream iss(l);
string cmd;
iss >> cmd;
boost::to_lower(cmd);
if (cmd == "netstart")
{
iss >> netPrefs.listenPort;
web3.setNetworkPreferences(netPrefs);
web3.startNetwork();
}
else if (cmd == "connect")
{
string addrPort;
iss >> addrPort;
web3.addNode(p2p::NodeId(), addrPort);
}
else if (cmd == "netstop")
web3.stopNetwork();
else if (c && cmd == "minestart")
c->startMining();
else if (c && cmd == "minestop")
c->stopMining();
else if (c && cmd == "mineforce")
{
string enable;
iss >> enable;
c->setForceMining(isTrue(enable));
}
else if (cmd == "verbosity")
{
if (iss.peek() != -1)
iss >> g_logVerbosity;
cout << "Verbosity: " << g_logVerbosity << endl;
}
else if (cmd == "address")
{
cout << "Current mining beneficiary:" << endl << beneficiary << endl;
cout << "Current signing account:" << endl << signingKey << endl;
}
else if (c && cmd == "blockhashfromnumber")
{
if (iss.peek() != -1)
{
unsigned number;
iss >> number;
cout << " hash of block: " << c->hashFromNumber(number).hex() << endl;
}
}
else if (c && cmd == "numberfromblockhash")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
h256 hash = h256(fromHex(stringHash));
cout << " number of block: " << c->numberFromHash(hash) << endl;
}
}
else if (c && cmd == "block")
cout << "Current block: " << c->blockChain().details().number << endl;
else if (c && cmd == "blockqueue")
cout << "Current blockqueue status: " << endl << c->blockQueueStatus() << endl;
else if (c && cmd == "sync")
cout << "Current sync status: " << endl << c->syncStatus() << endl;
else if (c && cmd == "hashrate")
cout << "Current hash rate: " << toString(c->hashrate()) << " hashes per second." << endl;
else if (c && cmd == "findblock")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
h256 hash = h256(fromHex(stringHash));
// search in blockchain
cout << "search in blockchain... " << endl;
try
{
cout << c->blockInfo(hash) << endl;
}
catch(Exception& _e)
{
cout << "block not in blockchain" << endl;
cout << boost::diagnostic_information(_e) << endl;
}
cout << "search in blockqueue... " << endl;
switch(c->blockQueue().blockStatus(hash))
{
case QueueStatus::Ready:
cout << "Ready" << endl;
break;
case QueueStatus::Importing:
cout << "Importing" << endl;
break;
case QueueStatus::UnknownParent:
cout << "UnknownParent" << endl;
break;
case QueueStatus::Bad:
cout << "Bad" << endl;
break;
case QueueStatus::Unknown:
cout << "Unknown" << endl;
break;
default:
cout << "invalid queueStatus" << endl;
}
}
else
cwarn << "Require parameter: findblock HASH";
}
else if (c && cmd == "firstunknown")
cout << "first unknown blockhash: " << c->blockQueue().firstUnknown().hex() << endl;
else if (c && cmd == "retryunknown")
c->retryUnknown();
else if (cmd == "peers")
{
for (auto it: web3.peers())
cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
<< endl;
}
else if (cmd == "newaccount")
{
string name;
std::getline(iss, name);
auto s = Secret::random();
string password;
while (password.empty())
{
password = getPassword("Please enter a password to protect this key (press enter for protection only be the MASTER password/keystore): ");
string confirm = getPassword("Please confirm the password by entering it again: ");
if (password != confirm)
{
cout << "Passwords were different. Try again." << endl;
password.clear();
}
}
if (!password.empty())
{
cout << "Enter a hint for this password: " << flush;
string hint;
std::getline(cin, hint);
keyManager.import(s, name, password, hint);
}
else
keyManager.import(s, name);
cout << "New account created: " << toAddress(s);
}
else if (c && cmd == "accounts")
{
cout << "Accounts:" << endl;
u256 total = 0;
for (auto const& address: keyManager.accounts())
{
auto b = c->balanceAt(address);
cout << ((address == signingKey) ? "SIGNING " : " ") << ((address == beneficiary) ? "COINBASE " : " ") << keyManager.accountName(address) << " (" << address << "): " << formatBalance(b) << " = " << b << " wei" << endl;
total += b;
}
cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl;
}
else if (c && cmd == "transact")
{
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
if (iss.peek() != -1)
{
string hexAddr;
u256 amount;
u256 gasPrice;
u256 gas;
string sechex;
string sdata;
iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata;
if (!gasPrice)
gasPrice = gasPricer->bid(priority);
cnote << "Data:";
cnote << sdata;
bytes data = dev::eth::parseData(sdata);
cnote << "Bytes:";
string sbd = asString(data);
bytes bbd = asBytes(sbd);
stringstream ssbd;
ssbd << bbd;
cnote << ssbd.str();
int ssize = sechex.length();
int size = hexAddr.length();
u256 minGas = (u256)Transaction::gasRequired(data, 0);
if (size < 40)
{
if (size > 0)
cwarn << "Invalid address length:" << size;
}
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else if (ssize < 40)
{
if (ssize > 0)
cwarn << "Invalid secret length:" << ssize;
}
else
{
try
{
Secret secret(fromHex(sechex));
Address dest = h160(fromHex(hexAddr));
c->submitTransaction(secret, amount, dest, data, gas, gasPrice);
}
catch (BadHexCharacter& _e)
{
cwarn << "invalid hex character, transaction rejected";
cwarn << boost::diagnostic_information(_e);
}
catch (...)
{
cwarn << "transaction rejected";
}
}
}
else
cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
}
else if (c && cmd == "transactnonce")
{
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
if (iss.peek() != -1)
{
string hexAddr;
u256 amount;
u256 gasPrice;
u256 gas;
string sechex;
string sdata;
u256 nonce;
iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata >> nonce;
if (!gasPrice)
gasPrice = gasPricer->bid(priority);
cnote << "Data:";
cnote << sdata;
bytes data = dev::eth::parseData(sdata);
cnote << "Bytes:";
string sbd = asString(data);
bytes bbd = asBytes(sbd);
stringstream ssbd;
ssbd << bbd;
cnote << ssbd.str();
int ssize = sechex.length();
int size = hexAddr.length();
u256 minGas = (u256)Transaction::gasRequired(data, 0);
if (size < 40)
{
if (size > 0)
cwarn << "Invalid address length:" << size;
}
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else if (ssize < 40)
{
if (ssize > 0)
cwarn << "Invalid secret length:" << ssize;
}
else
{
try
{
Secret secret(fromHex(sechex));
Address dest = h160(fromHex(hexAddr));
c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce);
}
catch (BadHexCharacter& _e)
{
cwarn << "invalid hex character, transaction rejected";
cwarn << boost::diagnostic_information(_e);
}
catch (...)
{
cwarn << "transaction rejected";
}
}
}
else
cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA NONCE";
}
else if (c && cmd == "txcreate")
{
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
if (iss.peek() != -1)
{
u256 amount;
u256 gasPrice;
u256 gas;
string sechex;
string sdata;
iss >> amount >> gasPrice >> gas >> sechex >> sdata;
if (!gasPrice)
gasPrice = gasPricer->bid(priority);
cnote << "Data:";
cnote << sdata;
bytes data = dev::eth::parseData(sdata);
cnote << "Bytes:";
string sbd = asString(data);
bytes bbd = asBytes(sbd);
stringstream ssbd;
ssbd << bbd;
cnote << ssbd.str();
int ssize = sechex.length();
u256 minGas = (u256)Transaction::gasRequired(data, 0);
if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else if (ssize < 40)
{
if (ssize > 0)
cwarn << "Invalid secret length:" << ssize;
}
else
{
try
{
Secret secret(fromHex(sechex));
cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl;
}
catch (BadHexCharacter& _e)
{
cwarn << "invalid hex character, transaction rejected";
cwarn << boost::diagnostic_information(_e);
}
catch (...)
{
cwarn << "transaction rejected";
}
}
}
else
cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET INIT";
}
#if ETH_FATDB
else if (c && cmd == "listcontracts")
{
auto acs =c->addresses();
string ss;
for (auto const& i: acs)
if ( c->codeAt(i, PendingBlock).size())
{
ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl;
}
}
else if (c && cmd == "listaccounts")
{
auto acs =c->addresses();
string ss;
for (auto const& i: acs)
if ( c->codeAt(i, PendingBlock).empty())
{
ss = toString(i) + " : " + toString( c->balanceAt(i)) + " [" + toString((unsigned) c->countAt(i)) + "]";
cout << ss << endl;
}
}
else if (c && cmd == "balanceat")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
Address address = h160(fromHex(stringHash));
cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address)) << endl;
}
}
else if (c && cmd == "balanceatblock")
{
if (iss.peek() != -1)
{
string stringHash;
unsigned blocknumber;
iss >> stringHash >> blocknumber;
Address address = h160(fromHex(stringHash));
cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address, blocknumber)) << endl;
}
}
else if (c && cmd == "storageat")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
Address address = h160(fromHex(stringHash));
cout << "storage at " << stringHash << " is: " << endl;
for (auto s: c->storageAt(address))
cout << toHex(s.first) << " : " << toHex(s.second) << endl;
}
}
else if (c && cmd == "storageatblock")
{
if (iss.peek() != -1)
{
string stringHash;
unsigned blocknumber;
iss >> stringHash >> blocknumber;
Address address = h160(fromHex(stringHash));
cout << "storage at " << stringHash << " is: " << endl;
for (auto s: c->storageAt(address, blocknumber))
cout << "\"0x" << toHex(s.first) << "\" : \"0x" << toHex(s.second) << "\"," << endl;
}
}
else if (c && cmd == "codeat")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
Address address = h160(fromHex(stringHash));
cout << "code at " << stringHash << " is: " << toHex(c->codeAt(address)) << endl;
}
}
#endif
else if (c && cmd == "send")
{
if (iss.peek() != -1)
{
string hexAddr;
u256 amount;
iss >> hexAddr >> amount;
int size = hexAddr.length();
if (size < 40)
{
if (size > 0)
cwarn << "Invalid address length:" << size;
}
else
{
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
u256 minGas = (u256)Transaction::gasRequired(bytes(), 0);
try
{
Address dest = h160(fromHex(hexAddr, WhenError::Throw));
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getAccountPassword(signingKey); }), amount, dest, bytes(), minGas);
}
catch (BadHexCharacter& _e)
{
cwarn << "invalid hex character, transaction rejected";
cwarn << boost::diagnostic_information(_e);
}
catch (...)
{
cwarn << "transaction rejected";
}
}
}
else
cwarn << "Require parameters: send ADDRESS AMOUNT";
}
else if (c && cmd == "contract")
{
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
if (iss.peek() != -1)
{
u256 endowment;
u256 gas;
u256 gasPrice;
string sinit;
iss >> endowment >> gasPrice >> gas >> sinit;
trim_all(sinit);
int size = sinit.length();
bytes init;
cnote << "Init:";
cnote << sinit;
cnote << "Code size:" << size;
if (size < 1)
cwarn << "No code submitted";
else
{
cnote << "Assembled:";
stringstream ssc;
try
{
init = fromHex(sinit, WhenError::Throw);
}
catch (BadHexCharacter& _e)
{
cwarn << "invalid hex character, code rejected";
cwarn << boost::diagnostic_information(_e);
init = bytes();
}
catch (...)
{
cwarn << "code rejected";
init = bytes();
}
ssc.str(string());
ssc << disassemble(init);
cnote << "Init:";
cnote << ssc.str();
}
u256 minGas = (u256)Transaction::gasRequired(init, 0);
if (!init.size())
cwarn << "Contract creation aborted, no init code.";
else if (endowment < 0)
cwarn << "Invalid endowment";
else if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else
c->submitTransaction(keyManager.secret(signingKey, [&](){ return getAccountPassword(signingKey); }), endowment, init, gas, gasPrice);
}
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
}
else if (c && cmd == "dumpreceipt")
{
unsigned block;
unsigned index;
iss >> block >> index;
dev::eth::TransactionReceipt r = c->blockChain().receipts(c->blockChain().numberHash(block)).receipts[index];
auto rb = r.rlp();
cout << "RLP: " << RLP(rb) << endl;
cout << "Hex: " << toHex(rb) << endl;
cout << r << endl;
}
else if (c && cmd == "reprocess")
{
string block;
iss >> block;
h256 blockHash;
try
{
if (block.size() == 64 || block.size() == 66)
blockHash = h256(block);
else
blockHash = c->blockChain().numberHash(stoi(block));
c->state(blockHash);
}
catch (...)
{}
}
else if (c && cmd == "dumptrace")
{
unsigned block;
unsigned index;
string filename;
string format;
iss >> block >> index >> filename >> format;
ofstream f;
f.open(filename);
dev::eth::State state = c->state(index + 1,c->blockChain().numberHash(block));
if (index < state.pending().size())
{
Executive e(state, c->blockChain(), 0);
Transaction t = state.pending()[index];
state = state.fromPending(index);
try
{
OnOpFunc oof;
if (format == "pretty")
oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
{
dev::eth::VM* vm = vvm;
dev::eth::ExtVM const* ext = static_cast<ExtVM const*>(vextVM);
f << endl << " STACK" << endl;
for (auto i: vm->stack())
f << (h256)i << endl;
std::string memDump = (
(vm->memory().size() > 1000) ?
" mem size greater than 1000 bytes " :
dev::memDump(vm->memory())
);
f << " MEMORY" << endl << memDump;
f << " STORAGE" << endl;
for (auto const& i: ext->state().storage(ext->myAddress))
f << showbase << hex << i.first << ": " << i.second << endl;
f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << gas << " | -" << dec << gasCost << " | " << newMemSize << "x32";
};
else if (format == "standard")
oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
{
dev::eth::VM* vm = vvm;
dev::eth::ExtVM const* ext = static_cast<ExtVM const*>(vextVM);
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl;
};
else if (format == "standard+")
oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
{
dev::eth::VM* vm = vvm;
dev::eth::ExtVM const* ext = static_cast<ExtVM const*>(vextVM);
if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE)
for (auto const& i: ext->state().storage(ext->myAddress))
f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl;
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl;
};
e.initialize(t);
if (!e.execute())
e.go(oof);
e.finalize();
}
catch(Exception const& _e)
{
// TODO: a bit more information here. this is probably quite worrying as the transaction is already in the blockchain.
cwarn << diagnostic_information(_e);
}
}
}
else if (c && cmd == "inspect")
{
string rechex;
iss >> rechex;
if (rechex.length() != 40)
cwarn << "Invalid address length";
else
{
auto h = h160(fromHex(rechex));
stringstream s;
try
{
auto storage =c->storageAt(h, PendingBlock);
for (auto const& i: storage)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
s << endl << disassemble( c->codeAt(h, PendingBlock)) << endl;
string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs;
ofs.open(outFile, ofstream::binary);
ofs.write(s.str().c_str(), s.str().length());
ofs.close();
cnote << "Saved" << rechex << "to" << outFile;
}
catch (dev::InvalidTrie)
{
cwarn << "Corrupted trie.";
}
}
}
else if (cmd == "setsigningkey")
{
if (iss.peek() != -1)
{
string hexSec;
iss >> hexSec;
signingKey = Address(fromHex(hexSec));
}
else
cwarn << "Require parameter: setSecret HEXSECRETKEY";
}
else if (cmd == "setaddress")
{
if (iss.peek() != -1)
{
string hexAddr;
iss >> hexAddr;
if (hexAddr.length() != 40)
cwarn << "Invalid address length: " << hexAddr.length();
else
{
try
{
beneficiary = h160(fromHex(hexAddr, WhenError::Throw));
}
catch (BadHexCharacter& _e)
{
cwarn << "invalid hex character, coinbase rejected";
cwarn << boost::diagnostic_information(_e);
}
catch (...)
{
cwarn << "coinbase rejected";
}
}
}
else
cwarn << "Require parameter: setAddress HEXADDRESS";
}
else if (cmd == "exportconfig")
{
if (iss.peek() != -1)
{
string path;
iss >> path;
writeFile(path, rlpList(signingKey, beneficiary));
}
else
cwarn << "Require parameter: exportConfig PATH";
}
else if (cmd == "importconfig")
{
if (iss.peek() != -1)
{
string path;
iss >> path;
bytes b = contents(path);
if (b.size())
{
RLP config(b);
signingKey = config[0].toHash<Address>();
beneficiary = config[1].toHash<Address>();
}
else
cwarn << path << "has no content!";
}
else
cwarn << "Require parameter: importConfig PATH";
}
else if (cmd == "help")
interactiveHelp();
else if (cmd == "exit")
break;
else
cout << "Unrecognised command. Type 'help' for help in interactive mode." << endl;
}
}
void interactiveMode(eth::Client*, std::shared_ptr<eth::TrivialGasPricer>, WebThreeDirect&, KeyManager&, string&, string&, function<string(string const&)>, function<string(Address const&)>, NetworkPreferences, Address, Address, TransactionPriority) {}
int main(int argc, char** argv)
{
@ -1777,7 +1001,7 @@ int main(int argc, char** argv)
// TODO: expose sealant interface.
c->setShouldPrecomputeDAG(m.shouldPrecompute());
c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU);
c->setAddress(beneficiary);
c->setBeneficiary(beneficiary);
c->setNetworkId(networkId);
}

16
ethvm/main.cpp

@ -21,6 +21,7 @@
*/
#include <fstream>
#include <iostream>
#include <ctime>
#include <boost/algorithm/string.hpp>
#include <libdevcore/CommonIO.h>
#include <libdevcore/RLP.h>
@ -87,6 +88,7 @@ int main(int argc, char** argv)
u256 gasPrice = 0;
bool styledJson = true;
StandardTrace st;
EnvInfo envInfo;
for (int i = 1; i < argc; ++i)
{
@ -130,6 +132,18 @@ int main(int argc, char** argv)
value = u256(argv[++i]);
else if (arg == "--value" && i + 1 < argc)
value = u256(argv[++i]);
else if (arg == "--beneficiary" && i + 1 < argc)
envInfo.setBeneficiary(Address(argv[++i]));
else if (arg == "--number" && i + 1 < argc)
envInfo.setNumber(u256(argv[++i]));
else if (arg == "--difficulty" && i + 1 < argc)
envInfo.setDifficulty(u256(argv[++i]));
else if (arg == "--timestamp" && i + 1 < argc)
envInfo.setTimestamp(u256(argv[++i]));
else if (arg == "--gas-limit" && i + 1 < argc)
envInfo.setGasLimit(u256(argv[++i]));
else if (arg == "--value" && i + 1 < argc)
value = u256(argv[++i]);
else if (arg == "stats")
mode = Mode::Statistics;
else if (arg == "output")
@ -151,7 +165,7 @@ int main(int argc, char** argv)
data = code;
state.addBalance(sender, value);
Executive executive(state, eth::LastHashes(), 0);
Executive executive(state, envInfo);
ExecutionResult res;
executive.setResultRecipient(res);
Transaction t = eth::Transaction(value, gasPrice, gas, data, 0);

2
evmjit/libevmjit-cpp/Env.cpp

@ -44,7 +44,7 @@ extern "C"
EXPORT void env_blockhash(ExtVMFace* _env, i256* _number, h256* o_hash)
{
*o_hash = _env->blockhash(jit2eth(*_number));
*o_hash = _env->blockHash(jit2eth(*_number));
}
EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address)

2
evmjit/libevmjit-cpp/JitVM.cpp

@ -41,7 +41,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on
m_data.caller = eth2jit(fromAddress(_ext.caller));
m_data.origin = eth2jit(fromAddress(_ext.origin));
m_data.callValue = eth2jit(_ext.value);
m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress()));
m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.beneficiary()));
m_data.difficulty = eth2jit(_ext.currentBlock.difficulty());
m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit());
m_data.number = static_cast<decltype(m_data.number)>(_ext.currentBlock.number());

2
evmjit/libevmjit/Compiler.cpp

@ -700,7 +700,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
case Instruction::BLOCKHASH:
{
auto number = stack.pop();
auto hash = _ext.blockhash(number);
auto hash = _ext.blockHash(number);
stack.push(hash);
break;
}

12
exp/main.cpp

@ -299,7 +299,7 @@ int main()
#elif 0
void mine(State& s, BlockChain const& _bc, SealEngineFace* _se)
{
s.commitToMine(_bc);
s.commitToSeal(_bc);
Notified<bytes> sealed;
_se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; });
_se->generateSeal(s.info());
@ -329,8 +329,8 @@ int main()
OverlayDB stateDB = State::openDB(bc.genesisHash());
cnote << bc;
State s = bc.genesisState(stateDB);
s.setAddress(myMiner.address());
Block s = bc.genesisBlock(stateDB);
s.setBeneficiary(myMiner.address());
cnote << s;
// Sync up - this won't do much until we use the last state.
@ -362,8 +362,8 @@ int main()
cnote << s;
// Mine to get some ether and set in stone.
s.commitToMine(bc);
s.commitToMine(bc);
s.commitToSeal(bc);
s.commitToSeal(bc);
mine(s, bc, se);
bc.attemptImport(s.blockData(), stateDB);
@ -386,7 +386,7 @@ int main()
cdebug << "Path:" << tempDir;
Client c(&net, tempDir);
c.setAddress(myMiner.address());
c.setBeneficiary(myMiner.address());
this_thread::sleep_for(chrono::milliseconds(1000));

2
libdevcore/Exceptions.h

@ -60,6 +60,8 @@ struct BadRoot: virtual Exception { public: BadRoot(h256 const& _root): Exceptio
DEV_SIMPLE_EXCEPTION(FileError);
DEV_SIMPLE_EXCEPTION(Overflow);
DEV_SIMPLE_EXCEPTION(FailedInvariant);
DEV_SIMPLE_EXCEPTION(ValueTooLarge);
struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} };
struct ExternalFunctionFailure: virtual Exception { public: ExternalFunctionFailure(std::string _f): Exception("Function " + _f + "() failed.") {} };

6
libethcore/BlockInfo.h

@ -97,7 +97,7 @@ public:
{
return m_parentHash == _cmp.parentHash() &&
m_sha3Uncles == _cmp.sha3Uncles() &&
m_coinbaseAddress == _cmp.coinbaseAddress() &&
m_coinbaseAddress == _cmp.beneficiary() &&
m_stateRoot == _cmp.stateRoot() &&
m_transactionsRoot == _cmp.transactionsRoot() &&
m_receiptsRoot == _cmp.receiptsRoot() &&
@ -134,7 +134,7 @@ public:
void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); }
void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); }
Address const& coinbaseAddress() const { return m_coinbaseAddress; }
Address const& beneficiary() const { return m_coinbaseAddress; }
h256 const& stateRoot() const { return m_stateRoot; }
h256 const& transactionsRoot() const { return m_transactionsRoot; }
h256 const& receiptsRoot() const { return m_receiptsRoot; }
@ -182,7 +182,7 @@ private:
inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi)
{
_out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " <<
_out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.beneficiary() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " <<
_bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " <<
_bi.gasUsed() << " " << _bi.timestamp();
return _out;

55
libethereum/Account.cpp

@ -20,11 +20,66 @@
*/
#include "Account.h"
#include <test/JsonSpiritHeaders.h>
#include <libethcore/Common.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;
#pragma GCC diagnostic ignored "-Wunused-variable"
const h256 Account::c_contractConceptionCodeHash;
AccountMap dev::eth::jsonToAccountMap(std::string const& _json, AccountMaskMap* o_mask)
{
auto u256Safe = [](std::string const& s) -> u256 {
bigint ret(s);
if (ret >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State value is equal or greater than 2**256") );
return (u256)ret;
};
std::unordered_map<Address, Account> ret;
js::mValue val;
json_spirit::read_string(_json, val);
for (auto account: val.get_obj())
{
Address a(fromHex(account.first));
auto o = account.second.get_obj();
u256 balance;
bool haveBalance = true;
if (o.count("wei"))
balance = u256Safe(o["wei"].get_str());
else if (o.count("finney"))
balance = u256Safe(o["finney"].get_str()) * finney;
else if (o.count("balance"))
balance = u256Safe(o["balance"].get_str());
else
haveBalance = false;
bool haveCode = o.count("code");
if (haveCode)
{
ret[a] = Account(balance, Account::ContractConception);
ret[a].setCode(fromHex(o["code"].get_str()));
}
else
ret[a] = Account(balance, Account::NormalCreation);
bool haveStorage = o.count("storage");
for (pair<string, js::mValue> const& j: o["storage"].get_obj())
ret[a].setStorage(u256(j.first), u256(j.second.get_str()));
bool haveNonce = o.count("nonce");
for (auto i = 0; i < u256Safe(o["nonce"].get_str()); ++i)
ret[a].incNonce();
if (o_mask)
(*o_mask)[a] = AccountMask(haveBalance, haveNonce, haveCode, haveStorage);
}
return ret;
}

37
libethereum/Account.h

@ -25,6 +25,7 @@
#include <libdevcore/RLP.h>
#include <libdevcore/TrieDB.h>
#include <libdevcore/SHA3.h>
#include <libethcore/Common.h>
namespace dev
{
@ -203,5 +204,41 @@ private:
static const h256 c_contractConceptionCodeHash;
};
class AccountMask
{
public:
AccountMask(bool _all = false):
m_hasBalance(_all),
m_hasNonce(_all),
m_hasCode(_all),
m_hasStorage(_all)
{}
AccountMask(
bool _hasBalance,
bool _hasNonce,
bool _hasCode,
bool _hasStorage
):
m_hasBalance(_hasBalance),
m_hasNonce(_hasNonce),
m_hasCode(_hasCode),
m_hasStorage(_hasStorage)
{}
bool allSet() const { return m_hasBalance && m_hasNonce && m_hasCode && m_hasStorage; }
private:
bool m_hasBalance;
bool m_hasNonce;
bool m_hasCode;
bool m_hasStorage;
};
using AccountMap = std::unordered_map<Address, Account>;
using AccountMaskMap = std::unordered_map<Address, AccountMask>;
AccountMap jsonToAccountMap(std::string const& _json, AccountMaskMap* o_mask = nullptr);
}
}

2
libethereum/BasicGasPricer.h

@ -37,7 +37,7 @@ public:
void setRefPrice(u256 _weiPerRef) { if ((bigint)m_refsPerBlock * _weiPerRef > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_weiPerRef = _weiPerRef; }
void setRefBlockFees(u256 _refsPerBlock) { if ((bigint)m_weiPerRef * _refsPerBlock > std::numeric_limits<u256>::max() ) BOOST_THROW_EXCEPTION(Overflow() << errinfo_comment("ether price * block fees is larger than 2**256-1, choose a smaller number.") ); else m_refsPerBlock = _refsPerBlock; }
u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; }
u256 ask(Block 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;

810
libethereum/Block.cpp

@ -0,0 +1,810 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Block.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Block.h"
#include <ctime>
#include <random>
#include <boost/filesystem.hpp>
#include <boost/timer.hpp>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Assertions.h>
#include <libdevcore/StructuredLogger.h>
#include <libdevcore/TrieHash.h>
#include <libevmcore/Instruction.h>
#include <libethcore/Exceptions.h>
#include <libevm/VMFactory.h>
#include "BlockChain.h"
#include "Defaults.h"
#include "ExtVM.h"
#include "Executive.h"
#include "CachedAddressState.h"
#include "CanonBlockChain.h"
#include "TransactionQueue.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace fs = boost::filesystem;
#define ctrace clog(BlockTrace)
#define ETH_TIMED_ENACTMENTS 0
static const u256 c_blockReward = c_network == Network::Olympic ? (1500 * finney) : (5 * ether);
static const unsigned c_maxSyncTransactions = 256;
const char* BlockSafeExceptions::name() { return EthViolet "" EthBlue ""; }
const char* BlockDetail::name() { return EthViolet "" EthWhite ""; }
const char* BlockTrace::name() { return EthViolet "" EthGray ""; }
const char* BlockChat::name() { return EthViolet "" EthWhite ""; }
Block::Block(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress):
m_state(_db, _bs),
m_beneficiary(_coinbaseAddress),
m_blockReward(c_blockReward)
{
m_previousBlock.clear();
m_currentBlock.clear();
// assert(m_state.root() == m_previousBlock.stateRoot());
}
Block::Block(Block const& _s):
m_state(_s.m_state),
m_transactions(_s.m_transactions),
m_receipts(_s.m_receipts),
m_transactionSet(_s.m_transactionSet),
m_previousBlock(_s.m_previousBlock),
m_currentBlock(_s.m_currentBlock),
m_beneficiary(_s.m_beneficiary),
m_blockReward(_s.m_blockReward)
{
m_precommit = m_state;
m_committedToMine = false;
}
Block& Block::operator=(Block const& _s)
{
m_state = _s.m_state;
m_transactions = _s.m_transactions;
m_receipts = _s.m_receipts;
m_transactionSet = _s.m_transactionSet;
m_previousBlock = _s.m_previousBlock;
m_currentBlock = _s.m_currentBlock;
m_beneficiary = _s.m_beneficiary;
m_blockReward = _s.m_blockReward;
m_precommit = m_state;
m_committedToMine = false;
return *this;
}
void Block::resetCurrent()
{
m_transactions.clear();
m_receipts.clear();
m_transactionSet.clear();
m_currentBlock = BlockInfo();
m_currentBlock.setCoinbaseAddress(m_beneficiary);
m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0)));
m_currentBlock.populateFromParent(m_previousBlock);
// TODO: check.
m_state.setRoot(m_previousBlock.stateRoot());
m_precommit = m_state;
m_committedToMine = false;
}
PopulationStatistics Block::populateFromChain(BlockChain const& _bc, h256 const& _h, ImportRequirements::value _ir)
{
PopulationStatistics ret { 0.0, 0.0 };
if (!_bc.isKnown(_h))
{
// Might be worth throwing here.
cwarn << "Invalid block given for state population: " << _h;
BOOST_THROW_EXCEPTION(BlockNotFound() << errinfo_target(_h));
}
auto b = _bc.block(_h);
BlockInfo bi(b);
if (bi.number())
{
// Non-genesis:
// 1. Start at parent's end state (state root).
BlockInfo bip(_bc.block(bi.parentHash()));
sync(_bc, bi.parentHash(), bip);
// 2. Enact the block's transactions onto this state.
m_beneficiary = bi.beneficiary();
Timer t;
auto vb = _bc.verifyBlock(&b, function<void(Exception&)>(), _ir);
ret.verify = t.elapsed();
t.restart();
enact(vb, _bc);
ret.enact = t.elapsed();
}
else
{
// Genesis required:
// We know there are no transactions, so just populate directly.
m_state = State(m_state.db(), BaseState::Empty); // TODO: try with PreExisting.
sync(_bc, _h, bi);
}
return ret;
}
bool Block::sync(BlockChain const& _bc)
{
return sync(_bc, _bc.currentHash());
}
bool Block::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi)
{
bool ret = false;
// BLOCK
BlockInfo bi = _bi ? _bi : _bc.info(_block);
#if ETH_PARANOIA
if (!bi)
while (1)
{
try
{
auto b = _bc.block(_block);
bi.populate(b);
break;
}
catch (Exception const& _e)
{
// TODO: Slightly nicer handling? :-)
cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
cerr << diagnostic_information(_e) << endl;
}
catch (std::exception const& _e)
{
// TODO: Slightly nicer handling? :-)
cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
cerr << _e.what() << endl;
}
}
#endif
if (bi == m_currentBlock)
{
// We mined the last block.
// Our state is good - we just need to move on to next.
m_previousBlock = m_currentBlock;
resetCurrent();
ret = true;
}
else if (bi == m_previousBlock)
{
// No change since last sync.
// Carry on as we were.
}
else
{
// New blocks available, or we've switched to a different branch. All change.
// Find most recent state dump and replay what's left.
// (Most recent state dump might end up being genesis.)
if (m_state.db().lookup(bi.stateRoot()).empty()) // TODO: API in State for this?
{
cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database.";
cwarn << "Database corrupt: contains block without stateRoot:" << bi;
cwarn << "Try rescuing the database by running: eth --rescue";
BOOST_THROW_EXCEPTION(InvalidStateRoot() << errinfo_target(bi.stateRoot()));
}
m_previousBlock = bi;
resetCurrent();
ret = true;
}
#if ALLOW_REBUILD
else
{
// New blocks available, or we've switched to a different branch. All change.
// Find most recent state dump and replay what's left.
// (Most recent state dump might end up being genesis.)
std::vector<h256> chain;
while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block...
{
chain.push_back(bi.hash()); // push back for later replay.
bi.populate(_bc.block(bi.parentHash())); // move to parent.
}
m_previousBlock = bi;
resetCurrent();
// Iterate through in reverse, playing back each of the blocks.
try
{
for (auto it = chain.rbegin(); it != chain.rend(); ++it)
{
auto b = _bc.block(*it);
enact(&b, _bc, _ir);
cleanup(true);
}
}
catch (...)
{
// TODO: Slightly nicer handling? :-)
cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
cerr << boost::current_exception_diagnostic_information() << endl;
exit(1);
}
resetCurrent();
ret = true;
}
#endif
return ret;
}
pair<TransactionReceipts, bool> Block::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, unsigned msTimeout)
{
// TRANSACTIONS
pair<TransactionReceipts, bool> ret;
ret.second = false;
auto ts = _tq.topTransactions(c_maxSyncTransactions);
LastHashes lh;
auto deadline = chrono::steady_clock::now() + chrono::milliseconds(msTimeout);
for (int goodTxs = 1; goodTxs; )
{
goodTxs = 0;
for (auto const& t: ts)
if (!m_transactionSet.count(t.sha3()))
{
try
{
if (t.gasPrice() >= _gp.ask(*this))
{
// Timer t;
if (lh.empty())
lh = _bc.lastHashes();
execute(lh, t);
ret.first.push_back(m_receipts.back());
++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
}
else if (t.gasPrice() < _gp.ask(*this) * 9 / 10)
{
clog(StateTrace) << t.sha3() << "Dropping El Cheapo transaction (<90% of ask price)";
_tq.drop(t.sha3());
}
}
catch (InvalidNonce const& in)
{
bigint const& req = *boost::get_error_info<errinfo_required>(in);
bigint const& got = *boost::get_error_info<errinfo_got>(in);
if (req > got)
{
// too old
clog(StateTrace) << t.sha3() << "Dropping old transaction (nonce too low)";
_tq.drop(t.sha3());
}
else if (got > req + _tq.waiting(t.sender()))
{
// too new
clog(StateTrace) << t.sha3() << "Dropping new transaction (too many nonces ahead)";
_tq.drop(t.sha3());
}
else
_tq.setFuture(t.sha3());
}
catch (BlockGasLimitReached const& e)
{
bigint const& got = *boost::get_error_info<errinfo_got>(e);
if (got > m_currentBlock.gasLimit())
{
clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)";
_tq.drop(t.sha3());
}
else
{
// Temporarily no gas left in current block.
// OPTIMISE: could note this and then we don't evaluate until a block that does have the gas left.
// for now, just leave alone.
}
}
catch (Exception const& _e)
{
// Something else went wrong - drop it.
clog(StateTrace) << t.sha3() << "Dropping invalid transaction:" << diagnostic_information(_e);
_tq.drop(t.sha3());
}
catch (std::exception const&)
{
// Something else went wrong - drop it.
_tq.drop(t.sha3());
cwarn << t.sha3() << "Transaction caused low-level exception :(";
}
}
if (chrono::steady_clock::now() > deadline)
{
ret.second = true;
break;
}
}
return ret;
}
u256 Block::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc)
{
#if ETH_TIMED_ENACTMENTS
Timer t;
double populateVerify;
double populateGrand;
double syncReset;
double enactment;
#endif
// Check family:
BlockInfo biParent = _bc.info(_block.info.parentHash());
_block.info.verifyParent(biParent);
#if ETH_TIMED_ENACTMENTS
populateVerify = t.elapsed();
t.restart();
#endif
BlockInfo biGrandParent;
if (biParent.number())
biGrandParent = _bc.info(biParent.parentHash());
#if ETH_TIMED_ENACTMENTS
populateGrand = t.elapsed();
t.restart();
#endif
sync(_bc, _block.info.parentHash(), BlockInfo());
resetCurrent();
#if ETH_TIMED_ENACTMENTS
syncReset = t.elapsed();
t.restart();
#endif
m_previousBlock = biParent;
auto ret = enact(_block, _bc);
#if ETH_TIMED_ENACTMENTS
enactment = t.elapsed();
if (populateVerify + populateGrand + syncReset + enactment > 0.5)
clog(StateChat) << "popVer/popGrand/syncReset/enactment = " << populateVerify << "/" << populateGrand << "/" << syncReset << "/" << enactment;
#endif
return ret;
}
u256 Block::enact(VerifiedBlockRef const& _block, BlockChain const& _bc)
{
DEV_TIMED_FUNCTION_ABOVE(500);
// m_currentBlock is assumed to be prepopulated and reset.
#if !ETH_RELEASE
assert(m_previousBlock.hash() == _block.info.parentHash());
assert(m_currentBlock.parentHash() == _block.info.parentHash());
assert(rootHash() == m_previousBlock.stateRoot());
#endif
if (m_currentBlock.parentHash() != m_previousBlock.hash())
// Internal client error.
BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values.
m_currentBlock.noteDirty();
m_currentBlock = _block.info;
// cnote << "playback begins:" << m_state.root();
// cnote << m_state;
LastHashes lh;
DEV_TIMED_ABOVE("lastHashes", 500)
lh = _bc.lastHashes((unsigned)m_previousBlock.number());
RLP rlp(_block.block);
vector<bytes> receipts;
// All ok with the block generally. Play back the transactions now...
unsigned i = 0;
DEV_TIMED_ABOVE("txExec", 500)
for (auto const& tr: _block.transactions)
{
try
{
LogOverride<ExecutiveWarnChannel> o(false);
execute(lh, tr);
}
catch (Exception& ex)
{
ex << errinfo_transactionIndex(i);
throw;
}
RLPStream receiptRLP;
m_receipts.back().streamRLP(receiptRLP);
receipts.push_back(receiptRLP.out());
++i;
}
h256 receiptsRoot;
DEV_TIMED_ABOVE(".receiptsRoot()", 500)
receiptsRoot = orderedTrieRoot(receipts);
if (receiptsRoot != m_currentBlock.receiptsRoot())
{
InvalidReceiptsStateRoot ex;
ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot());
ex << errinfo_receipts(receipts);
ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None));
BOOST_THROW_EXCEPTION(ex);
}
if (m_currentBlock.logBloom() != logBloom())
{
InvalidLogBloom ex;
ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom());
ex << errinfo_receipts(receipts);
BOOST_THROW_EXCEPTION(ex);
}
// Initialise total difficulty calculation.
u256 tdIncrease = m_currentBlock.difficulty();
// Check uncles & apply their rewards to state.
if (rlp[2].itemCount() > 2)
{
TooManyUncles ex;
ex << errinfo_max(2);
ex << errinfo_got(rlp[2].itemCount());
BOOST_THROW_EXCEPTION(ex);
}
vector<BlockInfo> rewarded;
h256Hash excluded;
DEV_TIMED_ABOVE("allKin", 500)
excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6);
excluded.insert(m_currentBlock.hash());
unsigned ii = 0;
DEV_TIMED_ABOVE("uncleCheck", 500)
for (auto const& i: rlp[2])
{
try
{
auto h = sha3(i.data());
if (excluded.count(h))
{
UncleInChain ex;
ex << errinfo_comment("Uncle in block already mentioned");
ex << errinfo_unclesExcluded(excluded);
ex << errinfo_hash256(sha3(i.data()));
BOOST_THROW_EXCEPTION(ex);
}
excluded.insert(h);
// IgnoreSeal since it's a VerifiedBlock.
BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData);
BlockInfo uncleParent;
if (!_bc.isKnown(uncle.parentHash()))
BOOST_THROW_EXCEPTION(UnknownParent());
uncleParent = BlockInfo(_bc.block(uncle.parentHash()));
if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7)
{
UncleTooOld ex;
ex << errinfo_uncleNumber(uncle.number());
ex << errinfo_currentNumber(m_currentBlock.number());
BOOST_THROW_EXCEPTION(ex);
}
else if (uncle.number() == m_currentBlock.number())
{
UncleIsBrother ex;
ex << errinfo_uncleNumber(uncle.number());
ex << errinfo_currentNumber(m_currentBlock.number());
BOOST_THROW_EXCEPTION(ex);
}
uncle.verifyParent(uncleParent);
rewarded.push_back(uncle);
++ii;
}
catch (Exception& ex)
{
ex << errinfo_uncleIndex(ii);
throw;
}
}
DEV_TIMED_ABOVE("applyRewards", 500)
applyRewards(rewarded);
// Commit all cached state changes to the state trie.
DEV_TIMED_ABOVE("commit", 500)
m_state.commit();
// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash())
{
m_state.db().rollback(); // TODO: API in State for this?
BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot()));
}
if (m_currentBlock.gasUsed() != gasUsed())
{
// Rollback the trie.
m_state.db().rollback(); // TODO: API in State for this?
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed())));
}
return tdIncrease;
}
ExecutionResult Block::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp)
{
// Uncommitting is a non-trivial operation - only do it once we've verified as much of the
// transaction as possible.
uncommitToMine();
std::pair<ExecutionResult, TransactionReceipt> resultReceipt = m_state.execute(EnvInfo(info(), _lh, gasUsed()), _t, _p, _onOp);
if (_p == Permanence::Committed)
{
// Add to the user-originated transactions that we've executed.
m_transactions.push_back(_t);
m_receipts.push_back(resultReceipt.second);
m_transactionSet.insert(_t.sha3());
}
return resultReceipt.first;
}
void Block::applyRewards(vector<BlockInfo> const& _uncleBlockHeaders)
{
u256 r = m_blockReward;
for (auto const& i: _uncleBlockHeaders)
{
m_state.addBalance(i.beneficiary(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8);
r += m_blockReward / 32;
}
m_state.addBalance(m_currentBlock.beneficiary(), r);
}
void Block::commitToSeal(BlockChain const& _bc, bytes const& _extraData)
{
if (m_committedToMine)
uncommitToMine();
else
m_precommit = m_state;
vector<BlockInfo> uncleBlockHeaders;
RLPStream unclesData;
unsigned unclesCount = 0;
if (m_previousBlock.number() != 0)
{
// Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations.
clog(StateDetail) << "Checking " << m_previousBlock.hash() << ", parent=" << m_previousBlock.parentHash();
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6);
auto p = m_previousBlock.parentHash();
for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent)
{
auto us = _bc.details(p).children;
assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent!
for (auto const& u: us)
if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about.
{
uncleBlockHeaders.push_back(_bc.info(u));
unclesData.appendRaw(_bc.headerData(u));
++unclesCount;
if (unclesCount == 2)
break;
}
}
}
BytesMap transactionsMap;
BytesMap receiptsMap;
RLPStream txs;
txs.appendList(m_transactions.size());
for (unsigned i = 0; i < m_transactions.size(); ++i)
{
RLPStream k;
k << i;
RLPStream receiptrlp;
m_receipts[i].streamRLP(receiptrlp);
receiptsMap.insert(std::make_pair(k.out(), receiptrlp.out()));
RLPStream txrlp;
m_transactions[i].streamRLP(txrlp);
transactionsMap.insert(std::make_pair(k.out(), txrlp.out()));
txs.appendRaw(txrlp.out());
}
txs.swapOut(m_currentTxs);
RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles);
// Apply rewards last of all.
applyRewards(uncleBlockHeaders);
// Commit any and all changes to the trie that are in the cache, then update the state root accordingly.
m_state.commit();
clog(StateDetail) << "Post-reward stateRoot:" << m_state.rootHash();
clog(StateDetail) << m_state;
clog(StateDetail) << *this;
m_currentBlock.setLogBloom(logBloom());
m_currentBlock.setGasUsed(gasUsed());
m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.rootHash());
m_currentBlock.setParentHash(m_previousBlock.hash());
m_currentBlock.setExtraData(_extraData);
if (m_currentBlock.extraData().size() > 32)
{
auto ed = m_currentBlock.extraData();
ed.resize(32);
m_currentBlock.setExtraData(ed);
}
m_committedToMine = true;
}
void Block::uncommitToMine()
{
if (m_committedToMine)
{
m_state = m_precommit;
m_committedToMine = false;
}
}
bool Block::sealBlock(bytesConstRef _header)
{
if (!m_committedToMine)
return false;
clog(StateDetail) << "Sealing block!";
// Got it!
// Compile block:
RLPStream ret;
ret.appendList(3);
ret.appendRaw(_header);
ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles);
ret.swapOut(m_currentBytes);
m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData);
cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")";
// TODO: move into Sealer
StructuredLogger::minedNewBlock(
m_currentBlock.hash().abridged(),
"", // Can't give the nonce here.
"", //TODO: chain head hash here ??
m_currentBlock.parentHash().abridged()
);
// Quickly reset the transactions.
// TODO: Leave this in a better state than this limbo, or at least record that it's in limbo.
m_transactions.clear();
m_receipts.clear();
m_transactionSet.clear();
m_precommit = m_state;
return true;
}
State Block::fromPending(unsigned _i) const
{
State ret = m_state;
_i = min<unsigned>(_i, m_transactions.size());
if (!_i)
ret.setRoot(m_previousBlock.stateRoot());
else
ret.setRoot(m_receipts[_i - 1].stateRoot());
return ret;
}
LogBloom Block::logBloom() const
{
LogBloom ret;
for (TransactionReceipt const& i: m_receipts)
ret |= i.bloom();
return ret;
}
void Block::cleanup(bool _fullCommit)
{
if (_fullCommit)
{
// Commit the new trie to disk.
if (isChannelVisible<StateTrace>()) // Avoid calling toHex if not needed
clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(db().lookup(rootHash())));
try
{
EnforceRefs er(db(), true);
rootHash();
}
catch (BadRoot const&)
{
clog(StateChat) << "Trie corrupt! :-(";
throw;
}
m_state.db().commit(); // TODO: State API for this?
if (isChannelVisible<StateTrace>()) // Avoid calling toHex if not needed
clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(db().lookup(rootHash())));
m_previousBlock = m_currentBlock;
m_currentBlock.populateFromParent(m_previousBlock);
clog(StateTrace) << "finalising enactment. current -> previous, hash is" << m_previousBlock.hash();
}
else
m_state.db().rollback(); // TODO: State API for this?
resetCurrent();
}
string Block::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir)
{
RLP rlp(_block);
cleanup(false);
BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal);
m_currentBlock = bi;
m_currentBlock.verifyInternals(_block);
m_currentBlock.noteDirty();
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number());
string ret;
unsigned i = 0;
for (auto const& tr: rlp[1])
{
StandardTrace st;
st.setShowMnemonics();
execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, st.onOp());
ret += (ret.empty() ? "[" : ",") + st.json();
++i;
}
return ret.empty() ? "[]" : (ret + "]");
}
std::ostream& dev::eth::operator<<(std::ostream& _out, Block const& _s)
{
(void)_s;
return _out;
}

310
libethereum/Block.h

@ -0,0 +1,310 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Block.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <array>
#include <unordered_map>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/TrieDB.h>
#include <libdevcrypto/OverlayDB.h>
#include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Miner.h>
#include <libevm/ExtVMFace.h>
#include "Account.h"
#include "Transaction.h"
#include "TransactionReceipt.h"
#include "AccountDiff.h"
#include "GasPricer.h"
#include "State.h"
namespace dev
{
namespace test { class ImportTest; class StateLoader; }
namespace eth
{
class BlockChain;
class State;
class TransactionQueue;
struct VerifiedBlockRef;
struct BlockChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct BlockTrace: public LogChannel { static const char* name(); static const int verbosity = 5; };
struct BlockDetail: public LogChannel { static const char* name(); static const int verbosity = 14; };
struct BlockSafeExceptions: public LogChannel { static const char* name(); static const int verbosity = 21; };
struct PopulationStatistics
{
double verify;
double enact;
};
/**
* @brief Active model of a block within the block chain.
* Keeps track of all transactions, receipts and state for a particular block. Can apply all
* needed transforms of the state for rewards and contains logic for sealing the block.
*/
class Block
{
friend class ExtVM;
friend class dev::test::ImportTest;
friend class dev::test::StateLoader;
friend class Executive;
friend class BlockChain;
public:
/// Default constructor; creates with a blank database prepopulated with the genesis block.
Block(): m_state(OverlayDB(), BaseState::Empty) {}
/// Basic state object from database.
/// Use the default when you already have a database and you just want to make a Block object
/// which uses it. If you have no preexisting database then set BaseState to something other
/// than BaseState::PreExisting in order to prepopulate the Trie.
/// You can also set the beneficiary address.
explicit Block(OverlayDB const& _db, BaseState _bs = BaseState::PreExisting, Address _coinbaseAddress = Address());
/// Copy state object.
Block(Block const& _s);
/// Copy state object.
Block& operator=(Block const& _s);
/// Get the beneficiary address for any transactions we do and rewards we get.
Address beneficiary() const { return m_beneficiary; }
/// Set the beneficiary address for any transactions we do and rewards we get.
/// This causes a complete reset of current block.
void setBeneficiary(Address const& _id) { m_beneficiary = _id; resetCurrent(); }
// Account-getters. All operate on the final state.
/// Get an account's balance.
/// @returns 0 if the address has never been used.
u256 balance(Address const& _address) const { return m_state.balance(_address); }
/// Get the number of transactions a particular address has sent (used for the transaction nonce).
/// @returns 0 if the address has never been used.
u256 transactionsFrom(Address const& _address) const { return m_state.transactionsFrom(_address); }
/// Check if the address is in use.
bool addressInUse(Address const& _address) const { return m_state.addressInUse(_address); }
/// Check if the address contains executable code.
bool addressHasCode(Address const& _address) const { return m_state.addressHasCode(_address); }
/// Get the root of the storage of an account.
h256 storageRoot(Address const& _contract) const { return m_state.storageRoot(_contract); }
/// Get the value of a storage position of an account.
/// @returns 0 if no account exists at that address.
u256 storage(Address const& _contract, u256 const& _memory) const { return m_state.storage(_contract, _memory); }
/// Get the storage of an account.
/// @note This is expensive. Don't use it unless you need to.
/// @returns std::unordered_map<u256, u256> if no account exists at that address.
std::unordered_map<u256, u256> storage(Address const& _contract) const { return m_state.storage(_contract); }
/// Get the code of an account.
/// @returns bytes() if no account exists at that address.
bytes const& code(Address const& _contract) const { return m_state.code(_contract); }
/// Get the code hash of an account.
/// @returns EmptySHA3 if no account exists at that address or if there is no code associated with the address.
h256 codeHash(Address const& _contract) const { return m_state.codeHash(_contract); }
// General information from state
/// Get the backing state object.
State const& state() const { return m_state; }
/// Open a DB - useful for passing into the constructor & keeping for other states that are necessary.
OverlayDB const& db() const { return m_state.db(); }
/// The hash of the root of our state tree.
h256 rootHash() const { return m_state.rootHash(); }
/// @returns the set containing all addresses currently in use in Ethereum.
/// @throws InterfaceNotSupported if compiled without ETH_FATDB.
std::unordered_map<Address, u256> addresses() const { return m_state.addresses(); }
// For altering accounts behind-the-scenes
/// Get a mutable State object which is backing this block.
/// @warning Only use this is you know what you're doing. If you use it while constructing a
/// normal sealable block, don't expect things to work right.
State& mutableState() { return m_state; }
// Information concerning ongoing transactions
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); }
/// Get the list of pending transactions.
Transactions const& pending() const { return m_transactions; }
/// Get the list of hashes of pending transactions.
h256Hash const& pendingHashes() const { return m_transactionSet; }
/// Get the transaction receipt for the transaction of the given index.
TransactionReceipt const& receipt(unsigned _i) const { return m_receipts[_i]; }
/// Get the list of pending transactions.
LogEntries const& log(unsigned _i) const { return m_receipts[_i].log(); }
/// Get the bloom filter of all logs that happened in the block.
LogBloom logBloom() const;
/// Get the bloom filter of a particular transaction that happened in the block.
LogBloom const& logBloom(unsigned _i) const { return m_receipts[_i].bloom(); }
/// Get the State immediately after the given number of pending transactions have been applied.
/// If (_i == 0) returns the initial state of the block.
/// If (_i == pending().size()) returns the final state of the block, prior to rewards.
State fromPending(unsigned _i) const;
/// @returns the StateDiff caused by the pending transaction of index @a _i.
StateDiff pendingDiff(unsigned _i) const { return fromPending(_i).diff(fromPending(_i + 1), true); }
// State-change operations
/// Construct state object from arbitrary point in blockchain.
PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None);
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());
/// Sync our transactions, killing those from the queue that we have and assimilating those that we don't.
/// @returns a list of receipts one for each transaction placed from the queue into the state and bool, true iff there are more transactions to be processed.
std::pair<TransactionReceipts, bool> sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, unsigned _msTimeout = 100);
/// 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);
/// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block.
bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo());
/// Execute all transactions within a given block.
/// @returns the additional total difficulty.
u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc);
/// Returns back to a pristine state after having done a playback.
/// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates
/// the block since all state changes are ultimately reversed.
void cleanup(bool _fullCommit);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();
// Sealing
/// Prepares the current state for mining.
/// Commits all transactions into the trie, compiles uncles and transactions list, applies all
/// rewards and populates the current block header with the appropriate hashes.
/// The only thing left to do after this is to actually mine().
///
/// This may be called multiple times and without issue.
void commitToSeal(BlockChain const& _bc, bytes const& _extraData = {});
/// Pass in a solution to the proof-of-work.
/// @returns true iff we were previously committed to mining.
/// TODO: verify it prior to calling this.
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
* @code
* while (notYetMined)
* {
* // lock
* commitToSeal(_blockChain); // will call uncommitToMine if a repeat.
* completeMine();
* // unlock
* @endcode
*/
bool sealBlock(bytes const& _header) { return sealBlock(&_header); }
bool sealBlock(bytesConstRef _header);
/// Get the complete current block, including valid nonce.
/// Only valid after mine() returns true.
bytes const& blockData() const { return m_currentBytes; }
/// Get the header information on the present block.
BlockInfo const& info() const { return m_currentBlock; }
private:
/// Undo the changes to the state for committing to mine.
void uncommitToMine();
/// Retrieve all information about a given address into the cache.
/// If _requireMemory is true, grab the full memory should it be a contract item.
/// If _forceCreate is true, then insert a default item into the cache, in the case it doesn't
/// exist in the DB.
void ensureCached(Address const& _a, bool _requireCode, bool _forceCreate) const;
/// Retrieve all information about a given address into a cache.
void ensureCached(std::unordered_map<Address, Account>& _cache, Address const& _a, bool _requireCode, bool _forceCreate) const;
/// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc);
/// Finalise the block, applying the earned rewards.
void applyRewards(std::vector<BlockInfo> const& _uncleBlockHeaders);
/// @returns gas used by transactions thus far executed.
u256 gasUsed() const { return m_receipts.size() ? m_receipts.back().gasUsed() : 0; }
/// Provide a standard VM trace for debugging purposes.
std::string vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir);
State m_state; ///< Our state tree, as an OverlayDB DB.
Transactions m_transactions; ///< The current list of transactions that we've included in the state.
TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts.
h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state.
State m_precommit; ///< State at the point immediately prior to rewards.
BlockInfo m_previousBlock; ///< The previous block's information.
BlockInfo m_currentBlock; ///< The current block's information.
bytes m_currentBytes; ///< The current block.
bool m_committedToMine = false; ///< Have we committed to mine on the present m_currentBlock?
bytes m_currentTxs; ///< The RLP-encoded block of transactions.
bytes m_currentUncles; ///< The RLP-encoded block of uncles.
Address m_beneficiary; ///< Our address (i.e. the address to which fees go).
u256 m_blockReward;
friend std::ostream& operator<<(std::ostream& _out, Block const& _s);
};
std::ostream& operator<<(std::ostream& _out, Block const& _s);
}
}

22
libethereum/BlockChain.cpp

@ -40,6 +40,7 @@
#include <liblll/Compiler.h>
#include "GenesisInfo.h"
#include "State.h"
#include "Block.h"
#include "Utility.h"
#include "Defaults.h"
using namespace std;
@ -146,13 +147,13 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path):
BlockChain::BlockChain(bytes const& _genesisBlock, AccountMap const& _genesisState, std::string const& _path):
m_dbPath(_path)
{
open(_genesisBlock, _genesisState, _path);
}
void BlockChain::open(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path)
void BlockChain::open(bytes const& _genesisBlock, AccountMap const& _genesisState, std::string const& _path)
{
// initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize);
@ -295,7 +296,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
ldb::DB::Open(o, extrasPath + "/extras", &m_extrasDB);
// Open a fresh state DB
State s = genesisState(State::openDB(path, m_genesisHash, WithExisting::Kill));
Block s = genesisBlock(State::openDB(path, m_genesisHash, WithExisting::Kill));
// Clear all memos ready for replay.
m_details.clear();
@ -554,7 +555,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
{
// Check transactions are valid and that they result in a state equivalent to our state_root.
// Get total difficulty increase and update state, checking it.
State s(_db);
Block s(_db);
auto tdIncrease = s.enactOn(_block, *this);
for (unsigned i = 0; i < s.pending().size(); ++i)
@ -676,7 +677,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
h256s alteredBlooms;
{
LogBloom blockBloom = tbi.logBloom();
blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref()));
blockBloom.shiftBloom<3>(sha3(tbi.beneficiary().ref()));
// Pre-memoize everything we need before locking x_blocksBlooms
for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize)
@ -1266,13 +1267,12 @@ bytes BlockChain::headerData(h256 const& _hash) const
return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes();
}
State BlockChain::genesisState(OverlayDB const& _db)
Block BlockChain::genesisBlock(OverlayDB const& _db)
{
State ret(_db, BaseState::Empty);
dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it?
ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit.
ret.m_previousBlock = BlockInfo(&m_genesisBlock);
ret.resetCurrent();
Block ret(_db, BaseState::Empty);
dev::eth::commit(m_genesisState, ret.mutableState().m_state); // bit horrible. maybe consider a better way of constructing it?
ret.mutableState().db().commit(); // have to use this db() since it's the one that has been altered with the above commit.
ret.m_previousBlock = BlockInfo(m_genesisBlock);
return ret;
}

14
libethereum/BlockChain.h

@ -58,6 +58,7 @@ namespace eth
static const h256s NullH256s;
class State;
class Block;
struct AlreadyHaveBlock: virtual Exception {};
struct UnknownParent: virtual Exception {};
@ -89,7 +90,6 @@ enum {
};
using ProgressCallback = std::function<void(unsigned, unsigned)>;
using StateDefinition = std::unordered_map<Address, Account>;
class VersionChecker
{
@ -106,7 +106,7 @@ class BlockChain
public:
/// Doesn't open the database - if you want it open it's up to you to subclass this and open it
/// in the constructor there.
BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path);
BlockChain(bytes const& _genesisBlock, AccountMap const& _genesisState, std::string const& _path);
~BlockChain();
/// Reopen everything.
@ -286,7 +286,7 @@ public:
template <class T> void setOnBad(T const& _t) { m_onBad = _t; }
/// Get a pre-made genesis State object.
State genesisState(OverlayDB const& _db);
Block genesisBlock(OverlayDB const& _db);
/// Verify block and prepare it for enactment
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir = ImportRequirements::OutOfOrderChecks) const = 0;
@ -296,7 +296,7 @@ protected:
/// Initialise everything and ready for openning the database.
// TODO: rename to init
void open(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path);
void open(bytes const& _genesisBlock, AccountMap const& _genesisState, std::string const& _path);
/// Open the database.
// TODO: rename to open.
unsigned openDatabase(std::string const& _path, WithExisting _we);
@ -400,11 +400,17 @@ class FullBlockChain: public BlockChain
public:
using BlockHeader = typename Sealer::BlockHeader;
<<<<<<< HEAD
FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _pc = ProgressCallback()):
BlockChain(_genesisBlock, _genesisState, _path)
{
openDatabase(_path, _we, _pc);
}
=======
FullBlockChain(bytes const& _genesisBlock, AccountMap const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()):
BlockChain(_genesisBlock, _genesisState, _path, _we, _p)
{}
>>>>>>> 0672b04... Compile fixes galore.
/// Get the header of a block (or the most recent mined if none given). Thread-safe.
typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); }

29
libethereum/CanonBlockChain.cpp

@ -21,7 +21,6 @@
#include "CanonBlockChain.h"
#include <test/JsonSpiritHeaders.h>
#include <boost/filesystem.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
@ -36,7 +35,6 @@
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;
unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis;
boost::shared_mutex CanonBlockChain<Ethash>::x_genesis;
@ -104,32 +102,11 @@ bytes CanonBlockChain<Ethash>::createGenesisBlock()
return block.out();
}
unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
AccountMap const& CanonBlockChain<Ethash>::createGenesisState()
{
static std::unordered_map<Address, Account> s_ret;
static AccountMap s_ret;
if (s_ret.empty())
{
js::mValue val;
js::read_string(s_genesisStateJSON.empty() ? c_network == Network::Frontier ? c_genesisInfoFrontier : c_genesisInfoOlympic : s_genesisStateJSON, val);
for (auto account: val.get_obj()["alloc"].get_obj())
{
u256 balance;
if (account.second.get_obj().count("wei"))
balance = u256(account.second.get_obj()["wei"].get_str());
else if (account.second.get_obj().count("balance"))
balance = u256(account.second.get_obj()["balance"].get_str());
else if (account.second.get_obj().count("finney"))
balance = u256(account.second.get_obj()["finney"].get_str()) * finney;
if (account.second.get_obj().count("code"))
{
s_ret[Address(fromHex(account.first))] = Account(balance, Account::ContractConception);
s_ret[Address(fromHex(account.first))].setCode(fromHex(account.second.get_obj()["code"].get_str()));
}
else
s_ret[Address(fromHex(account.first))] = Account(balance, Account::NormalCreation);
}
}
s_ret = jsonToAccountMap(s_genesisStateJSON.empty() ? c_network == Network::Frontier ? c_genesisInfoFrontier : c_genesisInfoOlympic : s_genesisStateJSON);
return s_ret;
}

4
libethereum/CanonBlockChain.h

@ -52,7 +52,7 @@ class CanonBlockChain: public FullBlockChain<Sealer>
public:
CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain<Sealer>(std::string(), _we, _pc) {}
CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()):
FullBlockChain<Sealer>(createGenesisBlock(), StateDefinition(), _path, _we, _pc)
FullBlockChain<Sealer>(createGenesisBlock(), AccountMap(), _path, _we, _pc)
{
BlockChain::openDatabase(_path, _we, _pc);
}
@ -93,7 +93,7 @@ public:
/// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static std::unordered_map<Address, Account> createGenesisState();
static AccountMap const& createGenesisState();
/// Alter all the genesis block's state by giving a JSON string with account details.
/// @warning Unless you're very careful, make sure you call this right at the start of the

65
libethereum/Client.cpp

@ -40,6 +40,7 @@
#include "Executive.h"
#include "EthereumHost.h"
#include "Utility.h"
#include "Block.h"
#include "TransactionQueue.h"
using namespace std;
@ -87,7 +88,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _
// until after the construction.
m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction);
// LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block.
m_preMine = bc().genesisState(m_stateDB);
m_preMine = bc().genesisBlock(m_stateDB);
m_postMine = m_preMine;
m_bq.setChain(bc());
@ -344,16 +345,16 @@ void Client::reopenChain(WithExisting _we)
WriteGuard l2(x_preMine);
WriteGuard l3(x_working);
m_preMine = State();
m_postMine = State();
m_working = State();
m_preMine = Block();
m_postMine = Block();
m_working = Block();
m_stateDB = OverlayDB();
bc().reopen(_we);
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), _we);
m_preMine = bc().genesisState(m_stateDB);
m_postMine = m_preMine;
m_preMine = bc().genesisBlock(m_stateDB);
m_postMine = Block(m_stateDB);
}
if (auto h = m_host.lock())
@ -502,12 +503,12 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
ExecutionResult ret;
try
{
State temp;
Block temp;
clog(ClientDetail) << "Nonce at " << _dest << " pre:" << m_preMine.transactionsFrom(_dest) << " post:" << m_postMine.transactionsFrom(_dest);
DEV_READ_GUARDED(x_postMine)
temp = m_postMine;
temp.addBalance(_from, _value + _gasPrice * _gas);
Executive e(temp, LastHashes(), 0);
temp.mutableState().addBalance(_from, _value + _gasPrice * _gas);
Executive e(temp);
e.setResultRecipient(ret);
if (!e.call(_dest, _from, _value, _gasPrice, &_data, _gas))
e.go();
@ -615,14 +616,14 @@ void Client::resyncStateFromChain()
if (!isMajorSyncing())
{
bool preChanged = false;
State newPreMine;
Block newPreMine;
DEV_READ_GUARDED(x_preMine)
newPreMine = m_preMine;
// TODO: use m_postMine to avoid re-evaluating our own blocks.
preChanged = newPreMine.sync(bc());
if (preChanged || m_postMine.address() != m_preMine.address())
if (preChanged || m_postMine.beneficiary() != m_preMine.beneficiary())
{
if (isMining())
clog(ClientTrace) << "New block on chain.";
@ -710,7 +711,7 @@ void Client::rejigMining()
{
clog(ClientTrace) << "Rejigging mining...";
DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(bc(), m_extraData);
m_working.commitToSeal(bc(), m_extraData);
DEV_READ_GUARDED(x_working)
{
DEV_WRITE_GUARDED(x_postMine)
@ -814,56 +815,38 @@ void Client::checkWatchGarbage()
}
}
State Client::asOf(h256 const& _block) const
{
try
{
State ret(m_stateDB);
ret.populateFromChain(bc(), _block);
return ret;
}
catch (Exception& ex)
{
ex << errinfo_block(bc().block(_block));
onBadBlock(ex);
return State();
}
}
void Client::prepareForTransaction()
{
startWorking();
}
State Client::state(unsigned _txi, h256 _block) const
Block Client::block(h256 const& _blockHash, PopulationStatistics* o_stats) const
{
try
{
State ret(m_stateDB);
ret.populateFromChain(bc(), _block);
return ret.fromPending(_txi);
Block ret(m_stateDB);
PopulationStatistics s = ret.populateFromChain(bc(), _blockHash);
if (o_stats)
swap(s, *o_stats);
return ret;
}
catch (Exception& ex)
{
ex << errinfo_block(bc().block(_block));
ex << errinfo_block(bc().block(_blockHash));
onBadBlock(ex);
return State();
return Block();
}
}
State Client::state(h256 const& _block, PopulationStatistics* o_stats) const
State Client::state(unsigned _txi, h256 const& _blockHash) const
{
try
{
State ret(m_stateDB);
PopulationStatistics s = ret.populateFromChain(bc(), _block);
if (o_stats)
swap(s, *o_stats);
return ret;
return block(_blockHash).fromPending(_txi);
}
catch (Exception& ex)
{
ex << errinfo_block(bc().block(_block));
ex << errinfo_block(bc().block(_blockHash));
onBadBlock(ex);
return State();
}

28
libethereum/Client.h

@ -40,7 +40,7 @@
#include <libethcore/ABI.h>
#include <libp2p/Common.h>
#include "CanonBlockChain.h"
#include "State.h"
#include "Block.h"
#include "CommonNet.h"
#include "ClientBase.h"
@ -100,12 +100,18 @@ public:
virtual u256 gasLimitRemaining() const override { return m_postMine.gasLimitRemaining(); }
// [PRIVATE API - only relevant for base clients, not available in general]
dev::eth::State state(unsigned _txi, h256 _block) const;
dev::eth::State state(h256 const& _block, PopulationStatistics* o_stats = nullptr) const;
/// Get the block.
dev::eth::Block block(h256 const& _blockHash, PopulationStatistics* o_stats = nullptr) const;
dev::eth::Block state(h256 const& _blockHash, PopulationStatistics* o_stats = nullptr) const { return block(_blockHash, o_stats); }// TODO REMOVE
/// Get the state of the given block part way through execution, immediately before transaction
/// index @a _txi.
dev::eth::State state(unsigned _txi, h256 const& _block) const;
/// Get the state of the currently pending block part way through execution, immediately before
/// transaction index @a _txi.
dev::eth::State state(unsigned _txi) const;
/// Get the object representing the current state of Ethereum.
dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; }
dev::eth::Block postState() const { ReadGuard l(x_postMine); return m_postMine; }
/// Get the object representing the current canonical blockchain.
BlockChain const& blockChain() const { return bc(); }
/// Get some information on the block queue.
@ -122,7 +128,7 @@ public:
// Mining stuff:
virtual void setAddress(Address _us) override { WriteGuard l(x_preMine); m_preMine.setAddress(_us); }
virtual void setBeneficiary(Address _us) override { WriteGuard l(x_preMine); m_preMine.setBeneficiary(_us); }
/// Check block validity prior to mining.
bool miningParanoia() const { return m_paranoia; }
@ -212,9 +218,9 @@ protected:
/// Returns the state object for the full block (i.e. the terminal state) for index _h.
/// Works properly with LatestBlock and PendingBlock.
using ClientBase::asOf;
virtual State asOf(h256 const& _block) const override;
virtual State preMine() const override { ReadGuard l(x_preMine); return m_preMine; }
virtual State postMine() const override { ReadGuard l(x_postMine); return m_postMine; }
virtual Block asOf(h256 const& _block) const override;
virtual Block preMine() const override { ReadGuard l(x_preMine); return m_preMine; }
virtual Block postMine() const override { ReadGuard l(x_postMine); return m_postMine; }
virtual void prepareForTransaction() override;
/// Collate the changed filters for the bloom filter of the given pending transaction.
@ -295,11 +301,11 @@ protected:
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
mutable SharedMutex x_preMine; ///< Lock on m_preMine.
State m_preMine; ///< The present state of the client.
Block m_preMine; ///< The present state of the client.
mutable SharedMutex x_postMine; ///< Lock on m_postMine.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
Block m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
mutable SharedMutex x_working; ///< Lock on m_working.
State m_working; ///< The state of the client which we're mining (i.e. it'll have all the rewards added), while we're actually working on it.
Block m_working; ///< The state of the client which we're mining (i.e. it'll have all the rewards added), while we're actually working on it.
BlockInfo m_miningInfo; ///< The header we're attempting to mine on (derived from m_postMine).
bool remoteActive() const; ///< Is there an active and valid remote worker?
bool m_remoteWorking = false; ///< Has the remote worker recently been reset?

23
libethereum/ClientBase.cpp

@ -36,7 +36,7 @@ const char* WorkInChannel::name() { return EthOrange "⚒" EthGreen "▬▶"; }
const char* WorkOutChannel::name() { return EthOrange "" EthNavy "◀▬"; }
const char* WorkChannel::name() { return EthOrange "" EthWhite " "; }
State ClientBase::asOf(BlockNumber _h) const
Block ClientBase::asOf(BlockNumber _h) const
{
if (_h == PendingBlock)
return postMine();
@ -68,12 +68,12 @@ ExecutionResult ClientBase::call(Address const& _from, u256 _value, Address _des
ExecutionResult ret;
try
{
State temp = asOf(_blockNumber);
Block temp = asOf(_blockNumber);
u256 n = temp.transactionsFrom(_from);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
temp.addBalance(_from, (u256)(t.gas() * t.gasPrice() + t.value()));
temp.mutableState().addBalance(_from, (u256)(t.gas() * t.gasPrice() + t.value()));
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
@ -88,14 +88,13 @@ ExecutionResult ClientBase::create(Address const& _from, u256 _value, bytes cons
ExecutionResult ret;
try
{
State temp = asOf(_blockNumber);
Block temp = asOf(_blockNumber);
u256 n = temp.transactionsFrom(_from);
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
temp.mutableState().addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
@ -165,7 +164,7 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const
// Handle pending transactions differently as they're not on the block chain.
if (begin > bc().number())
{
State temp = postMine();
Block temp = postMine();
for (unsigned i = 0; i < temp.pending().size(); ++i)
{
// Might have a transaction that contains a matching log.
@ -440,14 +439,14 @@ h256s ClientBase::pendingHashes() const
StateDiff ClientBase::diff(unsigned _txi, h256 _block) const
{
State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1), true);
Block b = asOf(_block);
return b.fromPending(_txi).diff(b.fromPending(_txi + 1), true);
}
StateDiff ClientBase::diff(unsigned _txi, BlockNumber _block) const
{
State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1), true);
Block b = asOf(_block);
return b.fromPending(_txi).diff(b.fromPending(_txi + 1), true);
}
Addresses ClientBase::addresses(BlockNumber _block) const
@ -465,7 +464,7 @@ u256 ClientBase::gasLimitRemaining() const
Address ClientBase::address() const
{
return preMine().address();
return preMine().beneficiary();
}
h256 ClientBase::hashFromNumber(BlockNumber _number) const

15
libethereum/ClientBase.h

@ -26,10 +26,13 @@
#include "Interface.h"
#include "LogFilter.h"
#include "TransactionQueue.h"
#include "Block.h"
namespace dev {
namespace dev
{
namespace eth {
namespace eth
{
struct InstalledFilter
{
@ -163,16 +166,16 @@ public:
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
State asOf(BlockNumber _h) const;
Block asOf(BlockNumber _h) const;
protected:
/// The interface that must be implemented in any class deriving this.
/// {
virtual BlockChain& bc() = 0;
virtual BlockChain const& bc() const = 0;
virtual State asOf(h256 const& _h) const = 0;
virtual State preMine() const = 0;
virtual State postMine() const = 0;
virtual Block asOf(h256 const& _h) const = 0;
virtual Block preMine() const = 0;
virtual Block postMine() const = 0;
virtual void prepareForTransaction() = 0;
/// }

37
libethereum/Executive.cpp

@ -30,6 +30,7 @@
#include "ExtVM.h"
#include "Precompiled.h"
#include "BlockChain.h"
#include "Block.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
@ -142,9 +143,27 @@ string StandardTrace::json(bool _styled) const
return _styled ? Json::StyledWriter().write(*m_trace) : Json::FastWriter().write(*m_trace);
}
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
Executive::Executive(Block& _s, BlockChain const& _bc, unsigned _level):
Executive(_s, _bc.lastHashes(unsigned(_s.info().number() - 1)), _level)
{}
Executive::Executive(Block& _s, LastHashes const& _lh, unsigned _level):
m_s(_s.mutableState()),
m_envInfo(_s.info(), _lh),
m_depth(_level)
{}
Executive::Executive(State& _s, BlockChain const& _bc, EnvInfo const& _envInfo, unsigned _level):
m_s(_s),
m_envInfo(_envInfo),
m_depth(_level)
{
m_envInfo.setLastHashes(_bc.lastHashes((unsigned)m_envInfo.number() - 1));
}
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _number, unsigned _level):
m_s(_s),
m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)),
m_envInfo(_bc.info(_bc.numberHash(_number)), _bc.lastHashes(_number - 1)),
m_depth(_level)
{}
@ -169,12 +188,12 @@ void Executive::initialize(Transaction const& _transaction)
m_t = _transaction;
// Avoid transactions that would take us beyond the block gas limit.
u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit())
u256 startGasUsed = m_envInfo.gasUsed();
if (startGasUsed + (bigint)m_t.gas() > m_envInfo.gasLimit())
{
clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas();
clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_envInfo.gasLimit() - startGasUsed) << " Got" << m_t.gas();
m_excepted = TransactionException::BlockGasLimitReached;
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas()));
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_envInfo.gasLimit() - startGasUsed), (bigint)m_t.gas()));
}
// Check gas cost is enough.
@ -265,7 +284,7 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co
m_outRef = _p.out; // Save ref to expected output buffer to be used in go()
bytes const& c = m_s.code(_p.codeAddress);
h256 codeHash = m_s.codeHash(_p.codeAddress);
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, codeHash, m_depth);
m_ext = make_shared<ExtVM>(m_s, m_envInfo, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, codeHash, m_depth);
}
}
@ -285,7 +304,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// Execute _init.
if (!_init.empty())
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), m_depth);
m_ext = make_shared<ExtVM>(m_s, m_envInfo, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), m_depth);
m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress), Account::ContractConception);
m_s.transferBalance(_sender, m_newAddress, _endowment);
@ -406,7 +425,7 @@ void Executive::finalize()
m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice());
u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice();
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned);
m_s.addBalance(m_envInfo.beneficiary(), feesEarned);
}
// Suicides...

39
libethereum/Executive.h

@ -32,10 +32,14 @@ namespace Json
namespace dev
{
class OverlayDB;
namespace eth
{
class State;
class Block;
class BlockChain;
class ExtVM;
struct Manifest;
@ -84,10 +88,32 @@ private:
class Executive
{
public:
/// Basic constructor.
Executive(State& _s, LastHashes const& _lh, unsigned _level = 0): m_s(_s), m_lastHashes(_lh), m_depth(_level) {}
/// Basic constructor.
Executive(State& _s, BlockChain const& _bc, unsigned _level = 0);
/// Simple constructor; executive will operate on given state, with the given environment info.
Executive(State& _s, EnvInfo const& _envInfo, unsigned _level = 0): m_s(_s), m_envInfo(_envInfo), m_depth(_level) {}
/** Easiest constructor.
* Creates executive to operate on the state of end of the given block, populating environment
* info from given Block and the LastHashes portion from the BlockChain.
*/
Executive(Block& _s, BlockChain const& _bc, unsigned _level = 0);
/** LastHashes-split constructor.
* Creates executive to operate on the state of end of the given block, populating environment
* info accordingly, with last hashes given explicitly.
*/
Executive(Block& _s, LastHashes const& _lh = LastHashes(), unsigned _level = 0);
/** Partially-automated split constructor; executive will operate on given state, with the given
* environment info, populating the last hashes from the given chain.
*/
Executive(State& _s, BlockChain const& _bc, EnvInfo const& _envInfo, unsigned _level = 0);
/**
* Automated split constructor; executive will operate on given state, with the environment info
* populated from the given chain.
* @note This will only work when the state to be operated on is already in the chain.
*/
Executive(State& _s, BlockChain const& _bc, unsigned _number, unsigned _level = 0);
Executive(Executive const&) = delete;
void operator=(Executive) = delete;
@ -147,8 +173,9 @@ public:
private:
State& m_s; ///< The state to which this operation/transaction is applied.
LastHashes m_lastHashes;
std::shared_ptr<ExtVM> m_ext; ///< The VM externality object for the VM execution or null if no VM is required. shared_ptr used only to allow ExtVM forward reference.
// TODO: consider changign to EnvInfo const& to avoid LastHashes copy at every CALL/CREATE
EnvInfo m_envInfo; ///< Information on the runtime environment.
std::shared_ptr<ExtVM> m_ext; ///< The VM externality object for the VM execution or null if no VM is required. shared_ptr used only to allow ExtVM forward reference. This field does *NOT* survive this object.
bytesRef m_outRef; ///< Reference to "expected output" buffer.
ExecutionResult* m_res = nullptr; ///< Optional storage for execution results.
Address m_newAddress; ///< The address of the created contract in the case of create() being called.

10
libethereum/ExtVM.cpp

@ -88,14 +88,14 @@ void go(unsigned _depth, Executive& _e, OnOpFunc const& _onOp)
bool ExtVM::call(CallParameters& _p)
{
Executive e(m_s, lastHashes, depth + 1);
Executive e(m_s, envInfo(), depth + 1);
if (!e.call(_p, gasPrice, origin))
{
#if __clang__ // Enabled for clang only as the problem affects OSX
#if __clang__ // Enabled for clang only as the problem affects OSX
go(depth, e, _p.onOp);
#else
#else
e.go(_p.onOp);
#endif
#endif
e.accrueSubState(sub);
}
_p.gas = e.gas();
@ -108,7 +108,7 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc
// Increment associated nonce for sender.
m_s.noteSending(myAddress);
Executive e(m_s, lastHashes, depth + 1);
Executive e(m_s, envInfo(), depth + 1);
if (!e.create(myAddress, _endowment, gasPrice, io_gas, _code, origin))
{
go(depth, e, _onOp);

4
libethereum/ExtVM.h

@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace
{
public:
/// Full constructor.
ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, unsigned _depth = 0):
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache)
ExtVM(State& _s, EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, unsigned _depth = 0):
ExtVMFace(_envInfo, _myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _depth), m_s(_s), m_origCache(_s.m_cache)
{
m_s.ensureCached(_myAddress, true, true);
}

6
libethereum/GasPricer.h

@ -28,7 +28,7 @@ namespace dev
namespace eth
{
class State;
class Block;
class BlockChain;
enum class TransactionPriority
@ -48,7 +48,7 @@ public:
GasPricer() = default;
virtual ~GasPricer() = default;
virtual u256 ask(State const&) const = 0;
virtual u256 ask(Block const&) const = 0;
virtual u256 bid(TransactionPriority _p = TransactionPriority::Medium) const = 0;
virtual void update(BlockChain const&) {}
@ -64,7 +64,7 @@ public:
void setBid(u256 const& _bid) { m_bid = _bid; }
u256 ask() const { return m_ask; }
u256 ask(State const&) const override { return m_ask; }
u256 ask(Block const&) const override { return m_ask; }
u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return m_bid; }
private:

2
libethereum/Interface.h

@ -194,7 +194,7 @@ public:
// [MINING API]:
/// Set the coinbase address.
virtual void setAddress(Address _us) = 0;
virtual void setBeneficiary(Address _us) = 0;
/// Get the coinbase address.
virtual Address address() const = 0;

4
libethereum/LogFilter.cpp

@ -22,7 +22,7 @@
#include "LogFilter.h"
#include <libdevcore/SHA3.h>
#include "State.h"
#include "Block.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
@ -80,7 +80,7 @@ bool LogFilter::matches(LogBloom _bloom) const
return true;
}
bool LogFilter::matches(State const& _s, unsigned _i) const
bool LogFilter::matches(Block const& _s, unsigned _i) const
{
return matches(_s.receipt(_i)).size() > 0;
}

3
libethereum/LogFilter.h

@ -41,6 +41,7 @@ namespace eth
std::ostream& operator<<(std::ostream& _out, dev::eth::LogFilter const& _s);
class State;
class Block;
class LogFilter
{
@ -65,7 +66,7 @@ public:
std::vector<LogBloom> bloomPossibilities() const;
bool matches(LogBloom _bloom) const;
bool matches(State const& _s, unsigned _i) const;
bool matches(Block const& _b, unsigned _i) const;
LogEntries matches(TransactionReceipt const& _r) const;
LogFilter address(Address _a) { m_addresses.insert(_a); return *this; }

794
libethereum/State.cpp

@ -54,6 +54,25 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; }
const char* StateTrace::name() { return EthViolet "" EthGray ""; }
const char* StateChat::name() { return EthViolet "" EthWhite ""; }
State::State(OverlayDB const& _db, BaseState _bs):
m_db(_db),
m_state(&m_db)
{
if (_bs != BaseState::PreExisting)
// Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly.
m_state.init();
paranoia("end of normal construction.", true);
}
State::State(State const& _s):
m_db(_s.m_db),
m_state(&m_db, _s.m_state.root(), Verification::Skip),
m_cache(_s.m_cache),
m_touched(_s.m_touched)
{
paranoia("after state cloning (copy cons).", true);
}
OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we)
{
std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath;
@ -92,80 +111,10 @@ OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash,
return OverlayDB(db);
}
State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress):
m_db(_db),
m_state(&m_db),
m_ourAddress(_coinbaseAddress),
m_blockReward(c_blockReward)
{
if (_bs != BaseState::PreExisting)
// Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly.
m_state.init();
paranoia("beginning of Genesis construction.", true);
m_previousBlock.clear();
m_currentBlock.clear();
// assert(m_state.root() == m_previousBlock.stateRoot());
paranoia("end of normal construction.", true);
}
PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& _h, ImportRequirements::value _ir)
{
PopulationStatistics ret { 0.0, 0.0 };
if (!_bc.isKnown(_h))
{
// Might be worth throwing here.
cwarn << "Invalid block given for state population: " << _h;
BOOST_THROW_EXCEPTION(BlockNotFound() << errinfo_target(_h));
}
auto b = _bc.block(_h);
BlockInfo bi(b);
if (bi.number())
{
// Non-genesis:
// 1. Start at parent's end state (state root).
BlockInfo bip(_bc.block(bi.parentHash()));
sync(_bc, bi.parentHash(), bip);
// 2. Enact the block's transactions onto this state.
m_ourAddress = bi.coinbaseAddress();
Timer t;
auto vb = _bc.verifyBlock(&b, function<void(Exception&)>(), _ir | ImportRequirements::TransactionBasic);
ret.verify = t.elapsed();
t.restart();
enact(vb, _bc);
ret.enact = t.elapsed();
}
else
{
// Genesis required:
// We know there are no transactions, so just populate directly.
m_state.init();
sync(_bc, _h, bi);
}
return ret;
}
State::State(State const& _s):
m_db(_s.m_db),
m_state(&m_db, _s.m_state.root(), Verification::Skip),
m_transactions(_s.m_transactions),
m_receipts(_s.m_receipts),
m_transactionSet(_s.m_transactionSet),
m_touched(_s.m_touched),
m_cache(_s.m_cache),
m_previousBlock(_s.m_previousBlock),
m_currentBlock(_s.m_currentBlock),
m_ourAddress(_s.m_ourAddress),
m_blockReward(_s.m_blockReward)
void State::populateFrom(AccountMap const& _map)
{
paranoia("after state cloning (copy cons).", true);
eth::commit(_map, m_state);
commit();
}
void State::paranoia(std::string const& _when, bool _enforceRefs) const
@ -188,18 +137,9 @@ State& State::operator=(State const& _s)
{
m_db = _s.m_db;
m_state.open(&m_db, _s.m_state.root(), Verification::Skip);
m_transactions = _s.m_transactions;
m_receipts = _s.m_receipts;
m_transactionSet = _s.m_transactionSet;
m_cache = _s.m_cache;
m_previousBlock = _s.m_previousBlock;
m_currentBlock = _s.m_currentBlock;
m_ourAddress = _s.m_ourAddress;
m_blockReward = _s.m_blockReward;
m_lastTx = _s.m_lastTx;
m_touched = _s.m_touched;
paranoia("after state cloning (assignment op)", true);
m_committedToMine = false;
return *this;
}
@ -280,159 +220,6 @@ void State::commit()
m_cache.clear();
}
bool State::sync(BlockChain const& _bc)
{
return sync(_bc, _bc.currentHash());
}
bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi)
{
bool ret = false;
// BLOCK
BlockInfo bi = _bi ? _bi : _bc.info(_block);
#if ETH_PARANOIA
if (!bi)
while (1)
{
try
{
auto b = _bc.block(_block);
bi.populate(b);
break;
}
catch (Exception const& _e)
{
// TODO: Slightly nicer handling? :-)
cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
cerr << diagnostic_information(_e) << endl;
}
catch (std::exception const& _e)
{
// TODO: Slightly nicer handling? :-)
cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
cerr << _e.what() << endl;
}
}
#endif
if (bi == m_currentBlock)
{
// We mined the last block.
// Our state is good - we just need to move on to next.
m_previousBlock = m_currentBlock;
resetCurrent();
ret = true;
}
else if (bi == m_previousBlock)
{
// No change since last sync.
// Carry on as we were.
}
else
{
// New blocks available, or we've switched to a different branch. All change.
// Find most recent state dump and replay what's left.
// (Most recent state dump might end up being genesis.)
if (m_db.lookup(bi.stateRoot()).empty())
{
cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database.";
cwarn << "Database corrupt: contains block without stateRoot:" << bi;
cwarn << "Try rescuing the database by running: eth --rescue";
BOOST_THROW_EXCEPTION(InvalidStateRoot() << errinfo_target(bi.stateRoot()));
}
m_previousBlock = bi;
resetCurrent();
ret = true;
}
#if ALLOW_REBUILD
else
{
// New blocks available, or we've switched to a different branch. All change.
// Find most recent state dump and replay what's left.
// (Most recent state dump might end up being genesis.)
std::vector<h256> chain;
while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block...
{
chain.push_back(bi.hash()); // push back for later replay.
bi.populate(_bc.block(bi.parentHash())); // move to parent.
}
m_previousBlock = bi;
resetCurrent();
// Iterate through in reverse, playing back each of the blocks.
try
{
for (auto it = chain.rbegin(); it != chain.rend(); ++it)
{
auto b = _bc.block(*it);
enact(&b, _bc, _ir);
cleanup(true);
}
}
catch (...)
{
// TODO: Slightly nicer handling? :-)
cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
cerr << boost::current_exception_diagnostic_information() << endl;
exit(1);
}
resetCurrent();
ret = true;
}
#endif
return ret;
}
u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc)
{
#if ETH_TIMED_ENACTMENTS
Timer t;
double populateVerify;
double populateGrand;
double syncReset;
double enactment;
#endif
// Check family:
BlockInfo biParent = _bc.info(_block.info.parentHash());
_block.info.verifyParent(biParent);
#if ETH_TIMED_ENACTMENTS
populateVerify = t.elapsed();
t.restart();
#endif
BlockInfo biGrandParent;
if (biParent.number())
biGrandParent = _bc.info(biParent.parentHash());
#if ETH_TIMED_ENACTMENTS
populateGrand = t.elapsed();
t.restart();
#endif
sync(_bc, _block.info.parentHash(), BlockInfo());
resetCurrent();
#if ETH_TIMED_ENACTMENTS
syncReset = t.elapsed();
t.restart();
#endif
m_previousBlock = biParent;
auto ret = enact(_block, _bc);
#if ETH_TIMED_ENACTMENTS
enactment = t.elapsed();
if (populateVerify + populateGrand + syncReset + enactment > 0.5)
clog(StateChat) << "popVer/popGrand/syncReset/enactment = " << populateVerify << "/" << populateGrand << "/" << syncReset << "/" << enactment;
#endif
return ret;
}
unordered_map<Address, u256> State::addresses() const
{
#if ETH_FATDB
@ -449,496 +236,14 @@ unordered_map<Address, u256> State::addresses() const
#endif
}
void State::resetCurrent()
void State::setRoot(h256 const& _r)
{
m_transactions.clear();
m_receipts.clear();
m_transactionSet.clear();
m_cache.clear();
m_touched.clear();
m_currentBlock = BlockInfo();
m_currentBlock.setCoinbaseAddress(m_ourAddress);
m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0)));
m_currentBlock.populateFromParent(m_previousBlock);
// TODO: check.
m_lastTx = m_db;
m_state.setRoot(m_previousBlock.stateRoot());
m_committedToMine = false;
m_state.setRoot(_r);
paranoia("begin resetCurrent", true);
}
pair<TransactionReceipts, bool> State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, unsigned msTimeout)
{
// TRANSACTIONS
pair<TransactionReceipts, bool> ret;
ret.second = false;
auto ts = _tq.topTransactions(c_maxSyncTransactions);
LastHashes lh;
auto deadline = chrono::steady_clock::now() + chrono::milliseconds(msTimeout);
for (int goodTxs = 1; goodTxs; )
{
goodTxs = 0;
for (auto const& t: ts)
if (!m_transactionSet.count(t.sha3()))
{
try
{
if (t.gasPrice() >= _gp.ask(*this))
{
// Timer t;
if (lh.empty())
lh = _bc.lastHashes();
execute(lh, t);
ret.first.push_back(m_receipts.back());
++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
}
else if (t.gasPrice() < _gp.ask(*this) * 9 / 10)
{
clog(StateTrace) << t.sha3() << "Dropping El Cheapo transaction (<90% of ask price)";
_tq.drop(t.sha3());
}
}
catch (InvalidNonce const& in)
{
bigint const& req = *boost::get_error_info<errinfo_required>(in);
bigint const& got = *boost::get_error_info<errinfo_got>(in);
if (req > got)
{
// too old
clog(StateTrace) << t.sha3() << "Dropping old transaction (nonce too low)";
_tq.drop(t.sha3());
}
else if (got > req + _tq.waiting(t.sender()))
{
// too new
clog(StateTrace) << t.sha3() << "Dropping new transaction (too many nonces ahead)";
_tq.drop(t.sha3());
}
else
_tq.setFuture(t.sha3());
}
catch (BlockGasLimitReached const& e)
{
bigint const& got = *boost::get_error_info<errinfo_got>(e);
if (got > m_currentBlock.gasLimit())
{
clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)";
_tq.drop(t.sha3());
}
else
{
// Temporarily no gas left in current block.
// OPTIMISE: could note this and then we don't evaluate until a block that does have the gas left.
// for now, just leave alone.
}
}
catch (Exception const& _e)
{
// Something else went wrong - drop it.
clog(StateTrace) << t.sha3() << "Dropping invalid transaction:" << diagnostic_information(_e);
_tq.drop(t.sha3());
}
catch (std::exception const&)
{
// Something else went wrong - drop it.
_tq.drop(t.sha3());
cwarn << t.sha3() << "Transaction caused low-level exception :(";
}
}
if (chrono::steady_clock::now() > deadline)
{
ret.second = true;
break;
}
}
return ret;
}
string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir)
{
RLP rlp(_block);
cleanup(false);
BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal);
m_currentBlock = bi;
m_currentBlock.verifyInternals(_block);
m_currentBlock.noteDirty();
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number());
string ret;
unsigned i = 0;
for (auto const& tr: rlp[1])
{
StandardTrace st;
st.setShowMnemonics();
execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, st.onOp());
ret += (ret.empty() ? "[" : ",") + st.json();
++i;
}
return ret.empty() ? "[]" : (ret + "]");
}
u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc)
{
DEV_TIMED_FUNCTION_ABOVE(500);
// m_currentBlock is assumed to be prepopulated and reset.
#if !ETH_RELEASE
assert(m_previousBlock.hash() == _block.info.parentHash());
assert(m_currentBlock.parentHash() == _block.info.parentHash());
assert(rootHash() == m_previousBlock.stateRoot());
#endif
if (m_currentBlock.parentHash() != m_previousBlock.hash())
// Internal client error.
BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values.
m_currentBlock.noteDirty();
m_currentBlock = _block.info;
// cnote << "playback begins:" << m_state.root();
// cnote << m_state;
LastHashes lh;
DEV_TIMED_ABOVE("lastHashes", 500)
lh = _bc.lastHashes((unsigned)m_previousBlock.number());
RLP rlp(_block.block);
vector<bytes> receipts;
// All ok with the block generally. Play back the transactions now...
unsigned i = 0;
DEV_TIMED_ABOVE("txExec", 500)
for (auto const& tr: _block.transactions)
{
try
{
LogOverride<ExecutiveWarnChannel> o(false);
execute(lh, tr);
}
catch (Exception& ex)
{
ex << errinfo_transactionIndex(i);
throw;
}
RLPStream receiptRLP;
m_receipts.back().streamRLP(receiptRLP);
receipts.push_back(receiptRLP.out());
++i;
}
h256 receiptsRoot;
DEV_TIMED_ABOVE(".receiptsRoot()", 500)
receiptsRoot = orderedTrieRoot(receipts);
if (receiptsRoot != m_currentBlock.receiptsRoot())
{
InvalidReceiptsStateRoot ex;
ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot());
ex << errinfo_receipts(receipts);
// ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None));
BOOST_THROW_EXCEPTION(ex);
}
if (m_currentBlock.logBloom() != logBloom())
{
InvalidLogBloom ex;
ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom());
ex << errinfo_receipts(receipts);
BOOST_THROW_EXCEPTION(ex);
}
// Initialise total difficulty calculation.
u256 tdIncrease = m_currentBlock.difficulty();
// Check uncles & apply their rewards to state.
if (rlp[2].itemCount() > 2)
{
TooManyUncles ex;
ex << errinfo_max(2);
ex << errinfo_got(rlp[2].itemCount());
BOOST_THROW_EXCEPTION(ex);
}
vector<BlockInfo> rewarded;
h256Hash excluded;
DEV_TIMED_ABOVE("allKin", 500)
excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6);
excluded.insert(m_currentBlock.hash());
unsigned ii = 0;
DEV_TIMED_ABOVE("uncleCheck", 500)
for (auto const& i: rlp[2])
{
try
{
auto h = sha3(i.data());
if (excluded.count(h))
{
UncleInChain ex;
ex << errinfo_comment("Uncle in block already mentioned");
ex << errinfo_unclesExcluded(excluded);
ex << errinfo_hash256(sha3(i.data()));
BOOST_THROW_EXCEPTION(ex);
}
excluded.insert(h);
// IgnoreSeal since it's a VerifiedBlock.
BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData);
BlockInfo uncleParent;
if (!_bc.isKnown(uncle.parentHash()))
BOOST_THROW_EXCEPTION(UnknownParent());
uncleParent = BlockInfo(_bc.block(uncle.parentHash()));
if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7)
{
UncleTooOld ex;
ex << errinfo_uncleNumber(uncle.number());
ex << errinfo_currentNumber(m_currentBlock.number());
BOOST_THROW_EXCEPTION(ex);
}
else if (uncle.number() == m_currentBlock.number())
{
UncleIsBrother ex;
ex << errinfo_uncleNumber(uncle.number());
ex << errinfo_currentNumber(m_currentBlock.number());
BOOST_THROW_EXCEPTION(ex);
}
uncle.verifyParent(uncleParent);
rewarded.push_back(uncle);
++ii;
}
catch (Exception& ex)
{
ex << errinfo_uncleIndex(ii);
throw;
}
}
DEV_TIMED_ABOVE("applyRewards", 500)
applyRewards(rewarded);
// Commit all cached state changes to the state trie.
DEV_TIMED_ABOVE("commit", 500)
commit();
// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash())
{
auto r = rootHash();
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(r, m_currentBlock.stateRoot()));
}
if (m_currentBlock.gasUsed() != gasUsed())
{
// Rollback the trie.
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed())));
}
return tdIncrease;
}
void State::cleanup(bool _fullCommit)
{
if (_fullCommit)
{
paranoia("immediately before database commit", true);
// Commit the new trie to disk.
if (isChannelVisible<StateTrace>()) // Avoid calling toHex if not needed
clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash())));
try
{
EnforceRefs er(m_db, true);
rootHash();
}
catch (BadRoot const&)
{
clog(StateChat) << "Trie corrupt! :-(";
throw;
}
m_db.commit();
if (isChannelVisible<StateTrace>()) // Avoid calling toHex if not needed
clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash())));
paranoia("immediately after database commit", true);
m_previousBlock = m_currentBlock;
m_currentBlock.populateFromParent(m_previousBlock);
clog(StateTrace) << "finalising enactment. current -> previous, hash is" << m_previousBlock.hash();
}
else
m_db.rollback();
resetCurrent();
}
void State::uncommitToMine()
{
if (m_committedToMine)
{
m_cache.clear();
if (!m_transactions.size())
m_state.setRoot(m_previousBlock.stateRoot());
else
m_state.setRoot(m_receipts.back().stateRoot());
m_db = m_lastTx;
paranoia("Uncommited to mine", true);
m_committedToMine = false;
}
}
LogBloom State::logBloom() const
{
LogBloom ret;
for (TransactionReceipt const& i: m_receipts)
ret |= i.bloom();
return ret;
}
void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
{
uncommitToMine();
m_lastTx = m_db;
vector<BlockInfo> uncleBlockHeaders;
RLPStream unclesData;
unsigned unclesCount = 0;
if (m_previousBlock.number() != 0)
{
// Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations.
clog(StateDetail) << "Checking " << m_previousBlock.hash() << ", parent=" << m_previousBlock.parentHash();
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6);
auto p = m_previousBlock.parentHash();
for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent)
{
auto us = _bc.details(p).children;
assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent!
for (auto const& u: us)
if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about.
{
uncleBlockHeaders.push_back(_bc.info(u));
unclesData.appendRaw(_bc.headerData(u));
++unclesCount;
if (unclesCount == 2)
break;
}
}
}
BytesMap transactionsMap;
BytesMap receiptsMap;
RLPStream txs;
txs.appendList(m_transactions.size());
for (unsigned i = 0; i < m_transactions.size(); ++i)
{
RLPStream k;
k << i;
RLPStream receiptrlp;
m_receipts[i].streamRLP(receiptrlp);
receiptsMap.insert(std::make_pair(k.out(), receiptrlp.out()));
RLPStream txrlp;
m_transactions[i].streamRLP(txrlp);
transactionsMap.insert(std::make_pair(k.out(), txrlp.out()));
txs.appendRaw(txrlp.out());
}
txs.swapOut(m_currentTxs);
RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles);
// Apply rewards last of all.
applyRewards(uncleBlockHeaders);
// Commit any and all changes to the trie that are in the cache, then update the state root accordingly.
commit();
clog(StateDetail) << "Post-reward stateRoot:" << m_state.root();
clog(StateDetail) << m_state;
clog(StateDetail) << *this;
m_currentBlock.setLogBloom(logBloom());
m_currentBlock.setGasUsed(gasUsed());
m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root());
m_currentBlock.setParentHash(m_previousBlock.hash());
m_currentBlock.setExtraData(_extraData);
if (m_currentBlock.extraData().size() > 32)
{
auto ed = m_currentBlock.extraData();
ed.resize(32);
m_currentBlock.setExtraData(ed);
}
m_committedToMine = true;
}
bool State::sealBlock(bytesConstRef _header)
{
if (!m_committedToMine)
return false;
// Check that this header is indeed for this block.
if (BlockInfo(_header, CheckNothing, h256{}, HeaderData).hashWithout() != m_currentBlock.hashWithout())
return false;
// Looks good!
clog(StateDetail) << "Sealing block!";
// Compile block:
RLPStream ret;
ret.appendList(3);
ret.appendRaw(_header);
ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles);
ret.swapOut(m_currentBytes);
m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData);
cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")";
// TODO: move into Sealer
StructuredLogger::minedNewBlock(
m_currentBlock.hash().abridged(),
"", // Can't give the nonce here.
"", //TODO: chain head hash here ??
m_currentBlock.parentHash().abridged()
);
// Quickly reset the transactions.
// TODO: Leave this in a better state than this limbo, or at least record that it's in limbo.
m_transactions.clear();
m_receipts.clear();
m_transactionSet.clear();
m_lastTx = m_db;
return true;
}
bool State::addressInUse(Address const& _id) const
{
ensureCached(_id, false, false);
@ -1138,7 +443,7 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp)
std::pair<ExecutionResult, TransactionReceipt> State::execute(EnvInfo const& _envInfo, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp)
{
auto onOp = _onOp;
#if ETH_VMTRACE
@ -1154,17 +459,13 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
// Create and initialize the executive. This will throw fairly cheaply and quickly if the
// transaction is bad in any way.
Executive e(*this, _lh, 0);
Executive e(*this, _envInfo);
ExecutionResult res;
e.setResultRecipient(res);
e.initialize(_t);
// Uncommitting is a non-trivial operation - only do it once we've verified as much of the
// transaction as possible.
uncommitToMine();
// OK - transaction looks valid - execute.
u256 startGasUsed = gasUsed();
u256 startGasUsed = _envInfo.gasUsed();
#if ETH_PARANOIA
ctrace << "Executing" << e.t() << "on" << h;
ctrace << toHex(e.t().rlp());
@ -1183,7 +484,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
else
{
commit();
#if ETH_PARANOIA && !ETH_FATDB
ctrace << "Executed; now" << rootHash();
ctrace << old.diff(*this);
@ -1200,45 +501,10 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
}
}
#endif
// TODO: CHECK TRIE after level DB flush to make sure exactly the same.
// Add to the user-originated transactions that we've executed.
m_transactions.push_back(e.t());
m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs()));
m_transactionSet.insert(e.t().sha3());
}
return res;
}
State State::fromPending(unsigned _i) const
{
State ret = *this;
ret.m_cache.clear();
_i = min<unsigned>(_i, m_transactions.size());
if (!_i)
ret.m_state.setRoot(m_previousBlock.stateRoot());
else
ret.m_state.setRoot(m_receipts[_i - 1].stateRoot());
while (ret.m_transactions.size() > _i)
{
ret.m_transactionSet.erase(ret.m_transactions.back().sha3());
ret.m_transactions.pop_back();
ret.m_receipts.pop_back();
}
return ret;
}
void State::applyRewards(vector<BlockInfo> const& _uncleBlockHeaders)
{
u256 r = m_blockReward;
for (auto const& i: _uncleBlockHeaders)
{
addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8);
r += m_blockReward / 32;
}
addBalance(m_currentBlock.coinbaseAddress(), r);
return make_pair(res, TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs()));
}
std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)

153
libethereum/State.h

@ -85,16 +85,10 @@ enum class Permanence
Committed
};
struct PopulationStatistics
{
double verify;
double enact;
};
/**
* @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
* Should maintain ledger as of last N blocks, also, in case we end up on the wrong branch.
* @brief Model of an Ethereum state, essentially a facade for the trie.
* Allows you to query the state of accounts, and has built-in caching for various aspects of the
* state.
*/
class State
{
@ -113,7 +107,7 @@ public:
/// which uses it. If you have no preexisting database then set BaseState to something other
/// than BaseState::PreExisting in order to prepopulate the Trie.
/// You can also set the coinbase address.
explicit State(OverlayDB const& _db, BaseState _bs = BaseState::PreExisting, Address _coinbaseAddress = Address());
explicit State(OverlayDB const& _db, BaseState _bs = BaseState::PreExisting);
/// Copy state object.
State(State const& _s);
@ -121,66 +115,23 @@ public:
/// Copy state object.
State& operator=(State const& _s);
/// Construct state object from arbitrary point in blockchain.
PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None);
/// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block.
void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); }
Address address() const { return m_ourAddress; }
/// Open a DB - useful for passing into the constructor & keeping for other states that are necessary.
static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust);
static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); }
OverlayDB const& db() const { return m_db; }
OverlayDB& db() { return m_db; }
/// Populate the state from the given AccountMap. Just uses dev::eth::commit().
void populateFrom(AccountMap const& _map);
/// @returns the set containing all addresses currently in use in Ethereum.
/// @warning This is slowslowslow. Don't use it unless you want to lock the object for seconds or minutes at a time.
/// @throws InterfaceNotSupported if compiled without ETH_FATDB.
std::unordered_map<Address, u256> addresses() const;
/// Get the header information on the present block.
BlockInfo const& info() const { return m_currentBlock; }
/// Prepares the current state for mining.
/// Commits all transactions into the trie, compiles uncles and transactions list, applies all
/// rewards and populates the current block header with the appropriate hashes.
/// The only thing left to do after this is to actually mine().
///
/// This may be called multiple times and without issue.
void commitToMine(BlockChain const& _bc, bytes const& _extraData = {});
/// Pass in a solution to the proof-of-work.
/// @returns true iff we were previously committed to mining.
/// TODO: verify it prior to calling this.
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
* @code
* while (notYetMined)
* {
* // lock
* commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* completeMine();
* // unlock
* @endcode
*/
bool sealBlock(bytes const& _header) { return sealBlock(&_header); }
bool sealBlock(bytesConstRef _header);
/// Get the complete current block, including valid nonce.
/// Only valid after mine() returns true.
bytes const& blockData() const { return m_currentBytes; }
/// Sync our transactions, killing those from the queue that we have and assimilating those that we don't.
/// @returns a list of receipts one for each transaction placed from the queue into the state and bool, true iff there are more transactions to be processed.
std::pair<TransactionReceipts, bool> sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, unsigned _msTimeout = 100);
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); }
/// This will change the state accordingly.
std::pair<ExecutionResult, TransactionReceipt> execute(EnvInfo const& _envInfo, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());
/// Check if the address is in use.
bool addressInUse(Address const& _address) const;
@ -246,63 +197,18 @@ public:
/// The hash of the root of our state tree.
h256 rootHash() const { return m_state.root(); }
/// Get the list of pending transactions.
Transactions const& pending() const { return m_transactions; }
/// Get the list of hashes of pending transactions.
h256Hash const& pendingHashes() const { return m_transactionSet; }
/// Get the transaction receipt for the transaction of the given index.
TransactionReceipt const& receipt(unsigned _i) const { return m_receipts[_i]; }
/// Get the list of pending transactions.
LogEntries const& log(unsigned _i) const { return m_receipts[_i].log(); }
/// Get the bloom filter of all logs that happened in the block.
LogBloom logBloom() const;
/// Get the bloom filter of a particular transaction that happened in the block.
LogBloom const& logBloom(unsigned _i) const { return m_receipts[_i].bloom(); }
/// Get the State immediately after the given number of pending transactions have been applied.
/// If (_i == 0) returns the initial state of the block.
/// If (_i == pending().size()) returns the final state of the block, prior to rewards.
State fromPending(unsigned _i) const;
/// @returns the StateDiff caused by the pending transaction of index @a _i.
StateDiff pendingDiff(unsigned _i) const { return fromPending(_i).diff(fromPending(_i + 1), true); }
/// @return the difference between this state (origin) and @a _c (destination).
/// @param _quick if true doesn't check all addresses possible (/very/ slow for a full chain)
/// but rather only those touched by the transactions in creating the two States.
StateDiff diff(State const& _c, bool _quick = false) const;
/// 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);
/// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block.
bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo());
/// Execute all transactions within a given block.
/// @returns the additional total difficulty.
u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc);
/// Returns back to a pristine state after having done a playback.
/// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates
/// the block since all state changes are ultimately reversed.
void cleanup(bool _fullCommit);
/// Commit all changes waiting in the address cache to the DB.
void commit();
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();
/// Resets any uncommitted changes to the cache.
void setRoot(h256 const& _root);
private:
/// Undo the changes to the state for committing to mine.
void uncommitToMine();
/// Retrieve all information about a given address into the cache.
/// If _requireMemory is true, grab the full memory should it be a contract item.
/// If _forceCreate is true, then insert a default item into the cache, in the case it doesn't
@ -312,45 +218,16 @@ private:
/// Retrieve all information about a given address into a cache.
void ensureCached(std::unordered_map<Address, Account>& _cache, Address const& _a, bool _requireCode, bool _forceCreate) const;
/// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc);
/// Finalise the block, applying the earned rewards.
void applyRewards(std::vector<BlockInfo> const& _uncleBlockHeaders);
/// @returns gas used by transactions thus far executed.
u256 gasUsed() const { return m_receipts.size() ? m_receipts.back().gasUsed() : 0; }
/// Debugging only. Good for checking the Trie is in shape.
bool isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const;
/// Debugging only. Good for checking the Trie is in shape.
void paranoia(std::string const& _when, bool _enforceRefs = false) const;
/// Provide a standard VM trace for debugging purposes.
std::string vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir);
OverlayDB m_db; ///< Our overlay for the state tree.
SecureTrieDB<Address, OverlayDB> m_state; ///< Our state tree, as an OverlayDB DB.
Transactions m_transactions; ///< The current list of transactions that we've included in the state.
TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts.
h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state.
OverlayDB m_lastTx;
AddressHash m_touched; ///< Tracks all addresses touched by transactions so far.
mutable std::unordered_map<Address, Account> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.
BlockInfo m_previousBlock; ///< The previous block's information.
BlockInfo m_currentBlock; ///< The current block's information.
bytes m_currentBytes; ///< The current block.
bool m_committedToMine = false; ///< Have we committed to mine on the present m_currentBlock?
bytes m_currentTxs; ///< The RLP-encoded block of transactions.
bytes m_currentUncles; ///< The RLP-encoded block of uncles.
Address m_ourAddress; ///< Our address (i.e. the address to which fees go).
u256 m_blockReward;
AddressHash m_touched; ///< Tracks all addresses touched so far.
static std::string c_defaultPath;
@ -360,7 +237,7 @@ private:
std::ostream& operator<<(std::ostream& _out, State const& _s);
template <class DB>
AddressHash commit(std::unordered_map<Address, Account> const& _cache, SecureTrieDB<Address, DB>& _state)
AddressHash commit(AccountMap const& _cache, SecureTrieDB<Address, DB>& _state)
{
AddressHash ret;
for (auto const& i: _cache)

6
libevm/ExtVMFace.cpp

@ -24,7 +24,8 @@
using namespace dev;
using namespace dev::eth;
ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth):
ExtVMFace::ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, unsigned _depth):
m_envInfo(_envInfo),
myAddress(_myAddress),
caller(_caller),
origin(_origin),
@ -33,8 +34,5 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256
data(_data),
code(std::move(_code)),
codeHash(_codeHash),
lastHashes(_lh),
previousBlock(_previousBlock),
currentBlock(_currentBlock),
depth(_depth)
{}

66
libevm/ExtVMFace.h

@ -162,6 +162,57 @@ struct CallParameters
OnOpFunc onOp;
};
class EnvInfo
{
public:
EnvInfo() {}
EnvInfo(BlockInfo const& _current, LastHashes const& _lh = LastHashes(), u256 const& _gasUsed = u256()):
m_number(_current.number()),
m_beneficiary(_current.beneficiary()),
m_timestamp(_current.timestamp()),
m_difficulty(_current.difficulty()),
m_gasLimit(_current.gasLimit()),
m_lastHashes(_lh),
m_gasUsed(_gasUsed)
{}
EnvInfo(BlockInfo const& _current, LastHashes&& _lh, u256 const& _gasUsed = u256()):
m_number(_current.number()),
m_beneficiary(_current.beneficiary()),
m_timestamp(_current.timestamp()),
m_difficulty(_current.difficulty()),
m_gasLimit(_current.gasLimit()),
m_lastHashes(_lh),
m_gasUsed(_gasUsed)
{}
u256 const& number() const { return m_number; }
Address const& beneficiary() const { return m_beneficiary; }
u256 const& timestamp() const { return m_timestamp; }
u256 const& difficulty() const { return m_difficulty; }
u256 const& gasLimit() const { return m_gasLimit; }
LastHashes const& lastHashes() const { return m_lastHashes; }
u256 const& gasUsed() const { return m_gasUsed; }
void setNumber(u256 const& _v) { m_number = _v; }
void setBeneficiary(Address const& _v) { m_beneficiary = _v; }
void setTimestamp(u256 const& _v) { m_timestamp = _v; }
void setDifficulty(u256 const& _v) { m_difficulty = _v; }
void setGasLimit(u256 const& _v) { m_gasLimit = _v; }
void setLastHashes(LastHashes const& _lh) { m_lastHashes = _lh; }
void setLastHashes(LastHashes&& _lh) { m_lastHashes = _lh; }
void setGasUsed(u256 const& _v) { m_gasUsed = _v; }
private:
u256 m_number;
Address m_beneficiary;
u256 m_timestamp;
u256 m_difficulty;
u256 m_gasLimit;
LastHashes m_lastHashes;
u256 m_gasUsed;
};
/**
* @brief Interface and null implementation of the class for specifying VM externalities.
*/
@ -172,7 +223,7 @@ public:
ExtVMFace() = default;
/// Full constructor.
ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth);
ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, unsigned _depth);
virtual ~ExtVMFace() = default;
@ -216,11 +267,19 @@ public:
virtual void revert() {}
/// Hash of a block if within the last 256 blocks, or h256() otherwise.
h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max<u256>(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); }
h256 blockHash(u256 _number) { return _number < envInfo().number() && _number >= (std::max<u256>(256, envInfo().number()) - 256) ? envInfo().lastHashes()[(unsigned)(envInfo().number() - 1 - _number)] : h256(); }
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; }
/// Get the execution environment information.
EnvInfo const& envInfo() const { return m_envInfo; }
private:
EnvInfo const& m_envInfo;
public:
// TODO: make private
Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be).
Address caller; ///< Address which sent the message (either equal to origin or a contract).
Address origin; ///< Original transactor.
@ -229,9 +288,6 @@ public:
bytesConstRef data; ///< Current input data.
bytes code; ///< Current code that is executing.
h256 codeHash; ///< SHA3 hash of the executing code
LastHashes lastHashes; ///< Most recent 256 blocks' hashes.
BlockInfo previousBlock; ///< The previous block's information. TODO: PoC-8: REMOVE
BlockInfo currentBlock; ///< The current block's information.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
unsigned depth = 0; ///< Depth of the present call.
};

12
libevm/VM.cpp

@ -398,22 +398,22 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
m_stack.push_back(_ext.gasPrice);
break;
case Instruction::BLOCKHASH:
m_stack.back() = (u256)_ext.blockhash(m_stack.back());
m_stack.back() = (u256)_ext.blockHash(m_stack.back());
break;
case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress());
m_stack.push_back((u160)_ext.envInfo().beneficiary());
break;
case Instruction::TIMESTAMP:
m_stack.push_back(_ext.currentBlock.timestamp());
m_stack.push_back(_ext.envInfo().timestamp());
break;
case Instruction::NUMBER:
m_stack.push_back(_ext.currentBlock.number());
m_stack.push_back(_ext.envInfo().number());
break;
case Instruction::DIFFICULTY:
m_stack.push_back(_ext.currentBlock.difficulty());
m_stack.push_back(_ext.envInfo().difficulty());
break;
case Instruction::GASLIMIT:
m_stack.push_back(_ext.currentBlock.gasLimit());
m_stack.push_back(_ext.envInfo().gasLimit());
break;
case Instruction::PUSH1:
case Instruction::PUSH2:

16
libtestutils/BlockChainLoader.cpp

@ -21,9 +21,7 @@
#include <libethereum/CanonBlockChain.h>
#include "BlockChainLoader.h"
#include "StateLoader.h"
#include "Common.h"
using namespace std;
using namespace dev;
using namespace dev::test;
@ -31,21 +29,21 @@ using namespace dev::eth;
BlockChainLoader::BlockChainLoader(Json::Value const& _json)
{
// load genesisBlock
m_bc.reset(new FullBlockChain<Ethash>(fromHex(_json["genesisRLP"].asString()), jsonToAccountMap(_json["pre"].asString()), m_dir.path(), WithExisting::Kill));
// load pre state
StateLoader sl(_json["pre"], m_dir.path());
m_state = sl.state();
m_block = m_bc->genesisBlock(State::openDB(m_dir.path(), m_bc->genesisHash(), WithExisting::Kill));
// load genesisBlock
m_bc.reset(new FullBlockChain<Ethash>(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill));
assert(m_state.rootHash() == m_bc->info().stateRoot());
assert(m_block.rootHash() == m_bc->info().stateRoot());
// load blocks
for (auto const& block: _json["blocks"])
{
bytes rlp = fromHex(block["rlp"].asString());
m_bc->import(rlp, m_state.db());
m_bc->import(rlp, state().db());
}
// sync state
m_state.sync(*m_bc);
m_block.sync(*m_bc);
}

7
libtestutils/BlockChainLoader.h

@ -24,7 +24,7 @@
#include <json/json.h>
#include <libdevcore/TransientDirectory.h>
#include <libethereum/BlockChain.h>
#include <libethereum/State.h>
#include <libethereum/Block.h>
namespace dev
{
@ -40,12 +40,13 @@ class BlockChainLoader
public:
BlockChainLoader(Json::Value const& _json);
eth::BlockChain const& bc() const { return *m_bc; }
eth::State const& state() const { return m_state; }
eth::State const& state() const { return m_block.state(); } // TODO remove?
eth::Block const& block() const { return m_block; }
private:
TransientDirectory m_dir;
std::unique_ptr<eth::BlockChain> m_bc;
eth::State m_state;
eth::Block m_block;
};
}

4
libtestutils/FixedClient.cpp

@ -25,10 +25,10 @@ using namespace dev;
using namespace dev::eth;
using namespace dev::test;
eth::State FixedClient::asOf(h256 const& _h) const
Block FixedClient::asOf(h256 const& _h) const
{
ReadGuard l(x_stateDB);
State ret(m_state.db());
Block ret(m_block.db());
ret.populateFromChain(bc(), _h);
return ret;
}

12
libtestutils/FixedClient.h

@ -37,7 +37,7 @@ namespace test
class FixedClient: public dev::eth::ClientBase
{
public:
FixedClient(eth::BlockChain const& _bc, eth::State _state) : m_bc(_bc), m_state(_state) {}
FixedClient(eth::BlockChain const& _bc, eth::Block const& _block) : m_bc(_bc), m_block(_block) {}
virtual ~FixedClient() {}
// stub
@ -45,15 +45,15 @@ public:
virtual eth::BlockChain& bc() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("FixedClient::bc()")); }
virtual eth::BlockChain const& bc() const override { return m_bc; }
using ClientBase::asOf;
virtual eth::State asOf(h256 const& _h) const override;
virtual eth::State preMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual eth::State postMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual void setAddress(Address _us) override { WriteGuard l(x_stateDB); m_state.setAddress(_us); }
virtual eth::Block asOf(h256 const& _h) const override;
virtual eth::Block preMine() const override { ReadGuard l(x_stateDB); return m_block; }
virtual eth::Block postMine() const override { ReadGuard l(x_stateDB); return m_block; }
virtual void setBeneficiary(Address _us) override { WriteGuard l(x_stateDB); m_block.setBeneficiary(_us); }
virtual void prepareForTransaction() override {}
private:
eth::BlockChain const& m_bc;
eth::State m_state;
eth::Block m_block;
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
};

57
libtestutils/StateLoader.cpp

@ -1,57 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file StateLoader.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include "StateLoader.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath):
m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty)
{
for (string const& name: _json.getMemberNames())
{
Json::Value o = _json[name];
Address address = Address(name);
bytes code = fromHex(o["code"].asString().substr(2));
if (!code.empty())
{
m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::ContractConception);
m_state.m_cache[address].setCode(std::move(code));
}
else
m_state.m_cache[address] = Account(u256(o["balance"].asString()), Account::NormalCreation);
for (string const& j: o["storage"].getMemberNames())
m_state.setStorage(address, u256(j), u256(o["storage"][j].asString()));
for (auto i = 0; i < u256(o["nonce"].asString()); ++i)
m_state.noteSending(address);
m_state.ensureCached(address, false, false);
}
m_state.commit();
}

49
libtestutils/StateLoader.h

@ -1,49 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file StateLoader.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <json/json.h>
#include <libdevcore/TransientDirectory.h>
#include <libethereum/State.h>
#include <libethereum/BlockChain.h>
namespace dev
{
namespace test
{
/**
* @brief Friend of State, loads State from given JSON object
*/
class StateLoader
{
public:
StateLoader(Json::Value const& _json, std::string const& _dbPath);
eth::State const& state() const { return m_state; }
eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; }
private:
eth::State m_state;
};
}
}

2
libweb3jsonrpc/JsonHelper.cpp

@ -90,7 +90,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi)
res["hash"] = toJS(_bi.hash());
res["parentHash"] = toJS(_bi.parentHash());
res["sha3Uncles"] = toJS(_bi.sha3Uncles());
res["miner"] = toJS(_bi.coinbaseAddress());
res["miner"] = toJS(_bi.beneficiary());
res["stateRoot"] = toJS(_bi.stateRoot());
res["transactionsRoot"] = toJS(_bi.transactionsRoot());
res["difficulty"] = toJS(_bi.difficulty());

11
libweb3jsonrpc/WebThreeStubServer.cpp

@ -29,6 +29,7 @@
#include <libdevcore/CommonJS.h>
#include <libethcore/KeyManager.h>
#include <libethereum/Executive.h>
#include <libethereum/Block.h>
#include <libwebthree/WebThree.h>
#include "JsonHelper.h"
using namespace std;
@ -270,16 +271,14 @@ Json::Value WebThreeStubServer::admin_eth_vmTrace(std::string const& _blockNumbe
Json::Value ret;
auto c = m_web3.ethereum();
State state = c->state(_txIndex + 1, blockHash(_blockNumberOrHash));
if (_txIndex < 0)
throw jsonrpc::JsonRpcException("Negative index");
if ((unsigned)_txIndex < state.pending().size())
Block block = c->block(blockHash(_blockNumberOrHash));
if ((unsigned)_txIndex < block.pending().size())
{
Transaction t = block.pending()[_txIndex];
State state = block.fromPending(_txIndex);
Executive e(state, bc(), 0);
Transaction t = state.pending()[_txIndex];
state = state.fromPending(_txIndex);
try
{
StandardTrace st;

71
mix/MixClient.cpp

@ -93,10 +93,10 @@ void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts
h256 stateRoot = accountState.root();
m_bc.reset();
m_bc.reset(new MixBlockChain(m_dbPath, stateRoot));
State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address());
s.sync(bc());
m_state = s;
m_startState = m_state;
Block b(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address());
b.sync(bc());
m_preMine = b;
m_postMine = b;
WriteGuard lx(x_executions);
m_executions.clear();
}
@ -122,12 +122,13 @@ Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secre
return ret;
}
ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, LastHashes const& _lastHashes, bool _call)
// TODO: prototype changed - will need rejigging.
ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, EnvInfo const& _envInfo, bool _call)
{
State execState = _state;
execState.addBalance(_t.sender(), _t.gas() * _t.gasPrice()); //give it enough balance for gas estimation
eth::ExecutionResult er;
Executive execution(execState, _lastHashes, 0);
Executive execution(execState, _envInfo);
execution.setResultRecipient(er);
execution.initialize(_t);
execution.execute();
@ -239,35 +240,31 @@ ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const&
if (_t.isCreation())
d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce())));
if (!_call)
d.transactionIndex = m_state.pending().size();
d.transactionIndex = m_postMine.pending().size();
d.executonIndex = m_executions.size();
return d;
}
void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret)
void MixClient::executeTransaction(Transaction const& _t, Block& _block, bool _call, bool _gasAuto, Secret const& _secret)
{
Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t;
// do debugging run first
LastHashes lastHashes(256);
lastHashes[0] = bc().numberHash(bc().number());
for (unsigned i = 1; i < 256; ++i)
lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256();
Transaction t = _gasAuto ? replaceGas(_t, m_postMine.gasLimitRemaining()) : _t;
ExecutionResult d = debugTransaction(t, _state, lastHashes, _call);
// do debugging run first
EnvInfo envInfo(bc().info(), bc().lastHashes());
ExecutionResult d = debugTransaction(t, _block.state(), envInfo, _call);
// execute on a state
if (!_call)
{
t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t;
eth::ExecutionResult er = _state.execute(lastHashes, t);
if (t.isCreation() && _state.code(d.contractAddress).empty())
eth::ExecutionResult const& er = _block.execute(envInfo.lastHashes(), t);
if (t.isCreation() && _block.state().code(d.contractAddress).empty())
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend;
LocalisedLogEntries logs;
TransactionReceipt const& tr = _state.receipt(_state.pending().size() - 1);
TransactionReceipt const& tr = _block.receipt(_block.pending().size() - 1);
//auto trHash = _state.pending().at(_state.pending().size() - 1).sha3();
LogEntries le = tr.log();
if (le.size())
for (unsigned j = 0; j < le.size(); ++j)
@ -281,15 +278,15 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
void MixClient::mine()
{
WriteGuard l(x_state);
m_state.commitToMine(bc());
m_postMine.commitToSeal(bc());
NoProof::BlockHeader h(m_state.info());
NoProof::BlockHeader h(m_postMine.info());
RLPStream header;
h.streamRLP(header);
m_state.sealBlock(header.out());
bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal);
m_state.sync(bc());
m_startState = m_state;
m_postMine.sealBlock(header.out());
bc().import(m_postMine.blockData(), m_stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal);
m_postMine.sync(bc());
m_preMine = m_postMine;
}
ExecutionResult MixClient::lastExecution() const
@ -304,10 +301,10 @@ ExecutionResult MixClient::execution(unsigned _index) const
return m_executions.at(_index);
}
State MixClient::asOf(h256 const& _block) const
Block MixClient::asOf(h256 const& _block) const
{
ReadGuard l(x_state);
State ret(m_stateDB);
Block ret(m_stateDB);
ret.populateFromChain(bc(), _block);
return ret;
}
@ -317,23 +314,23 @@ pair<h256, Address> MixClient::submitTransaction(eth::TransactionSkeleton const&
WriteGuard l(x_state);
TransactionSkeleton ts = _ts;
ts.from = toAddress(_secret);
ts.nonce = m_state.transactionsFrom(ts.from);
ts.nonce = m_postMine.transactionsFrom(ts.from);
eth::Transaction t(ts, _secret);
executeTransaction(t, m_state, false, _gasAuto, _secret);
executeTransaction(t, m_postMine, false, _gasAuto, _secret);
return make_pair(t.sha3(), toAddress(ts.from, ts.nonce));
}
dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff)
{
(void)_blockNumber;
State temp = asOf(eth::PendingBlock);
u256 n = temp.transactionsFrom(_from);
Block block = asOf(eth::PendingBlock);
u256 n = block.transactionsFrom(_from);
Transaction t(_value, _gasPrice, _gas, _dest, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
block.mutableState().addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
WriteGuard lw(x_state); //TODO: lock is required only for last execution state
executeTransaction(t, temp, true, _gasAuto);
executeTransaction(t, block, true, _gasAuto);
return lastExecution().result;
}
@ -346,7 +343,7 @@ dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, b
{
(void)_blockNumber;
u256 n;
State temp;
Block temp;
{
ReadGuard lr(x_state);
temp = asOf(eth::PendingBlock);
@ -355,7 +352,7 @@ dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, b
Transaction t(_value, _gasPrice, _gas, _data, n);
t.forceSender(_from);
if (_ff == FudgeFactor::Lenient)
temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
temp.mutableState().addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
WriteGuard lw(x_state); //TODO: lock is required only for last execution state
executeTransaction(t, temp, true, false);
return lastExecution().result;
@ -367,10 +364,10 @@ eth::BlockInfo MixClient::blockInfo() const
return BlockInfo(bc().block());
}
void MixClient::setAddress(Address _us)
void MixClient::setBeneficiary(Address _us)
{
WriteGuard l(x_state);
m_state.setAddress(_us);
m_postMine.setBeneficiary(_us);
}
void MixClient::startMining()

17
mix/MixClient.h

@ -33,6 +33,7 @@
namespace dev
{
namespace eth { class EnvInfo; }
namespace mix
{
@ -89,8 +90,8 @@ public:
virtual std::pair<h256, Address> submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret) override { return submitTransaction(_ts, _secret, false); }
std::pair<h256, Address> submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret, bool _gasAuto);
dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict);
ExecutionResult debugTransaction(dev::eth::Transaction const& _t, eth:: State const& _state, eth::LastHashes const& _lastHashes, bool _call);
void setAddress(Address _us) override;
ExecutionResult debugTransaction(dev::eth::Transaction const& _t, eth:: State const& _state, eth::EnvInfo const& _envInfo, bool _call);
void setBeneficiary(Address _us) override;
void startMining() override;
void stopMining() override;
bool isMining() const override;
@ -108,19 +109,19 @@ public:
protected:
/// ClientBase methods
using ClientBase::asOf;
virtual dev::eth::State asOf(h256 const& _block) const override;
virtual dev::eth::Block asOf(h256 const& _block) const override;
virtual dev::eth::BlockChain& bc() override { return *m_bc; }
virtual dev::eth::BlockChain const& bc() const override { return *m_bc; }
virtual dev::eth::State preMine() const override { ReadGuard l(x_state); return m_startState; }
virtual dev::eth::State postMine() const override { ReadGuard l(x_state); return m_state; }
virtual dev::eth::Block preMine() const override { ReadGuard l(x_state); return m_preMine; }
virtual dev::eth::Block postMine() const override { ReadGuard l(x_state); return m_postMine; }
virtual void prepareForTransaction() override {}
private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret = dev::Secret());
void executeTransaction(dev::eth::Transaction const& _t, eth::Block& _block, bool _call, bool _gasAuto, dev::Secret const& _secret = dev::Secret());
dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas, dev::Secret const& _secret = dev::Secret());
eth::State m_state;
eth::State m_startState;
eth::Block m_preMine;
eth::Block m_postMine;
OverlayDB m_stateDB;
std::unique_ptr<MixBlockChain> m_bc;
mutable boost::shared_mutex x_state;

128
test/TestHelper.cpp

@ -64,7 +64,7 @@ void connectClients(Client& c1, Client& c2)
void mine(State& s, BlockChain const& _bc)
{
std::unique_ptr<SealEngineFace> sealer(Ethash::createSealEngine());
s.commitToMine(_bc);
s.commitToSeal(_bc);
Notified<bytes> sealed;
sealer->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; });
sealer->generateSeal(s.info());
@ -97,7 +97,8 @@ bigint const c_max256plus1 = bigint(1) << 256;
ImportTest::ImportTest(json_spirit::mObject& _o, bool isFiller):
m_statePre(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())),
m_statePost(OverlayDB(), eth::BaseState::Empty, Address(_o["env"].get_obj()["currentCoinbase"].get_str())),
m_TestObject(_o)
m_environment(m_envInfo),
m_testObject(_o)
{
importEnv(_o["env"].get_obj());
importState(_o["pre"].get_obj(), m_statePre);
@ -144,99 +145,28 @@ void ImportTest::importEnv(json_spirit::mObject& _o)
assert(_o.count("currentTimestamp") > 0);
assert(_o.count("currentCoinbase") > 0);
assert(_o.count("currentNumber") > 0);
RLPStream rlpStream;
rlpStream.appendList(BlockInfo::BasicFields);
rlpStream << h256(_o["previousHash"].get_str());
rlpStream << EmptyListSHA3;
rlpStream << Address(_o["currentCoinbase"].get_str());
rlpStream << h256(); // stateRoot
rlpStream << EmptyTrie; // transactionTrie
rlpStream << EmptyTrie; // receiptTrie
rlpStream << LogBloom(); // bloom
rlpStream << toInt(_o["currentDifficulty"]);
rlpStream << toInt(_o["currentNumber"]);
rlpStream << toInt(_o["currentGasLimit"]);
rlpStream << 0; //gasUsed
rlpStream << toInt(_o["currentTimestamp"]);
rlpStream << std::string(); //extra data
m_environment.currentBlock = BlockInfo(rlpStream.out(), CheckEverything, h256{}, HeaderData);
m_statePre.m_previousBlock = m_environment.previousBlock;
m_statePre.m_currentBlock = m_environment.currentBlock;
m_envInfo.setBeneficiary(Address(_o["currentCoinbase"].get_str()));
m_envInfo.setDifficulty(toInt(_o["currentDifficulty"]));
m_envInfo.setNumber(toInt(_o["currentNumber"]));
m_envInfo.setGasLimit(toInt(_o["currentGasLimit"]));
m_envInfo.setTimestamp(toInt(_o["currentTimestamp"]));
}
// import state from not fully declared json_spirit::mObject, writing to _stateOptionsMap which fields were defined in json
void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptionsMap& _stateOptionsMap)
void ImportTest::importState(json_spirit::mObject& _o, State& _state, AccountMaskMap& o_mask)
{
for (auto& i: _o)
{
json_spirit::mObject o = i.second.get_obj();
ImportStateOptions stateOptions;
u256 balance = 0;
u256 nonce = 0;
if (o.count("balance") > 0)
{
stateOptions.m_bHasBalance = true;
if (bigint(o["balance"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") );
balance = toInt(o["balance"]);
}
if (o.count("nonce") > 0)
{
stateOptions.m_bHasNonce = true;
if (bigint(o["nonce"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") );
nonce = toInt(o["nonce"]);
}
Address address = Address(i.first);
bytes code;
if (o.count("code") > 0)
{
code = importCode(o);
stateOptions.m_bHasCode = true;
}
if (!code.empty())
{
_state.m_cache[address] = Account(balance, Account::ContractConception);
_state.m_cache[address].setCode(std::move(code));
}
else
_state.m_cache[address] = Account(balance, Account::NormalCreation);
if (o.count("storage") > 0)
{
stateOptions.m_bHasStorage = true;
for (auto const& j: o["storage"].get_obj())
_state.setStorage(address, toInt(j.first), toInt(j.second));
}
for (int i = 0; i < nonce; ++i)
_state.noteSending(address);
_state.ensureCached(address, false, false);
_stateOptionsMap[address] = stateOptions;
}
_state.populateFrom(jsonToAccountMap(json_spirit::write_string(_o, false), &o_mask));
}
void ImportTest::importState(json_spirit::mObject& _o, State& _state)
{
stateOptionsMap importedMap;
importState(_o, _state, importedMap);
for (auto& stateOptionMap : importedMap)
{
AccountMaskMap mask;
importState(_o, _state, mask);
for (auto const& i: mask)
//check that every parameter was declared in state object
if (!stateOptionMap.second.isAllSet())
if (!i.second.allSet())
BOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!"));
}
}
void ImportTest::importTransaction(json_spirit::mObject& _o)
@ -347,41 +277,41 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost)
{
// export output
m_TestObject["out"] = (_output.size() > 4096 && !Options::get().fulloutput) ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add);
m_testObject["out"] = (_output.size() > 4096 && !Options::get().fulloutput) ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add);
// compare expected output with post output
if (m_TestObject.count("expectOut") > 0)
if (m_testObject.count("expectOut") > 0)
{
std::string warning = "Check State: Error! Unexpected output: " + m_TestObject["out"].get_str() + " Expected: " + m_TestObject["expectOut"].get_str();
std::string warning = "Check State: Error! Unexpected output: " + m_testObject["out"].get_str() + " Expected: " + m_testObject["expectOut"].get_str();
if (Options::get().checkState)
{TBOOST_CHECK_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning);}
{TBOOST_CHECK_MESSAGE((m_testObject["out"].get_str() == m_testObject["expectOut"].get_str()), warning);}
else
TBOOST_WARN_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning);
TBOOST_WARN_MESSAGE((m_testObject["out"].get_str() == m_testObject["expectOut"].get_str()), warning);
m_TestObject.erase(m_TestObject.find("expectOut"));
m_testObject.erase(m_testObject.find("expectOut"));
}
// export logs
m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries());
m_testObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries());
// compare expected state with post state
if (m_TestObject.count("expect") > 0)
if (m_testObject.count("expect") > 0)
{
stateOptionsMap stateMap;
State expectState(OverlayDB(), eth::BaseState::Empty);
importState(m_TestObject["expect"].get_obj(), expectState, stateMap);
importState(m_testObject["expect"].get_obj(), expectState, stateMap);
checkExpectedState(expectState, _statePost, stateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow);
m_TestObject.erase(m_TestObject.find("expect"));
m_testObject.erase(m_testObject.find("expect"));
}
// export post state
m_TestObject["post"] = fillJsonWithState(_statePost);
m_TestObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes());
m_testObject["post"] = fillJsonWithState(_statePost);
m_testObject["postStateRoot"] = toHex(_statePost.rootHash().asBytes());
// export pre state
m_TestObject["pre"] = fillJsonWithState(m_statePre);
m_TestObject["env"] = makeAllFieldsHex(m_TestObject["env"].get_obj());
m_TestObject["transaction"] = makeAllFieldsHex(m_TestObject["transaction"].get_obj());
m_testObject["pre"] = fillJsonWithState(m_statePre);
m_testObject["env"] = makeAllFieldsHex(m_testObject["env"].get_obj());
m_testObject["transaction"] = makeAllFieldsHex(m_testObject["transaction"].get_obj());
}
json_spirit::mObject fillJsonWithTransaction(Transaction _txn)

21
test/TestHelper.h

@ -122,26 +122,16 @@ namespace test
} \
while (0)
struct ImportStateOptions
{
ImportStateOptions(bool _bSetAll = false):m_bHasBalance(_bSetAll), m_bHasNonce(_bSetAll), m_bHasCode(_bSetAll), m_bHasStorage(_bSetAll) {}
bool isAllSet() {return m_bHasBalance && m_bHasNonce && m_bHasCode && m_bHasStorage;}
bool m_bHasBalance;
bool m_bHasNonce;
bool m_bHasCode;
bool m_bHasStorage;
};
typedef std::map<Address, ImportStateOptions> stateOptionsMap;
class ImportTest
{
public:
ImportTest(json_spirit::mObject& _o): m_TestObject(_o) {}
ImportTest(json_spirit::mObject& _o): m_environment(m_envInfo), m_testObject(_o) {}
ImportTest(json_spirit::mObject& _o, bool isFiller);
// imports
void importEnv(json_spirit::mObject& _o);
static void importState(json_spirit::mObject& _o, eth::State& _state);
static void importState(json_spirit::mObject& _o, eth::State& _state, stateOptionsMap& _stateOptionsMap);
static void importState(json_spirit::mObject& _o, eth::State& _state, eth::AccountMaskMap& o_mask);
void importTransaction(json_spirit::mObject& _o);
static json_spirit::mObject& makeAllFieldsHex(json_spirit::mObject& _o);
@ -150,17 +140,18 @@ public:
eth::State m_statePre;
eth::State m_statePost;
eth::EnvInfo m_envInfo;
eth::ExtVMFace m_environment;
eth::Transaction m_transaction;
private:
json_spirit::mObject& m_TestObject;
json_spirit::mObject& m_testObject;
};
class ZeroGasPricer: public eth::GasPricer
{
protected:
u256 ask(eth::State const&) const override { return 0; }
u256 ask(eth::Block const&) const override { return 0; }
u256 bid(eth::TransactionPriority = eth::TransactionPriority::Medium) const override { return 0; }
};

2
test/libethereum/ClientBase.cpp

@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(blocks)
h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString()));
h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString()));
ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom());
ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress());
ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.beneficiary());
ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty());
ETH_CHECK_EQUAL_COLLECTIONS(
expectedBlockInfoExtraData.begin(),

20
test/libethereum/blockchain.cpp

@ -68,7 +68,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
ImportTest importer(o["pre"].get_obj());
TransientDirectory td_stateDB_tmp;
BlockHeader biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj(), h256{});
State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path(), h256{}, WithExisting::Kill)), BaseState::Empty, biGenesisBlock.coinbaseAddress());
State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path(), h256{}, WithExisting::Kill)), BaseState::Empty, biGenesisBlock.beneficiary());
//Imported blocks from the start
std::vector<blockSet> blockSets;
@ -98,7 +98,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
// construct true blockchain
TransientDirectory td;
FullBlockChain<Ethash> trueBc(rlpGenesisBlock.out(), StateDefinition(), td.path(), WithExisting::Kill);
FullBlockChain<Ethash> trueBc(rlpGenesisBlock.out(), AccountMap(), td.path(), WithExisting::Kill);
if (_fillin)
{
@ -126,9 +126,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
vBiBlocks.push_back(biGenesisBlock);
TransientDirectory td_stateDB, td_bc;
FullBlockChain<Ethash> bc(rlpGenesisBlock.out(), StateDefinition(), td_bc.path(), WithExisting::Kill);
FullBlockChain<Ethash> bc(rlpGenesisBlock.out(), AccountMap(), td_bc.path(), WithExisting::Kill);
State state(OverlayDB(State::openDB(td_stateDB.path(), h256{}, WithExisting::Kill)), BaseState::Empty);
state.setAddress(biGenesisBlock.coinbaseAddress());
state.setAddress(biGenesisBlock.beneficiary());
importer.importState(o["pre"].get_obj(), state);
state.commit();
state.sync(bc);
@ -184,7 +184,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
}
}
bc.sync(uncleBlockQueue, state.db(), 4);
state.commitToMine(bc);
state.commitToSeal(bc);
try
{
@ -308,7 +308,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
if (o.count("expect") > 0)
{
stateOptionsMap expectStateMap;
State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress());
State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.beneficiary());
importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap);
ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow);
o.erase(o.find("expect"));
@ -319,7 +319,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
o["lastblockhash"] = toString(trueBc.info().hash());
//make all values hex in pre section
State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress());
State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.beneficiary());
importer.importState(o["pre"].get_obj(), prestate);
o["pre"] = fillJsonWithState(prestate);
}//_fillin
@ -382,7 +382,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithProof) == blockFromRlp.headerHash(WithProof)), "hash in given RLP not matching the block hash!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.beneficiary() == blockFromRlp.beneficiary()),"beneficiary in given RLP not matching the block beneficiary!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!");
TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!");
@ -574,7 +574,7 @@ mArray importUncles(mObject const& _blObj, vector<BlockHeader>& _vBiUncles, vect
uncleBlockFromFields = constructHeader(
overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(),
uncleBlockFromFields.sha3Uncles(),
uncleBlockFromFields.coinbaseAddress(),
uncleBlockFromFields.beneficiary(),
overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(),
uncleBlockFromFields.transactionsRoot(),
uncleBlockFromFields.receiptsRoot(),
@ -759,7 +759,7 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockHeader const& _bi)
{
_o["parentHash"] = toString(_bi.parentHash());
_o["uncleHash"] = toString(_bi.sha3Uncles());
_o["coinbase"] = toString(_bi.coinbaseAddress());
_o["coinbase"] = toString(_bi.beneficiary());
_o["stateRoot"] = toString(_bi.stateRoot());
_o["transactionsTrie"] = toString(_bi.transactionsRoot());
_o["receiptTrie"] = toString(_bi.receiptsRoot());

2
test/libethereum/gaspricer.cpp

@ -56,7 +56,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer)
std::shared_ptr<dev::eth::GasPricer> gp(new TrivialGasPricer);
BOOST_CHECK_EQUAL(gp->ask(State()), c_defaultGasPrice);
BOOST_CHECK_EQUAL(gp->bid(), c_defaultGasPrice);
gp->update(CanonBlockChain<Ethash>(TransientDirectory().path(), WithExisting::Kill));
gp->update(CanonBlockChain<Ethash>(bytes(), AccountMap(), TransientDirectory().path(), WithExisting::Kill));
BOOST_CHECK_EQUAL(gp->ask(State()), c_defaultGasPrice);
BOOST_CHECK_EQUAL(gp->bid(), c_defaultGasPrice);
}

12
test/libethereum/stateOriginal.cpp

@ -23,7 +23,7 @@
#include <boost/test/unit_test.hpp>
#include <boost/filesystem/operations.hpp>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/State.h>
#include <libethereum/Block.h>
#include <libethcore/Farm.h>
#include <libethcore/BasicAuthority.h>
#include <libethereum/Defaults.h>
@ -44,7 +44,7 @@ BOOST_AUTO_TEST_SUITE(StateIntegration)
BOOST_AUTO_TEST_CASE(Basic)
{
State s;
Block s;
}
BOOST_AUTO_TEST_CASE(Complex)
@ -64,8 +64,8 @@ BOOST_AUTO_TEST_CASE(Complex)
CanonBlockChain<BasicAuthority> bc;
cout << bc;
State s = bc.genesisState(stateDB);
s.setAddress(myMiner.address());
Block s = bc.genesisBlock(stateDB);
s.setBeneficiary(myMiner.address());
cout << s;
// Sync up - this won't do much until we use the last state.
@ -92,8 +92,8 @@ BOOST_AUTO_TEST_CASE(Complex)
cout << s;
// Mine to get some ether and set in stone.
s.commitToMine(bc);
s.commitToMine(bc);
s.commitToSeal(bc);
s.commitToSeal(bc);
mine(s, bc);
bc.attemptImport(s.blockData(), stateDB);

2
test/libevm/vm.cpp

@ -86,7 +86,7 @@ mObject FakeExtVM::exportEnv()
ret["previousHash"] = toString(currentBlock.parentHash());
ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1);
ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1);
ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress());
ret["currentCoinbase"] = toString(currentBlock.beneficiary());
ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1);
ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1);
return ret;

2
test/libsolidity/solidityExecutionFramework.h

@ -185,7 +185,7 @@ protected:
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0)
{
m_state.addBalance(m_sender, _value); // just in case
eth::Executive executive(m_state, eth::LastHashes(), 0);
eth::Executive executive(m_state, eth::EnvInfo(), 0);
eth::ExecutionResult res;
executive.setResultRecipient(res);
eth::Transaction t =

6
test/libweb3jsonrpc/jsonrpc.cpp

@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(jsonrpc_transact)
dev::KeyPair key = KeyPair::create();
auto address = key.address();
auto receiver = KeyPair::create();
web3->ethereum()->setAddress(address);
web3->ethereum()->setBeneficiary(address);
coinbase = jsonrpcClient->eth_coinbase();
BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address());
@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(simple_contract)
{
cnote << "Testing jsonrpc contract...";
KeyPair kp = KeyPair::create();
web3->ethereum()->setAddress(kp.address());
web3->ethereum()->setBeneficiary(kp.address());
jsonrpcServer->setAccounts({kp});
dev::eth::mine(*(web3->ethereum()), 1);
@ -279,7 +279,7 @@ BOOST_AUTO_TEST_CASE(contract_storage)
{
cnote << "Testing jsonrpc contract storage...";
KeyPair kp = KeyPair::create();
web3->ethereum()->setAddress(kp.address());
web3->ethereum()->setBeneficiary(kp.address());
jsonrpcServer->setAccounts({kp});
dev::eth::mine(*(web3->ethereum()), 1);

4
third/MainWin.cpp

@ -415,7 +415,7 @@ void Main::readSettings(bool _skipGeometry)
m_myKeys.append(KeyPair(k));
}
}
ethereum()->setAddress(m_myKeys.back().address());
ethereum()->setBeneficiary(m_myKeys.back().address());
m_networkConfig = s.value("peers").toByteArray();
ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html
on_urlEdit_returnPressed();
@ -609,7 +609,7 @@ void Main::on_mine_triggered()
{
if (ui->mine->isChecked())
{
ethereum()->setAddress(m_myKeys.last().address());
ethereum()->setBeneficiary(m_myKeys.last().address());
ethereum()->startMining();
}
else

Loading…
Cancel
Save