Browse Source

Merge branch 'develop' into reqpeer

Conflicts:
	libp2p/Network.cpp
cl-refactor
subtly 10 years ago
parent
commit
fb39490d66
  1. 3
      alethzero/Debugger.cpp
  2. 6
      alethzero/MainWin.cpp
  3. 4
      alethzero/Transact.cpp
  4. 7
      eth/main.cpp
  5. 52
      libethereum/BlockChain.cpp
  6. 47
      libethereum/BlockChain.h
  7. 2
      libethereum/Client.h
  8. 4
      libethereum/ClientBase.cpp
  9. 2
      libethereum/EthereumHost.cpp
  10. 78
      libethereum/Executive.cpp
  11. 41
      libethereum/Executive.h
  12. 6
      libethereum/Interface.h
  13. 74
      libethereum/State.cpp
  14. 8
      libethereum/State.h
  15. 10
      libethereum/TransactionQueue.cpp
  16. 11
      libethereum/TransactionQueue.h
  17. 22
      libp2p/Network.cpp
  18. 5
      mix/MixClient.cpp
  19. 21
      test/blockchain.cpp
  20. 3
      test/checkRandomStateTest.cpp
  21. 3
      test/createRandomStateTest.cpp
  22. 3
      test/solidityExecutionFramework.h
  23. 3
      test/state.cpp
  24. 10
      test/stateOriginal.cpp

3
alethzero/Debugger.cpp

@ -67,7 +67,8 @@ void Debugger::populate(dev::eth::Executive& _executive, dev::eth::Transaction c
bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction)
{
try {
if (_executive.setup(_transaction))
_executive.initialize(_transaction);
if (_executive.execute())
return false;
}
catch (...)

6
alethzero/MainWin.cpp

@ -1122,7 +1122,7 @@ void Main::refreshBlockChain()
blocks.insert(bc.numberHash(b));
}
else if (f.toLongLong() <= bc.number())
blocks.insert(bc.numberHash(u256(f.toLongLong())));
blocks.insert(bc.numberHash((unsigned)f.toLongLong()));
else if (f.size() == 40)
{
Address h(f.toStdString());
@ -1385,7 +1385,7 @@ void Main::on_transactionQueue_currentItemChanged()
if (!!receipt.bloom())
s << "<div>Log Bloom: " << receipt.bloom() << "</div>";
else
s << "<div>Log Bloom: <i>Uneventful</i></div>";
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "</span></div>";
@ -1484,7 +1484,7 @@ void Main::on_blocks_currentItemChanged()
if (!!info.logBloom)
s << "<div>Log Bloom: " << info.logBloom << "</div>";
else
s << "<div>Log Bloom: <i>Uneventful</i></div>";
s << "<div>Log Bloom: <b><i>Uneventful</i></b></div>";
s << "<div>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>" << "</div>";
s << "<div>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>" << "</div>";
for (auto u: block[2])

4
alethzero/Transact.cpp

@ -316,7 +316,7 @@ void Transact::rejigData()
return;
}
else
gasNeeded = min<qint64>((qint64)ethereum()->gasLimitRemaining(), (qint64)((b - value()) / gasPrice()));
gasNeeded = (qint64)min<bigint>(ethereum()->gasLimitRemaining(), ((b - value()) / gasPrice()));
// Dry-run execution to determine gas requirement and any execution errors
Address to;
@ -326,7 +326,7 @@ void Transact::rejigData()
else
{
to = m_context->fromString(ui->destination->currentText());
er = ethereum()->call(s, value(), to, m_data, ethereum()->gasLimitRemaining(), gasPrice());
er = ethereum()->call(s, value(), to, m_data, gasNeeded, gasPrice());
}
gasNeeded = (qint64)(er.gasUsed + er.gasRefunded);
htmlInfo = QString("<div class=\"info\"><span class=\"icon\">INFO</span> Gas required: %1 total = %2 base, %3 exec [%4 refunded later]</div>").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo;

7
eth/main.cpp

@ -835,11 +835,8 @@ int main(int argc, char** argv)
Executive e(state, c->blockChain(), 0);
Transaction t = state.pending()[index];
state = state.fromPending(index);
bytes r = t.rlp();
try
{
e.setup(&r);
OnOpFunc oof;
if (format == "pretty")
oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
@ -872,7 +869,9 @@ int main(int argc, char** argv)
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)vm->gas(), 1)) << endl;
};
e.go(oof);
e.initialize(t);
if (!e.execute())
e.go(oof);
e.finalize();
}
catch(Exception const& _e)

52
libethereum/BlockChain.cpp

@ -63,7 +63,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
return _out;
}
ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub)
ldb::Slice dev::eth::toSlice(h256 const& _h, unsigned _sub)
{
#if ALL_COMPILERS_ARE_CPP11_COMPLIANT
static thread_local h256 h = _h ^ sha3(h256(u256(_sub)));
@ -184,6 +184,19 @@ inline string toString(h256s const& _bs)
return out.str();
}
LastHashes BlockChain::lastHashes(unsigned _n) const
{
Guard l(x_lastLastHashes);
if (m_lastLastHashesNumber != _n || m_lastLastHashes.empty())
{
m_lastLastHashes.resize(256);
for (unsigned i = 0; i < 256; ++i)
m_lastLastHashes[i] = _n >= i ? numberHash(_n - i) : h256();
m_lastLastHashesNumber = _n;
}
return m_lastLastHashes;
}
h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{
_bq.tick(*this);
@ -412,6 +425,9 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
WriteGuard l(x_lastBlockHash);
m_lastBlockHash = newHash;
}
noteCanonChanged();
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(ret);
StructuredLogger::chainNewHead(
@ -428,7 +444,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
return ret;
}
h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, bool _post) const
h256s BlockChain::treeRoute(h256 const& _from, h256 const& _to, h256* o_common, bool _pre, bool _post) const
{
// cdebug << "treeRoute" << _from.abridged() << "..." << _to.abridged();
if (!_from || !_to)
@ -438,38 +454,40 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo
unsigned fn = details(_from).number;
unsigned tn = details(_to).number;
// cdebug << "treeRoute" << fn << "..." << tn;
h256 from = _from;
while (fn > tn)
{
if (_pre)
ret.push_back(_from);
_from = details(_from).parent;
ret.push_back(from);
from = details(from).parent;
fn--;
// cdebug << "from:" << fn << _from.abridged();
}
h256 to = _to;
while (fn < tn)
{
if (_post)
back.push_back(_to);
_to = details(_to).parent;
back.push_back(to);
to = details(to).parent;
tn--;
// cdebug << "to:" << tn << _to.abridged();
}
while (_from != _to)
while (from != to)
{
assert(_from);
assert(_to);
_from = details(_from).parent;
_to = details(_to).parent;
assert(from);
assert(to);
from = details(from).parent;
to = details(to).parent;
if (_pre)
ret.push_back(_from);
ret.push_back(from);
if (_post)
back.push_back(_to);
back.push_back(to);
fn--;
tn--;
// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged();
}
if (o_common)
*o_common = _from;
*o_common = from;
ret.reserve(ret.size() + back.size());
for (auto it = back.cbegin(); it != back.cend(); ++it)
ret.push_back(*it);
@ -677,7 +695,7 @@ vector<unsigned> BlockChain::withBlockBloom(LogBloom const& _b, unsigned _earlie
return ret;
}
h256Set BlockChain::allUnclesFrom(h256 _parent) const
h256Set BlockChain::allUnclesFrom(h256 const& _parent) const
{
// Get all uncles cited given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
h256Set ret;
@ -692,7 +710,7 @@ h256Set BlockChain::allUnclesFrom(h256 _parent) const
return ret;
}
bool BlockChain::isKnown(h256 _hash) const
bool BlockChain::isKnown(h256 const& _hash) const
{
if (_hash == m_genesisHash)
return true;
@ -706,7 +724,7 @@ bool BlockChain::isKnown(h256 _hash) const
return !!d.size();
}
bytes BlockChain::block(h256 _hash) const
bytes BlockChain::block(h256 const& _hash) const
{
if (_hash == m_genesisHash)
return m_genesisBlock;

47
libethereum/BlockChain.h

@ -30,9 +30,10 @@
#include <chrono>
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/Guards.h>
#include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
#include <libdevcore/Guards.h>
#include <libevm/ExtVMFace.h>
#include "BlockDetails.h"
#include "Account.h"
#include "Transaction.h"
@ -61,7 +62,7 @@ struct BlockChainNote: public LogChannel { static const char* name() { return "=
// TODO: Move all this Genesis stuff into Genesis.h/.cpp
std::map<Address, Account> const& genesisState();
ldb::Slice toSlice(h256 _h, unsigned _sub = 0);
ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0);
using BlocksHash = std::map<h256, bytes>;
using TransactionHashes = h256s;
@ -105,37 +106,42 @@ public:
h256s import(bytes const& _block, OverlayDB const& _stateDB);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 _hash) const;
bool isKnown(h256 const& _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockInfo info(h256 _hash) const { return BlockInfo(block(_hash)); }
BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash)); }
BlockInfo info() const { return BlockInfo(block()); }
/// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe.
bytes block(h256 _hash) const;
bytes block(h256 const& _hash) const;
bytes block() const { return block(currentHash()); }
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
BlockDetails details(h256 _hash) const { return queryExtras<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details(h256 const& _hash) const { return queryExtras<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
BlockDetails details() const { return details(currentHash()); }
/// Get the transactions' log blooms of a block (or the most recent mined if none given). Thread-safe.
BlockLogBlooms logBlooms(h256 _hash) const { return queryExtras<BlockLogBlooms, ExtraLogBlooms>(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); }
BlockLogBlooms logBlooms(h256 const& _hash) const { return queryExtras<BlockLogBlooms, ExtraLogBlooms>(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); }
BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); }
/// Get the transactions' receipts of a block (or the most recent mined if none given). Thread-safe.
BlockReceipts receipts(h256 _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); }
BlockReceipts receipts(h256 const& _hash) const { return queryExtras<BlockReceipts, ExtraReceipts>(_hash, m_receipts, x_receipts, NullBlockReceipts); }
BlockReceipts receipts() const { return receipts(currentHash()); }
/// Get a list of transaction hashes for a given block. Thread-safe.
TransactionHashes transactionHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }
TransactionHashes transactionHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; }
TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); }
/// Get a list of uncle hashes for a given block. Thread-safe.
UncleHashes uncleHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[2]) ret.push_back(sha3(t.data())); return ret; }
UncleHashes uncleHashes(h256 const& _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[2]) ret.push_back(sha3(t.data())); return ret; }
UncleHashes uncleHashes() const { return uncleHashes(currentHash()); }
h256 numberHash(u256 _index) const { if (!_index) return genesisHash(); return queryExtras<BlockHash, ExtraBlockHash>(h256(_index), m_blockHashes, x_blockHashes, NullBlockHash).value; }
/// Get the hash for a given block's number.
h256 numberHash(unsigned _i) const { if (!_i) return genesisHash(); return queryExtras<BlockHash, ExtraBlockHash>(h256(u256(_i)), m_blockHashes, x_blockHashes, NullBlockHash).value; }
/// Get the last N hashes for a given block. (N is determined by the LastHashes type.)
LastHashes lastHashes() const { return lastHashes(number()); }
LastHashes lastHashes(unsigned _i) const;
/** Get the block blooms for a number of blocks. Thread-safe.
* @returns the object pertaining to the blocks:
@ -158,15 +164,15 @@ public:
std::vector<unsigned> withBlockBloom(LogBloom const& _b, unsigned _earliest, unsigned _latest, unsigned _topLevel, unsigned _index) const;
/// Get a transaction from its hash. Thread-safe.
bytes transaction(h256 _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); }
std::pair<h256, unsigned> transactionLocation(h256 _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return std::pair<h256, unsigned>(h256(), 0); return std::make_pair(ta.blockHash, ta.index); }
bytes transaction(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); }
std::pair<h256, unsigned> transactionLocation(h256 const& _transactionHash) const { TransactionAddress ta = queryExtras<TransactionAddress, ExtraTransactionAddress>(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return std::pair<h256, unsigned>(h256(), 0); return std::make_pair(ta.blockHash, ta.index); }
/// Get a block's transaction (RLP format) for the given block hash (or the most recent mined if none given) & index. Thread-safe.
bytes transaction(h256 _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); }
bytes transaction(h256 const& _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); }
bytes transaction(unsigned _i) const { return transaction(currentHash(), _i); }
/// Get a number for the given hash (or the most recent mined if none given). Thread-safe.
unsigned number(h256 _hash) const { return details(_hash).number; }
unsigned number(h256 const& _hash) const { return details(_hash).number; }
unsigned number() const { return number(currentHash()); }
/// Get a given block (RLP format). Thread-safe.
@ -178,7 +184,7 @@ public:
/// Get all blocks not allowed as uncles given a parent (i.e. featured as uncles/main in parent, parent + 1, ... parent + 5).
/// @returns set including the header-hash of every parent (including @a _parent) up to and including generation +5
/// togther with all their quoted uncles.
h256Set allUnclesFrom(h256 _parent) const;
h256Set allUnclesFrom(h256 const& _parent) const;
/** @returns the hash of all blocks between @a _from and @a _to, all blocks are ordered first by a number of
* blocks that are parent-to-child, then two sibling blocks, then a number of blocks that are child-to-parent.
@ -194,7 +200,7 @@ public:
* treeRoute(1b, 2a) == { 1b, 1a, 2a }; // *o_common == g
* @endcode
*/
h256s treeRoute(h256 _from, h256 _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
h256s treeRoute(h256 const& _from, h256 const& _to, h256* o_common = nullptr, bool _pre = true, bool _post = true) const;
struct Statistics
{
@ -219,7 +225,7 @@ private:
void open(std::string _path, bool _killExisting = false);
void close();
template<class T, unsigned N> T queryExtras(h256 _h, std::map<h256, T>& _m, boost::shared_mutex& _x, T const& _n) const
template<class T, unsigned N> T queryExtras(h256 const& _h, std::map<h256, T>& _m, boost::shared_mutex& _x, T const& _n) const
{
{
ReadGuard l(_x);
@ -268,6 +274,11 @@ private:
void noteUsed(h256 const& _h, unsigned _extra = (unsigned)-1) const;
std::chrono::system_clock::time_point m_lastCollection;
void noteCanonChanged() const { Guard l(x_lastLastHashes); m_lastLastHashes.clear(); }
mutable Mutex x_lastLastHashes;
mutable LastHashes m_lastLastHashes;
mutable unsigned m_lastLastHashesNumber = (unsigned)-1;
void updateStats() const;
mutable Statistics m_lastStats;

2
libethereum/Client.h

@ -110,7 +110,7 @@ public:
private:
u256 m_weiPerRef;
u256 m_refsPerBlock;
u256 m_gasPerBlock = 1000000;
u256 m_gasPerBlock = 3141592;
std::array<u256, 9> m_octiles;
};

4
libethereum/ClientBase.cpp

@ -73,7 +73,7 @@ ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, byt
State temp = asOf(_blockNumber);
u256 n = temp.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
ret = temp.execute(bc(), t.rlp(), Permanence::Reverted);
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
{
@ -92,7 +92,7 @@ ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _da
// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _data, n, _secret);
ret = temp.execute(bc(), t.rlp(), Permanence::Reverted);
ret = temp.execute(bc().lastHashes(), t, Permanence::Reverted);
}
catch (...)
{

2
libethereum/EthereumHost.cpp

@ -178,7 +178,7 @@ void EthereumHost::maintainTransactions()
for (auto const& i: m_tq.transactions())
if (ep->m_requireTransactions || (!m_transactionsSent.count(i.first) && !ep->m_knownTransactions.count(i.first)))
{
b += i.second;
b += i.second.rlp();
++n;
m_transactionsSent.insert(i.first);
}

78
libethereum/Executive.cpp

@ -35,7 +35,7 @@ using namespace dev::eth;
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
m_s(_s),
m_lastHashes(_s.getLastHashes(_bc, (unsigned)_s.info().number - 1)),
m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)),
m_depth(_level)
{}
@ -55,12 +55,33 @@ void Executive::accrueSubState(SubState& _parentContext)
_parentContext += m_ext->sub;
}
bool Executive::setup(bytesConstRef _rlp)
void Executive::initialize(Transaction const& _transaction)
{
// Entry point for a user-executed 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)
{
clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.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()));
}
// Check gas cost is enough.
m_gasRequired = Interface::txGas(m_t.data());
if (m_t.gas() < m_gasRequired)
{
clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << m_gasRequired << " Got" << m_t.gas();
m_excepted = TransactionException::OutOfGas;
BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)m_gasRequired, (bigint)m_t.gas()));
}
// Avoid invalid transactions.
u256 nonceReq;
try
{
m_t = Transaction(_rlp, CheckSignature::Sender);
nonceReq = m_s.transactionsFrom(m_t.sender());
}
catch (...)
{
@ -68,15 +89,6 @@ bool Executive::setup(bytesConstRef _rlp)
m_excepted = TransactionException::InvalidSignature;
throw;
}
return setup();
}
bool Executive::setup()
{
// Entry point for a user-executed transaction.
// Avoid invalid transactions.
auto nonceReq = m_s.transactionsFrom(m_t.sender());
if (m_t.nonce() != nonceReq)
{
clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce();
@ -84,46 +96,32 @@ bool Executive::setup()
BOOST_THROW_EXCEPTION(InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce()));
}
// Check gas cost is enough.
auto gasRequired = Interface::txGas(m_t.data());
if (m_t.gas() < gasRequired)
{
clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasRequired << " Got" << m_t.gas();
m_excepted = TransactionException::OutOfGas;
BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)gasRequired, (bigint)m_t.gas()));
}
bigint gasCost = (bigint)m_t.gas() * m_t.gasPrice();
bigint totalCost = m_t.value() + gasCost;
// Avoid unaffordable transactions.
if (m_s.balance(m_t.sender()) < totalCost)
m_gasCost = (bigint)m_t.gas() * m_t.gasPrice();
m_totalCost = m_t.value() + m_gasCost;
if (m_s.balance(m_t.sender()) < m_totalCost)
{
clog(StateDetail) << "Not enough cash: Require >" << totalCost << " Got" << m_s.balance(m_t.sender());
clog(StateDetail) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender());
m_excepted = TransactionException::NotEnoughCash;
BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(totalCost, (bigint)m_s.balance(m_t.sender())));
BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(m_totalCost, (bigint)m_s.balance(m_t.sender())));
}
}
u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit)
{
clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.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()));
}
bool Executive::execute()
{
// Entry point for a user-executed transaction.
// Increment associated nonce for sender.
m_s.noteSending(m_t.sender());
// Pay...
clog(StateDetail) << "Paying" << formatBalance(u256(gasCost)) << "from sender for gas (" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
m_s.subBalance(m_t.sender(), gasCost);
clog(StateDetail) << "Paying" << formatBalance(u256(m_gasCost)) << "from sender for gas (" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
m_s.subBalance(m_t.sender(), m_gasCost);
if (m_t.isCreation())
return create(m_t.sender(), m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)gasRequired, &m_t.data(), m_t.sender());
return create(m_t.sender(), m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)m_gasRequired, &m_t.data(), m_t.sender());
else
return call(m_t.receiveAddress(), m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)gasRequired, m_t.sender());
return call(m_t.receiveAddress(), m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)m_gasRequired, m_t.sender());
}
bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress)

41
libethereum/Executive.h

@ -41,10 +41,21 @@ struct VMTraceChannel: public LogChannel { static const char* name() { return "E
* @brief Message-call/contract-creation executor; useful for executing transactions.
*
* Two ways of using this class - either as a transaction executive or a CALL/CREATE executive.
* In the first use, after construction, begin with setup() and end with finalize(). Call go()
* after setup() only if it returns false.
*
* In the first use, after construction, begin with initialize(), then execute() and end with finalize(). Call go()
* after execute() only if it returns false.
*
* In the second use, after construction, begin with call() or create() and end with
* accrueSubState(). Call go() after call()/create() only if it returns false.
*
* Example:
* @code
* Executive e(state, blockchain, 0);
* e.initialize(transaction);
* if (!e.execute())
* e.go();
* e.finalize();
* @endcode
*/
class Executive
{
@ -59,17 +70,17 @@ public:
Executive(Executive const&) = delete;
void operator=(Executive) = delete;
/// Set up the executive for evaluating a transaction. You must call finalize() following this.
/// @returns true iff go() must be called (and thus a VM execution in required).
bool setup(bytesConstRef _transaction);
/// Set up the executive for evaluating a transaction. You must call finalize() following this.
/// @returns true iff go() must be called (and thus a VM execution in required).
bool setup(Transaction const& _transaction) { m_t = _transaction; return setup(); }
/// Finalise a transaction previously set up with setup().
/// @warning Only valid after setup(), and possibly go().
/// Initializes the executive for evaluating a transaction. You must call finalize() at some point following this.
void initialize(bytesConstRef _transaction) { initialize(Transaction(_transaction, CheckSignature::None)); }
void initialize(Transaction const& _transaction);
/// Finalise a transaction previously set up with initialize().
/// @warning Only valid after initialize() and execute(), and possibly go().
void finalize();
/// @returns the transaction from setup().
/// @warning Only valid after setup().
/// Begins execution of a transaction. You must call finalize() following this.
/// @returns true if the transaction is done, false if go() must be called.
bool execute();
/// @returns the transaction from initialize().
/// @warning Only valid after initialize().
Transaction const& t() const { return m_t; }
/// @returns the log entries created by this operation.
/// @warning Only valid after finalise().
@ -107,8 +118,6 @@ public:
ExecutionResult executionResult() const;
private:
bool setup();
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.
@ -125,6 +134,10 @@ private:
Transaction m_t; ///< The original transaction. Set by setup().
LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize().
bigint m_gasRequired;
bigint m_gasCost;
bigint m_totalCost;
};
}

6
libethereum/Interface.h

@ -71,11 +71,13 @@ public:
virtual void flushTransactions() = 0;
/// Makes the given call. Nothing is recorded into the state.
virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = 0) = 0;
virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) = 0;
ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) { return call(_secret, _value, _dest, _data, _gas, _gasPrice, m_default); }
/// Does the given creation. Nothing is recorded into the state.
/// @returns the pair of the Address of the created contract together with its code.
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = 0) = 0;
virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) = 0;
ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) { return create(_secret, _value, _data, _gas, _gasPrice, m_default); }
// [STATE-QUERY API]

74
libethereum/State.cpp

@ -388,8 +388,7 @@ bool State::cull(TransactionQueue& _tq) const
{
try
{
Transaction t(i.second, CheckSignature::Sender);
if (t.nonce() <= transactionsFrom(t.sender()))
if (i.second.nonce() <= transactionsFrom(i.second.sender()))
{
_tq.drop(i.first);
ret = true;
@ -411,7 +410,7 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
TransactionReceipts ret;
auto ts = _tq.transactions();
auto lh = getLastHashes(_bc, _bc.number());
LastHashes lh;
for (int goodTxs = 1; goodTxs;)
{
@ -421,12 +420,11 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
{
try
{
if (Transaction(i.second, CheckSignature::Range).gasPrice() >= _gp.ask(*this))
if (i.second.gasPrice() >= _gp.ask(*this))
{
Transaction t(i.second, CheckSignature::Sender);
// don't have it yet! Execute it now.
uncommitToMine();
// boost::timer t;
if (lh.empty())
lh = _bc.lastHashes();
execute(lh, i.second);
ret.push_back(m_receipts.back());
_tq.noteGood(i);
@ -434,6 +432,7 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
// cnote << "TX took:" << t.elapsed() * 1000;
}
}
#if ETH_DEBUG
catch (InvalidNonce const& in)
{
bigint const* req = boost::get_error_info<errinfo_required>(in);
@ -449,13 +448,19 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
else
_tq.setFuture(i);
}
catch (BlockGasLimitReached const& e)
{
_tq.setFuture(i);
}
#endif
catch (Exception const& _e)
{
// Something else went wrong - drop it.
_tq.drop(i.first);
if (o_transactionQueueChanged)
*o_transactionQueueChanged = true;
cwarn << "Sync went wrong\n" << diagnostic_information(_e);
cnote << "Dropping invalid transaction:";
cnote << diagnostic_information(_e);
}
catch (std::exception const&)
{
@ -463,6 +468,7 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, Ga
_tq.drop(i.first);
if (o_transactionQueueChanged)
*o_transactionQueueChanged = true;
cnote << "Transaction caused low-level exception :(";
}
}
}
@ -498,7 +504,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
GenericTrieDB<MemoryDB> receiptsTrie(&rm);
receiptsTrie.init();
LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number);
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
RLP rlp(_block);
// All ok with the block generally. Play back the transactions now...
@ -509,7 +515,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
k << i;
transactionsTrie.insert(&k.out(), tr.data());
execute(lh, tr.data());
execute(lh, Transaction(tr.data(), CheckSignature::Sender));
RLPStream receiptrlp;
m_receipts.back().streamRLP(receiptrlp);
@ -1040,56 +1046,34 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
LastHashes State::getLastHashes(BlockChain const& _bc, unsigned _n) const
{
LastHashes ret;
ret.resize(256);
if (eth::c_protocolVersion > 49)
{
ret[0] = _bc.numberHash(_n);
for (unsigned i = 1; i < 256; ++i)
ret[i] = ret[i - 1] ? _bc.details(ret[i - 1]).parent : h256();
}
return ret;
}
ExecutionResult State::execute(BlockChain const& _bc, bytes const& _rlp, Permanence _p)
{
return execute(getLastHashes(_bc, _bc.number()), &_rlp, _p);
}
ExecutionResult State::execute(BlockChain const& _bc, bytesConstRef _rlp, Permanence _p)
ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p)
{
return execute(getLastHashes(_bc, _bc.number()), _rlp, _p);
}
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
ExecutionResult State::execute(LastHashes const& _lh, bytesConstRef _rlp, Permanence _p)
{
#ifndef ETH_RELEASE
commit(); // get an updated hash
#endif
#if ETH_PARANOIA
paranoia("start of execution.", true);
State old(*this);
#if ETH_PARANOIA
auto h = rootHash();
#endif
// 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);
e.setup(_rlp);
e.initialize(_t);
u256 startGasUsed = gasUsed();
// 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();
#if ETH_PARANOIA
ctrace << "Executing" << e.t() << "on" << h;
ctrace << toHex(e.t().rlp());
#endif
if (!e.execute())
#if ETH_VMTRACE
e.go(e.simpleTrace());
e.go(e.simpleTrace());
#else
e.go();
e.go();
#endif
e.finalize();

8
libethereum/State.h

@ -188,15 +188,9 @@ public:
/// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const;
/// Returns the last few block hashes of the current chain.
LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const;
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
ExecutionResult execute(BlockChain const& _bc, bytes const& _rlp, Permanence _p = Permanence::Committed);
ExecutionResult execute(BlockChain const& _bc, bytesConstRef _rlp, Permanence _p = Permanence::Committed);
ExecutionResult execute(LastHashes const& _lh, bytes const& _rlp, Permanence _p = Permanence::Committed) { return execute(_lh, &_rlp, _p); }
ExecutionResult execute(LastHashes const& _lh, bytesConstRef _rlp, Permanence _p = Permanence::Committed);
ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed);
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); }

10
libethereum/TransactionQueue.cpp

@ -46,7 +46,7 @@ bool TransactionQueue::import(bytesConstRef _transactionRLP)
UpgradeGuard ul(l);
// If valid, append to blocks.
m_current[h] = _transactionRLP.toBytes();
m_current[h] = t;
m_known.insert(h);
}
catch (Exception const& _e)
@ -63,20 +63,20 @@ bool TransactionQueue::import(bytesConstRef _transactionRLP)
return true;
}
void TransactionQueue::setFuture(std::pair<h256, bytes> const& _t)
void TransactionQueue::setFuture(std::pair<h256, Transaction> const& _t)
{
WriteGuard l(m_lock);
if (m_current.count(_t.first))
{
m_current.erase(_t.first);
m_unknown.insert(make_pair(Transaction(_t.second, CheckSignature::Sender).sender(), _t));
m_unknown.insert(make_pair(_t.second.sender(), _t));
}
}
void TransactionQueue::noteGood(std::pair<h256, bytes> const& _t)
void TransactionQueue::noteGood(std::pair<h256, Transaction> const& _t)
{
WriteGuard l(m_lock);
auto r = m_unknown.equal_range(Transaction(_t.second, CheckSignature::Sender).sender());
auto r = m_unknown.equal_range(_t.second.sender());
for (auto it = r.first; it != r.second; ++it)
m_current.insert(it->second);
m_unknown.erase(r.first, r.second);

11
libethereum/TransactionQueue.h

@ -25,6 +25,7 @@
#include <libdevcore/Common.h>
#include "libethcore/Common.h"
#include <libdevcore/Guards.h>
#include "Transaction.h"
namespace dev
{
@ -46,19 +47,19 @@ public:
void drop(h256 _txHash);
std::map<h256, bytes> transactions() const { ReadGuard l(m_lock); return m_current; }
std::map<h256, Transaction> transactions() const { ReadGuard l(m_lock); return m_current; }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); }
void setFuture(std::pair<h256, bytes> const& _t);
void noteGood(std::pair<h256, bytes> const& _t);
void setFuture(std::pair<h256, Transaction> const& _t);
void noteGood(std::pair<h256, Transaction> const& _t);
void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); }
private:
mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets.
std::map<h256, bytes> m_current; ///< Map of SHA3(tx) to tx.
std::multimap<Address, std::pair<h256, bytes>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
std::map<h256, Transaction> m_current; ///< Map of SHA3(tx) to tx.
std::multimap<Address, std::pair<h256, Transaction>> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX.
};
}

22
libp2p/Network.cpp

@ -165,7 +165,7 @@ int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const&
return retport;
}
bi::tcp::endpoint Network::traverseNAT(std::set<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr)
bi::tcp::endpoint Network::traverseNAT(std::set<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpInterfaceAddr)
{
asserts(_listenPort != 0);
@ -177,26 +177,26 @@ bi::tcp::endpoint Network::traverseNAT(std::set<bi::address> const& _ifAddresses
// let m_upnp continue as null - we handle it properly.
catch (...) {}
bi::tcp::endpoint upnpep;
bi::tcp::endpoint upnpEP;
if (upnp && upnp->isValid())
{
bi::address paddr;
bi::address pAddr;
int extPort = 0;
for (auto const& addr: _ifAddresses)
if (addr.is_v4() && isPrivateAddress(addr) && (extPort = upnp->addRedirect(addr.to_string().c_str(), _listenPort)))
{
paddr = addr;
pAddr = addr;
break;
}
auto eip = upnp->externalIP();
bi::address eipaddr(bi::address::from_string(eip));
if (extPort && eip != string("0.0.0.0") && !isPrivateAddress(eipaddr))
auto eIP = upnp->externalIP();
bi::address eIPAddr(bi::address::from_string(eIP));
if (extPort && eIP != string("0.0.0.0") && !isPrivateAddress(eIPAddr))
{
clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << extPort << ".";
clog(NetNote) << "External addr:" << eip;
o_upnpifaddr = paddr;
upnpep = bi::tcp::endpoint(eipaddr, (unsigned short)extPort);
clog(NetNote) << "External addr:" << eIP;
o_upnpInterfaceAddr = pAddr;
upnpEP = bi::tcp::endpoint(eIPAddr, (unsigned short)extPort);
}
else
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place).";
@ -205,7 +205,7 @@ bi::tcp::endpoint Network::traverseNAT(std::set<bi::address> const& _ifAddresses
delete upnp;
}
return upnpep;
return upnpEP;
}
bi::tcp::endpoint Network::resolveHost(string const& _addr)

5
mix/MixClient.cpp

@ -112,7 +112,8 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
State execState = _state;
Executive execution(execState, lastHashes, 0);
execution.setup(&rlp);
execution.initialize(&rlp);
execution.execute();
std::vector<MachineState> machineStates;
std::vector<unsigned> levels;
std::vector<MachineCode> codes;
@ -184,7 +185,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
// execute on a state
if (!_call)
{
_state.execute(lastHashes, rlp);
_state.execute(lastHashes, _t);
if (_t.isCreation() && _state.code(d.contractAddress).empty())
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
// collect watches

21
test/blockchain.cpp

@ -182,18 +182,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
Transactions txList;
for (auto const& txi: txs.transactions())
{
Transaction tx(txi.second, CheckSignature::Sender);
txList.push_back(tx);
txList.push_back(txi.second);
mObject txObject;
txObject["nonce"] = toString(tx.nonce());
txObject["data"] = "0x" + toHex(tx.data());
txObject["gasLimit"] = toString(tx.gas());
txObject["gasPrice"] = toString(tx.gasPrice());
txObject["r"] = "0x" + toString(tx.signature().r);
txObject["s"] = "0x" + toString(tx.signature().s);
txObject["v"] = to_string(tx.signature().v + 27);
txObject["to"] = tx.isCreation() ? "" : toString(tx.receiveAddress());
txObject["value"] = toString(tx.value());
txObject["nonce"] = toString(txi.second.nonce());
txObject["data"] = "0x" + toHex(txi.second.data());
txObject["gasLimit"] = toString(txi.second.gas());
txObject["gasPrice"] = toString(txi.second.gasPrice());
txObject["r"] = "0x" + toString(txi.second.signature().r);
txObject["s"] = "0x" + toString(txi.second.signature().s);
txObject["v"] = to_string(txi.second.signature().v + 27);
txObject["to"] = txi.second.isCreation() ? "" : toString(txi.second.receiveAddress());
txObject["value"] = toString(txi.second.value());
txArray.push_back(txObject);
}

3
test/checkRandomStateTest.cpp

@ -83,12 +83,11 @@ bool doStateTest(mValue& _v)
ImportTest importer(o, false);
eth::State theState = importer.m_statePre;
bytes tx = importer.m_transaction.rlp();
bytes output;
try
{
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output;
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
}
catch (Exception const& _e)
{

3
test/createRandomStateTest.cpp

@ -183,12 +183,11 @@ void doStateTests(json_spirit::mValue& _v)
test::ImportTest importer(o, true);
eth::State theState = importer.m_statePre;
bytes tx = importer.m_transaction.rlp();
bytes output;
try
{
output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), tx).output;
output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
}
catch (Exception const& _e)
{

3
test/solidityExecutionFramework.h

@ -142,7 +142,8 @@ protected:
try
{
// this will throw since the transaction is invalid, but it should nevertheless store the transaction
executive.setup(&transactionRLP);
executive.initialize(&transactionRLP);
executive.execute();
}
catch (...) {}
if (_isCreation)

3
test/state.cpp

@ -57,13 +57,12 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
ImportTest importer(o, _fillin);
State theState = importer.m_statePre;
bytes tx = importer.m_transaction.rlp();
bytes output;
try
{
Listener::ExecTimeGuard guard{i.first};
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output;
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
}
catch (Exception const& _e)
{

10
test/stateOriginal.cpp

@ -79,13 +79,9 @@ BOOST_AUTO_TEST_CASE(Complex)
cout << s;
// Inject a transaction to transfer funds from miner to me.
bytes tx;
{
Transaction t(1000, 10000, 10000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
assert(t.sender() == myMiner.address());
tx = t.rlp();
}
s.execute(bc, tx);
Transaction t(1000, 10000, 10000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
assert(t.sender() == myMiner.address());
s.execute(bc.lastHashes(), t);
cout << s;

Loading…
Cancel
Save