diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 04fc7757c..a240f64e1 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -1261,9 +1261,12 @@ void Main::on_blocks_currentItemChanged()
s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "";
s << "
Coinbase: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress;
s << "
Nonce: " << info.nonce << "";
- s << "
Hash w/o nonce: " << info.headerHashWithoutNonce() << "";
+ s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "";
s << "
Difficulty: " << info.difficulty << "";
- s << "
Proof-of-Work: " << ProofOfWork::eval(info.headerHashWithoutNonce(), info.nonce) << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "";
+ if (info.number)
+ s << "
Proof-of-Work: " << ProofOfWork::eval(info.headerHash(WithoutNonce), info.nonce) << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "";
+ else
+ s << "
Proof-of-Work: Phil has nothing to prove";
s << "
Parent: " << info.parentHash << "";
// s << "
Bloom: " << details.bloom << "";
s << "
Log Bloom: " << info.logBloom << "";
@@ -1280,7 +1283,7 @@ void Main::on_blocks_currentItemChanged()
if (info.parentHash)
s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "";
else
- s << "
Pre: Nothing is before the Gensesis";
+ s << "
Pre: Nothing is before Phil";
for (auto const& i: block[1])
s << "
" << sha3(i.data()).abridged();// << ": " << i[1].toHash() << " [" << i[2].toInt() << " used]";
s << "
Post: " << info.stateRoot << "";
@@ -1395,10 +1398,10 @@ void Main::populateDebugger(dev::bytesConstRef _r)
bytesConstRef lastData;
h256 lastHash;
h256 lastDataHash;
- auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt)
+ auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, dev::eth::VM* voidVM, dev::eth::ExtVMFace const* voidExt)
{
- dev::eth::VM& vm = *(dev::eth::VM*)voidVM;
- dev::eth::ExtVM const& ext = *(dev::eth::ExtVM const*)voidExt;
+ dev::eth::VM& vm = *voidVM;
+ dev::eth::ExtVM const& ext = *static_cast(voidExt);
if (ext.code != lastExtCode)
{
lastExtCode = ext.code;
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index 50b9df413..fffc5843f 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/eth/main.cpp b/eth/main.cpp
index 9485a11bf..0113fa1a5 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -630,10 +630,10 @@ int main(int argc, char** argv)
OnOpFunc oof;
if (format == "pretty")
- oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM)
+ oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
{
- dev::eth::VM* vm = (VM*)vvm;
- dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
+ dev::eth::VM* vm = vvm;
+ dev::eth::ExtVM const* ext = static_cast(vextVM);
f << endl << " STACK" << endl;
for (auto i: vm->stack())
f << (h256)i << endl;
@@ -644,17 +644,17 @@ int main(int argc, char** argv)
f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
};
else if (format == "standard")
- oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
+ oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
{
- dev::eth::VM* vm = (VM*)vvm;
- dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
+ dev::eth::VM* vm = vvm;
+ dev::eth::ExtVM const* ext = static_cast(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)vm->gas(), 1)) << endl;
};
else if (format == "standard+")
- oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
+ oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM)
{
dev::eth::VM* vm = (VM*)vvm;
- dev::eth::ExtVM const* ext = (ExtVM const*)vextVM;
+ dev::eth::ExtVM const* ext = static_cast(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;
diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp
index 015f8dad6..fbf056867 100644
--- a/libethcore/BlockInfo.cpp
+++ b/libethcore/BlockInfo.cpp
@@ -49,19 +49,19 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _block)
return ret;
}
-h256 BlockInfo::headerHashWithoutNonce() const
+h256 BlockInfo::headerHash(IncludeNonce _n) const
{
RLPStream s;
- streamRLP(s, false);
+ streamRLP(s, _n);
return sha3(s.out());
}
-void BlockInfo::streamRLP(RLPStream& _s, bool _nonce) const
+void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const
{
- _s.appendList(_nonce ? 14 : 13)
+ _s.appendList(_n == WithNonce ? 14 : 13)
<< parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom
<< difficulty << number << gasLimit << gasUsed << timestamp << extraData;
- if (_nonce)
+ if (_n == WithNonce)
_s << nonce;
}
@@ -100,8 +100,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
}
// check it hashes according to proof of work or that it's the genesis block.
- if (_checkNonce && parentHash && !ProofOfWork::verify(headerHashWithoutNonce(), nonce, difficulty))
- BOOST_THROW_EXCEPTION(InvalidBlockNonce(headerHashWithoutNonce(), nonce, difficulty));
+ if (_checkNonce && parentHash && !ProofOfWork::verify(headerHash(WithoutNonce), nonce, difficulty))
+ BOOST_THROW_EXCEPTION(InvalidBlockNonce(headerHash(WithoutNonce), nonce, difficulty));
if (gasUsed > gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed());
diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h
index aa7456f72..fc52880fa 100644
--- a/libethcore/BlockInfo.h
+++ b/libethcore/BlockInfo.h
@@ -32,6 +32,12 @@ namespace eth
extern u256 c_genesisDifficulty;
+enum IncludeNonce
+{
+ WithoutNonce = 0,
+ WithNonce = 1
+};
+
/** @brief Encapsulation of a block header.
* Class to contain all of a block header's data. It is able to parse a block header and populate
* from some given RLP block serialisation with the static fromHeader(), through the method
@@ -48,7 +54,7 @@ extern u256 c_genesisDifficulty;
*
* The difficulty and gas-limit derivations may be calculated with the calculateDifficulty()
* and calculateGasLimit() and the object serialised to RLP with streamRLP. To determine the
- * header hash without the nonce (for mining), the method headerHashWithoutNonce() is provided.
+ * header hash without the nonce (for mining), the method headerHash(WithoutNonce) is provided.
*
* The default constructor creates an empty object, which can be tested against with the boolean
* conversion operator.
@@ -113,8 +119,8 @@ public:
u256 calculateGasLimit(BlockInfo const& _parent) const;
/// No-nonce sha3 of the header only.
- h256 headerHashWithoutNonce() const;
- void streamRLP(RLPStream& _s, bool _nonce) const;
+ h256 headerHash(IncludeNonce _n) const;
+ void streamRLP(RLPStream& _s, IncludeNonce _n) const;
};
inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi)
diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp
index 5f9332ad8..36726dae4 100644
--- a/libethcore/CommonEth.cpp
+++ b/libethcore/CommonEth.cpp
@@ -33,7 +33,7 @@ namespace dev
namespace eth
{
-const unsigned c_protocolVersion = 48;
+const unsigned c_protocolVersion = 49;
const unsigned c_databaseVersion = 5;
static const vector> g_units =
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index 531005fb2..6ed0a2ca6 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -145,7 +145,7 @@ void BlockChain::open(std::string _path, bool _killExisting)
if (!details(m_genesisHash))
{
// Insert details of genesis block.
- m_details[m_genesisHash] = BlockDetails(0, c_genesisDifficulty, h256(), {}, h256());
+ m_details[m_genesisHash] = BlockDetails(0, c_genesisDifficulty, h256(), {});
auto r = m_details[m_genesisHash].rlp();
m_extrasDB->Put(m_writeOptions, ldb::Slice((char const*)&m_genesisHash, 32), (ldb::Slice)dev::ref(r));
}
@@ -303,7 +303,6 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
// Get total difficulty increase and update state, checking it.
State s(bi.coinbaseAddress, _db);
auto tdIncrease = s.enactOn(&_block, bi, *this);
- auto b = s.oldBloom();
BlockLogBlooms blb;
BlockReceipts br;
for (unsigned i = 0; i < s.pending().size(); ++i)
@@ -320,7 +319,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
// All ok - insert into DB
{
WriteGuard l(x_details);
- m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}, b);
+ m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {});
m_details[bi.parentHash].children.push_back(newHash);
}
{
diff --git a/libethereum/BlockDetails.cpp b/libethereum/BlockDetails.cpp
index 5a61eb037..58f37b7aa 100644
--- a/libethereum/BlockDetails.cpp
+++ b/libethereum/BlockDetails.cpp
@@ -32,10 +32,9 @@ BlockDetails::BlockDetails(RLP const& _r)
totalDifficulty = _r[1].toInt();
parent = _r[2].toHash();
children = _r[3].toVector();
- bloom = _r[4].toHash();
}
bytes BlockDetails::rlp() const
{
- return rlpList(number, totalDifficulty, parent, children, bloom);
+ return rlpList(number, totalDifficulty, parent, children);
}
diff --git a/libethereum/BlockDetails.h b/libethereum/BlockDetails.h
index 0c3af5b33..2fd0d3048 100644
--- a/libethereum/BlockDetails.h
+++ b/libethereum/BlockDetails.h
@@ -40,7 +40,7 @@ namespace eth
struct BlockDetails
{
BlockDetails(): number(0), totalDifficulty(0) {}
- BlockDetails(unsigned _n, u256 _tD, h256 _p, h256s _c, h256 _bloom): number(_n), totalDifficulty(_tD), parent(_p), children(_c), bloom(_bloom) {}
+ BlockDetails(unsigned _n, u256 _tD, h256 _p, h256s _c): number(_n), totalDifficulty(_tD), parent(_p), children(_c) {}
BlockDetails(RLP const& _r);
bytes rlp() const;
@@ -51,7 +51,6 @@ struct BlockDetails
u256 totalDifficulty;
h256 parent;
h256s children;
- h256 bloom;
};
struct BlockLogBlooms
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index 6a123875c..007896d75 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -21,6 +21,7 @@
#include
#include
+#include
#include
#include "Interface.h"
#include "Executive.h"
@@ -32,13 +33,6 @@ using namespace dev::eth;
#define ETH_VMTRACE 1
-Executive::~Executive()
-{
- // TODO: Make safe.
- delete m_ext;
- delete m_vm;
-}
-
u256 Executive::gasUsed() const
{
return m_t.gas() - m_endGas;
@@ -91,14 +85,6 @@ bool Executive::setup(bytesConstRef _rlp)
clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")";
m_s.subBalance(m_sender, cost);
- if (m_ms)
- {
- m_ms->from = m_sender;
- m_ms->to = m_t.receiveAddress();
- m_ms->value = m_t.value();
- m_ms->input = m_t.data();
- }
-
if (m_t.isCreation())
return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)gasCost, &m_t.data(), m_sender);
else
@@ -110,11 +96,24 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
// cnote << "Transferring" << formatBalance(_value) << "to receiver.";
m_s.addBalance(_receiveAddress, _value);
- if (m_s.addressHasCode(_receiveAddress))
+ auto it = !(_receiveAddress & ~h160(0xffffffff)) ? State::precompiled().find((unsigned)(u160)_receiveAddress) : State::precompiled().end();
+ if (it != State::precompiled().end())
{
- m_vm = new VM(_gas);
+ bigint g = it->second.gas(_data);
+ if (_gas < g)
+ {
+ m_endGas = 0;
+ return false;
+ }
+ m_endGas = (u256)(_gas - g);
+ it->second.exec(_data, bytesRef());
+ return true;
+ }
+ else if (m_s.addressHasCode(_receiveAddress))
+ {
+ m_vm = VMFactory::create(_gas);
bytes const& c = m_s.code(_receiveAddress);
- m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms);
+ m_ext.reset(new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c));
}
else
m_endGas = _gas;
@@ -131,17 +130,17 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception);
// Execute _init.
- m_vm = new VM(_gas);
- m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms);
+ m_vm = VMFactory::create(_gas);
+ m_ext.reset(new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init));
return _init.empty();
}
OnOpFunc Executive::simpleTrace()
{
- return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt)
+ return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, VM* voidVM, ExtVMFace const* voidExt)
{
- ExtVM const& ext = *(ExtVM const*)voidExt;
- VM& vm = *(VM*)voidVM;
+ ExtVM const& ext = *static_cast(voidExt);
+ VM& vm = *voidVM;
ostringstream o;
o << endl << " STACK" << endl;
@@ -162,16 +161,16 @@ bool Executive::go(OnOpFunc const& _onOp)
{
boost::timer t;
auto sgas = m_vm->gas();
- bool revert = false;
try
{
m_out = m_vm->go(*m_ext, _onOp);
- if (m_ext)
- {
- m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds);
- m_logs = m_ext->sub.logs;
- }
m_endGas = m_vm->gas();
+ m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds);
+ m_logs = m_ext->sub.logs;
+ if (m_out.size() * c_createDataGas <= m_endGas)
+ m_endGas -= m_out.size() * c_createDataGas;
+ else
+ m_out.reset();
}
catch (StepsDone const&)
{
@@ -181,7 +180,16 @@ bool Executive::go(OnOpFunc const& _onOp)
{
clog(StateChat) << "Safe VM Exception: " << diagnostic_information(_e);
m_endGas = 0;//m_vm->gas();
- revert = true;
+
+ // Write state out only in the case of a non-excepted transaction.
+ m_ext->revert();
+
+ // Explicitly delete a newly created address - this will still be in the reverted state.
+/* if (m_newAddress)
+ {
+ m_s.m_cache.erase(m_newAddress);
+ m_newAddress = Address();
+ }*/
}
catch (Exception const& _e)
{
@@ -194,18 +202,6 @@ bool Executive::go(OnOpFunc const& _onOp)
cwarn << "Unexpected std::exception in VM. This is probably unrecoverable. " << _e.what();
}
cnote << "VM took:" << t.elapsed() << "; gas used: " << (sgas - m_endGas);
-
- // Write state out only in the case of a non-excepted transaction.
- if (revert)
- {
- m_ext->revert();
- // Explicitly delete a newly created address - this will still be in the reverted state.
- if (m_newAddress)
- {
- m_s.m_cache.erase(m_newAddress);
- m_newAddress = Address();
- }
- }
}
return true;
}
@@ -217,9 +213,11 @@ u256 Executive::gas() const
void Executive::finalize(OnOpFunc const&)
{
- if (m_t.isCreation() && m_newAddress && m_out.size())
- // non-reverted creation - put code in place.
+ if (m_t.isCreation() && !m_ext->sub.suicides.count(m_newAddress))
+ {
+ // creation - put code in place.
m_s.m_cache[m_newAddress].setCode(m_out);
+ }
// cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")";
m_s.addBalance(m_sender, m_endGas * m_t.gasPrice());
@@ -228,9 +226,6 @@ void Executive::finalize(OnOpFunc const&)
// cnote << "Transferring" << formatBalance(gasSpent) << "to miner.";
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned);
- if (m_ms)
- m_ms->output = m_out.toBytes();
-
// Suicides...
if (m_ext)
for (auto a: m_ext->sub.suicides)
diff --git a/libethereum/Executive.h b/libethereum/Executive.h
index 930c2859b..9e47bbfbf 100644
--- a/libethereum/Executive.h
+++ b/libethereum/Executive.h
@@ -25,26 +25,27 @@
#include
#include
#include
-#include
+#include
#include "Transaction.h"
-#include "Manifest.h"
+#include "ExtVM.h"
namespace dev
{
namespace eth
{
-class VM;
-class ExtVM;
class State;
+struct Manifest;
struct VMTraceChannel: public LogChannel { static const char* name() { return "EVM"; } static const int verbosity = 11; };
class Executive
{
public:
- Executive(State& _s, Manifest* o_ms = nullptr): m_s(_s), m_ms(o_ms) {}
- ~Executive();
+ Executive(State& _s): m_s(_s) {}
+ ~Executive() = default;
+ Executive(Executive const&) = delete;
+ void operator=(Executive) = delete;
bool setup(bytesConstRef _transaction);
bool create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress);
@@ -63,15 +64,14 @@ public:
h160 newAddress() const { return m_newAddress; }
LogEntries const& logs() const { return m_logs; }
- VM const& vm() const { return *m_vm; }
+ VMFace const& vm() const { return *m_vm; }
State const& state() const { return m_s; }
ExtVM const& ext() const { return *m_ext; }
private:
State& m_s;
- ExtVM* m_ext = nullptr; // TODO: make safe.
- VM* m_vm = nullptr;
- Manifest* m_ms = nullptr;
+ std::unique_ptr m_ext;
+ std::unique_ptr m_vm;
bytesConstRef m_out;
Address m_newAddress;
diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h
index 24ce618ed..ad1045d3f 100644
--- a/libethereum/ExtVM.h
+++ b/libethereum/ExtVM.h
@@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace
{
public:
/// Full constructor.
- ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _depth = 0):
- ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms)
+ ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0):
+ ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache)
{
m_s.ensureCached(_myAddress, true, true);
}
@@ -49,7 +49,7 @@ public:
virtual u256 store(u256 _n) override final { return m_s.storage(myAddress, _n); }
/// Write a value in storage.
- virtual void setStore(u256 _n, u256 _v) override final { m_s.setStorage(myAddress, _n, _v); if (m_ms) m_ms->altered.push_back(_n); }
+ virtual void setStore(u256 _n, u256 _v) override final { m_s.setStorage(myAddress, _n, _v); }
/// Read address's code.
virtual bytes const& codeAt(Address _a) override final { return m_s.code(_a); }
@@ -59,23 +59,13 @@ public:
{
// Increment associated nonce for sender.
m_s.noteSending(myAddress);
- if (m_ms)
- m_ms->internal.resize(m_ms->internal.size() + 1);
- auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &sub, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
- if (m_ms && !m_ms->internal.back().from)
- m_ms->internal.pop_back();
- return ret;
+ return m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &sub, _onOp, depth + 1);
}
/// Create a new message call. Leave _myAddressOverride as the default to use the present address as caller.
virtual bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out, OnOpFunc const& _onOp = {}, Address _myAddressOverride = {}, Address _codeAddressOverride = {}) override final
{
- if (m_ms)
- m_ms->internal.resize(m_ms->internal.size() + 1);
- auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &sub, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
- if (m_ms && !m_ms->internal.back().from)
- m_ms->internal.pop_back();
- return ret;
+ return m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &sub, _onOp, depth + 1);
}
/// Read address's balance.
@@ -96,14 +86,13 @@ public:
/// Revert any changes made (by any of the other calls).
/// @TODO check call site for the parent manifest being discarded.
- virtual void revert() override final { if (m_ms) *m_ms = Manifest(); m_s.m_cache = m_origCache; }
+ virtual void revert() override final { m_s.m_cache = m_origCache; }
State& state() const { return m_s; }
private:
State& m_s; ///< A reference to the base state.
std::map m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.
- Manifest* m_ms;
};
}
diff --git a/libethereum/Manifest.cpp b/libethereum/Manifest.cpp
index 9e6d2f651..e69de29bb 100644
--- a/libethereum/Manifest.cpp
+++ b/libethereum/Manifest.cpp
@@ -1,46 +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 .
-*/
-/** @file Manifest.cpp
- * @author Gav Wood
- * @date 2014
- */
-
-#include "Manifest.h"
-using namespace std;
-using namespace dev;
-using namespace dev::eth;
-
-Manifest::Manifest(bytesConstRef _r)
-{
- RLP r(_r);
- from = r[0].toHash();
- to = r[1].toHash();
- value = r[2].toInt();
- altered = r[3].toVector();
- input = r[4].toBytes();
- output = r[5].toBytes();
- for (auto const& i: r[6])
- internal.emplace_back(i.data());
-}
-
-void Manifest::streamRLP(RLPStream& _s) const
-{
- _s.appendList(7) << from << to << value << altered << input << output;
- _s.appendList(internal.size());
- for (auto const& i: internal)
- i.streamRLP(_s);
-}
diff --git a/libethereum/Manifest.h b/libethereum/Manifest.h
index e0e512c92..e69de29bb 100644
--- a/libethereum/Manifest.h
+++ b/libethereum/Manifest.h
@@ -1,73 +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 .
-*/
-/** @file Manifest.h
- * @author Gav Wood
- * @date 2014
- */
-
-#pragma once
-
-#include
-#include
-#include
-#include
-
-namespace dev
-{
-namespace eth
-{
-
-struct Manifest;
-using Manifests = std::vector;
-
-/**
- * @brief A record of the state-interaction of a transaction/call/create.
- */
-struct Manifest
-{
- Manifest() {}
- Manifest(bytesConstRef _r);
- void streamRLP(RLPStream& _s) const;
-
- h256 bloom() const { h256 ret = from.bloom() | to.bloom(); for (auto const& i: internal) ret |= i.bloom(); for (auto const& i: altered) ret |= h256(i).bloom(); return ret; }
-
- std::string toString(unsigned _indent = 0) const
- {
- std::ostringstream oss;
- oss << std::string(_indent * 3, ' ') << from << " -> " << to << " [" << value << "]: {";
- if (internal.size())
- {
- oss << std::endl;
- for (auto const& m: internal)
- oss << m.toString(_indent + 1) << std::endl;
- oss << std::string(_indent * 3, ' ');
- }
- oss << "} I:" << toHex(input) << "; O:" << toHex(output);
- return oss.str();
- }
-
- Address from;
- Address to;
- u256 value;
- u256s altered;
- bytes input;
- bytes output;
- Manifests internal;
-};
-
-}
-}
diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp
index 0519fe28b..f44587620 100644
--- a/libethereum/MessageFilter.cpp
+++ b/libethereum/MessageFilter.cpp
@@ -27,131 +27,6 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
-void MessageFilter::streamRLP(RLPStream& _s) const
-{
- _s.appendList(8) << m_from << m_to << m_stateAltered << m_altered << m_earliest << m_latest << m_max << m_skip;
-}
-
-h256 MessageFilter::sha3() const
-{
- RLPStream s;
- streamRLP(s);
- return dev::sha3(s.out());
-}
-
-bool MessageFilter::matches(h256 _bloom) const
-{
- auto have = [=](Address const& a) { return _bloom.contains(a.bloom()); };
- if (m_from.size())
- {
- for (auto i: m_from)
- if (have(i))
- goto OK1;
- return false;
- }
- OK1:
- if (m_to.size())
- {
- for (auto i: m_to)
- if (have(i))
- goto OK2;
- return false;
- }
- OK2:
- if (m_stateAltered.size() || m_altered.size())
- {
- for (auto i: m_altered)
- if (have(i))
- goto OK3;
- for (auto i: m_stateAltered)
- if (have(i.first) && _bloom.contains(h256(i.second).bloom()))
- goto OK3;
- return false;
- }
- OK3:
- return true;
-}
-
-bool MessageFilter::matches(State const& _s, unsigned _i) const
-{
- h256 b = _s.changesFromPending(_i).bloom();
- if (!matches(b))
- return false;
-
- Transaction t = _s.pending()[_i];
- if (!m_to.empty() && !m_to.count(t.receiveAddress()))
- return false;
- if (!m_from.empty() && !m_from.count(t.sender()))
- return false;
- if (m_stateAltered.empty() && m_altered.empty())
- return true;
- StateDiff d = _s.pendingDiff(_i);
- if (!m_altered.empty())
- {
- for (auto const& s: m_altered)
- if (d.accounts.count(s))
- return true;
- return false;
- }
- if (!m_stateAltered.empty())
- {
- for (auto const& s: m_stateAltered)
- if (d.accounts.count(s.first) && d.accounts.at(s.first).storage.count(s.second))
- return true;
- return false;
- }
- return true;
-}
-
-PastMessages MessageFilter::matches(Manifest const& _m, unsigned _i) const
-{
- PastMessages ret;
- matches(_m, vector(1, _i), _m.from, PastMessages(), ret);
- return ret;
-}
-
-bool MessageFilter::matches(Manifest const& _m, vector _p, Address _o, PastMessages _limbo, PastMessages& o_ret) const
-{
- bool ret;
-
- if ((m_from.empty() || m_from.count(_m.from)) && (m_to.empty() || m_to.count(_m.to)))
- _limbo.push_back(PastMessage(_m, _p, _o));
-
- // Handle limbos, by checking against all addresses in alteration.
- bool alters = m_altered.empty() && m_stateAltered.empty();
- alters = alters || m_altered.count(_m.from) || m_altered.count(_m.to);
-
- if (!alters)
- for (auto const& i: _m.altered)
- if (m_altered.count(_m.to) || m_stateAltered.count(make_pair(_m.to, i)))
- {
- alters = true;
- break;
- }
- // If we do alter stuff,
- if (alters)
- {
- o_ret += _limbo;
- _limbo.clear();
- ret = true;
- }
-
- _p.push_back(0);
- for (auto const& m: _m.internal)
- {
- if (matches(m, _p, _o, _limbo, o_ret))
- {
- _limbo.clear();
- ret = true;
- }
- _p.back()++;
- }
-
- return ret;
-}
-
-
-
void LogFilter::streamRLP(RLPStream& _s) const
{
_s.appendList(6) << m_addresses << m_topics << m_earliest << m_latest << m_max << m_skip;
diff --git a/libethereum/MessageFilter.h b/libethereum/MessageFilter.h
index 482c68ef6..e2c26d214 100644
--- a/libethereum/MessageFilter.h
+++ b/libethereum/MessageFilter.h
@@ -24,7 +24,6 @@
#include
#include
#include
-#include "PastMessage.h"
#include "TransactionReceipt.h"
namespace dev
@@ -32,47 +31,8 @@ namespace dev
namespace eth
{
-struct Manifest;
class State;
-class MessageFilter
-{
-public:
- MessageFilter(int _earliest = 0, int _latest = -1, unsigned _max = 10, unsigned _skip = 0): m_earliest(_earliest), m_latest(_latest), m_max(_max), m_skip(_skip) {}
-
- void streamRLP(RLPStream& _s) const;
- h256 sha3() const;
-
- int earliest() const { return m_earliest; }
- int latest() const { return m_latest; }
- unsigned max() const { return m_max; }
- unsigned skip() const { return m_skip; }
- bool matches(h256 _bloom) const;
- bool matches(State const& _s, unsigned _i) const;
- PastMessages matches(Manifest const& _m, unsigned _i) const;
-
- MessageFilter from(Address _a) { m_from.insert(_a); return *this; }
- MessageFilter to(Address _a) { m_to.insert(_a); return *this; }
- MessageFilter altered(Address _a, u256 _l) { m_stateAltered.insert(std::make_pair(_a, _l)); return *this; }
- MessageFilter altered(Address _a) { m_altered.insert(_a); return *this; }
- MessageFilter withMax(unsigned _m) { m_max = _m; return *this; }
- MessageFilter withSkip(unsigned _m) { m_skip = _m; return *this; }
- MessageFilter withEarliest(int _e) { m_earliest = _e; return *this; }
- MessageFilter withLatest(int _e) { m_latest = _e; return *this; }
-
-private:
- bool matches(Manifest const& _m, std::vector _p, Address _o, PastMessages _limbo, PastMessages& o_ret) const;
-
- std::set m_from;
- std::set m_to;
- std::set> m_stateAltered;
- std::set m_altered;
- int m_earliest = 0;
- int m_latest = -1;
- unsigned m_max;
- unsigned m_skip;
-};
-
class LogFilter
{
public:
diff --git a/libethereum/PastMessage.cpp b/libethereum/PastMessage.cpp
index d81ae672c..e69de29bb 100644
--- a/libethereum/PastMessage.cpp
+++ b/libethereum/PastMessage.cpp
@@ -1,28 +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 .
-*/
-/** @file PastMessage.cpp
- * @author Gav Wood
- * @date 2014
- */
-
-#include "PastMessage.h"
-using namespace std;
-using namespace dev;
-using namespace dev::eth;
-
-#pragma GCC diagnostic ignored "-Wunused-variable"
-namespace { char dummy; };
diff --git a/libethereum/PastMessage.h b/libethereum/PastMessage.h
index 6446eff5a..e69de29bb 100644
--- a/libethereum/PastMessage.h
+++ b/libethereum/PastMessage.h
@@ -1,56 +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 .
-*/
-/** @file PastMessage.h
- * @author Gav Wood
- * @date 2014
- */
-
-#pragma once
-
-#include
-#include
-#include "Manifest.h"
-
-namespace dev
-{
-namespace eth
-{
-
-struct PastMessage
-{
- PastMessage(Manifest const& _m, std::vector _path, Address _o): to(_m.to), from(_m.from), value(_m.value), input(_m.input), output(_m.output), path(_path), origin(_o) {}
-
- PastMessage& polish(h256 _b, u256 _ts, unsigned _n, Address _coinbase) { block = _b; timestamp = _ts; number = _n; coinbase = _coinbase; return *this; }
-
- Address to; ///< The receiving address of the transaction. Address() in the case of a creation.
- Address from; ///< The receiving address of the transaction. Address() in the case of a creation.
- u256 value; ///< The value associated with the call.
- bytes input; ///< The data associated with the message, or the initialiser if it's a creation transaction.
- bytes output; ///< The data returned by the message, or the body code if it's a creation transaction.
-
- std::vector path; ///< Call path into the block transaction. size() is always > 0. First item is the transaction index in the block.
- Address origin; ///< Originating sender of the transaction.
- Address coinbase; ///< Block coinbase.
- h256 block; ///< Block hash.
- u256 timestamp; ///< Block timestamp.
- unsigned number; ///< Block number.
-};
-
-typedef std::vector PastMessages;
-
-}
-}
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 9a0426e18..1d6ad3480 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -29,10 +29,11 @@
#include
#include
#include
-#include
+#include
#include "BlockChain.h"
#include "Defaults.h"
#include "ExtVM.h"
+#include "Executive.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
@@ -89,9 +90,9 @@ void ripemd160Code(bytesConstRef _in, bytesRef _out)
const std::map State::c_precompiled =
{
- { 1, { 500, ecrecoverCode }},
- { 2, { 100, sha256Code }},
- { 3, { 100, ripemd160Code }}
+ { 1, { [](bytesConstRef) -> bigint { return (bigint)500; }, ecrecoverCode }},
+ { 2, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, sha256Code }},
+ { 3, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, ripemd160Code }}
};
OverlayDB State::openDB(std::string _path, bool _killExisting)
@@ -764,7 +765,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
// Compile block:
RLPStream block;
block.appendList(3);
- m_currentBlock.streamRLP(block, true);
+ m_currentBlock.streamRLP(block, WithNonce);
block.appendRaw(m_currentTxs);
block.appendRaw(m_currentUncles);
@@ -791,14 +792,6 @@ bool State::amIJustParanoid(BlockChain const& _bc)
return false;
}
-h256 State::oldBloom() const
-{
- h256 ret = m_currentBlock.coinbaseAddress.bloom();
- for (auto const& i: m_receipts)
- ret |= i.changes().bloom();
- return ret;
-}
-
LogBloom State::logBloom() const
{
LogBloom ret;
@@ -839,7 +832,7 @@ void State::commitToMine(BlockChain const& _bc)
if (!knownUncles.count(u)) // ignore any uncles/mainline blocks that we know about.
{
BlockInfo ubi(_bc.block(u));
- ubi.streamRLP(unclesData, true);
+ ubi.streamRLP(unclesData, WithNonce);
++unclesCount;
uncleAddresses.push_back(ubi.coinbaseAddress);
}
@@ -903,13 +896,13 @@ MineInfo State::mine(unsigned _msTimeout, bool _turbo)
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
// TODO: Miner class that keeps dagger between mine calls (or just non-polling mining).
- auto ret = m_pow.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout, true, _turbo);
+ auto ret = m_pow.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHash(WithoutNonce), m_currentBlock.difficulty, _msTimeout, true, _turbo);
if (!ret.completed)
m_currentBytes.clear();
else
{
- cnote << "Completed" << m_currentBlock.headerHashWithoutNonce().abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHashWithoutNonce(), m_currentBlock.nonce, m_currentBlock.difficulty);
+ cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.nonce, m_currentBlock.difficulty);
}
return ret;
@@ -923,7 +916,7 @@ void State::completeMine()
// Compile block:
RLPStream ret;
ret.appendList(3);
- m_currentBlock.streamRLP(ret, true);
+ m_currentBlock.streamRLP(ret, WithNonce);
ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles);
ret.swapOut(m_currentBytes);
@@ -1101,7 +1094,7 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return false;
}
}
- catch (InvalidTrie)
+ catch (InvalidTrie const&)
{
cwarn << "BAD TRIE" << (e ? "[enforced" : "[unenforced") << "refs]";
cnote << m_db.keys();
@@ -1126,9 +1119,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
auto h = rootHash();
#endif
- Manifest ms;
-
- Executive e(*this, &ms);
+ Executive e(*this);
e.setup(_rlp);
u256 startGasUsed = gasUsed();
@@ -1178,12 +1169,12 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
// 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(), ms));
+ m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs()));
m_transactionSet.insert(e.t().sha3());
return e.gasUsed();
}
-bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
+bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, SubState* o_sub, OnOpFunc const& _onOp, unsigned _level)
{
if (!_originAddress)
_originAddress = _senderAddress;
@@ -1191,132 +1182,108 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
// cnote << "Transferring" << formatBalance(_value) << "to receiver.";
addBalance(_receiveAddress, _value);
- if (o_ms)
- {
- o_ms->from = _senderAddress;
- o_ms->to = _receiveAddress;
- o_ms->value = _value;
- o_ms->input = _data.toBytes();
- }
-
auto it = !(_codeAddress & ~h160(0xffffffff)) ? c_precompiled.find((unsigned)(u160)_codeAddress) : c_precompiled.end();
if (it != c_precompiled.end())
{
- if (*_gas < it->second.gas)
+ bigint g = it->second.gas(_data);
+ if (*_gas < g)
{
*_gas = 0;
return false;
}
- *_gas -= it->second.gas;
+ *_gas -= (u256)g;
it->second.exec(_data, _out);
}
else if (addressHasCode(_codeAddress))
{
- VM vm(*_gas);
- ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level);
- bool revert = false;
-
+ auto vm = VMFactory::create(*_gas);
+ ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), _level);
try
{
- auto out = vm.go(evm, _onOp);
+ auto out = vm->go(evm, _onOp);
memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
if (o_sub)
*o_sub += evm.sub;
- if (o_ms)
- o_ms->output = out.toBytes();
- *_gas = vm.gas();
+ *_gas = vm->gas();
+ // Write state out only in the case of a non-excepted transaction.
+ return true;
}
catch (VMException const& _e)
{
clog(StateChat) << "Safe VM Exception: " << diagnostic_information(_e);
- revert = true;
+ evm.revert();
*_gas = 0;
+ return false;
}
catch (Exception const& _e)
{
cwarn << "Unexpected exception in VM: " << diagnostic_information(_e) << ". This is exceptionally bad.";
// TODO: use fallback known-safe VM.
+ // AUDIT: THIS SHOULD NEVER HAPPEN! PROVE IT!
+ throw;
}
catch (std::exception const& _e)
{
cwarn << "Unexpected exception in VM: " << _e.what() << ". This is exceptionally bad.";
// TODO: use fallback known-safe VM.
+ // AUDIT: THIS SHOULD NEVER HAPPEN! PROVE IT!
+ throw;
}
-
- // Write state out only in the case of a non-excepted transaction.
- if (revert)
- evm.revert();
-
- return !revert;
}
return true;
}
-h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
+h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, OnOpFunc const& _onOp, unsigned _level)
{
if (!_origin)
_origin = _sender;
- if (o_ms)
- {
- o_ms->from = _sender;
- o_ms->to = Address();
- o_ms->value = _endowment;
- o_ms->input = _code.toBytes();
- }
-
Address newAddress = right160(sha3(rlpList(_sender, transactionsFrom(_sender) - 1)));
// Set up new account...
m_cache[newAddress] = Account(balance(newAddress) + _endowment, Account::ContractConception);
// Execute init code.
- VM vm(*_gas);
- ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level);
- bool revert = false;
+ auto vm = VMFactory::create(*_gas);
+ ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, _level);
bytesConstRef out;
try
{
- out = vm.go(evm, _onOp);
- if (o_ms)
- o_ms->output = out.toBytes();
+ out = vm->go(evm, _onOp);
if (o_sub)
*o_sub += evm.sub;
- *_gas = vm.gas();
+ *_gas = vm->gas();
+
+ if (out.size() * c_createDataGas <= *_gas)
+ *_gas -= out.size() * c_createDataGas;
+ else
+ out.reset();
+
+ // Set code.
+ if (!evm.sub.suicides.count(newAddress))
+ m_cache[newAddress].setCode(out);
}
catch (VMException const& _e)
{
clog(StateChat) << "Safe VM Exception: " << diagnostic_information(_e);
- revert = true;
+ evm.revert();
*_gas = 0;
}
catch (Exception const& _e)
{
// TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does.
cwarn << "Unexpected exception in VM. There may be a bug in this implementation. " << diagnostic_information(_e);
+ throw;
}
catch (std::exception const& _e)
{
// TODO: AUDIT: check that this can never reasonably happen. Consider what to do if it does.
cwarn << "Unexpected std::exception in VM. This is probably unrecoverable. " << _e.what();
+ throw;
}
- // TODO: CHECK: AUDIT: IS THIS CORRECT?! (esp. given account created prior to revertion init.)
-
- // Write state out only in the case of a non-out-of-gas transaction.
- if (revert)
- {
- evm.revert();
- m_cache.erase(newAddress);
- newAddress = Address();
- }
- else
- // Set code.
- if (addressInUse(newAddress))
- m_cache[newAddress].setCode(out);
-
return newAddress;
}
diff --git a/libethereum/State.h b/libethereum/State.h
index 9c41843ff..10d73f671 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -36,7 +36,6 @@
#include "Account.h"
#include "Transaction.h"
#include "TransactionReceipt.h"
-#include "Executive.h"
#include "AccountDiff.h"
namespace dev
@@ -55,7 +54,7 @@ struct StateDetail: public LogChannel { static const char* name() { return "/S/"
struct PrecompiledAddress
{
- unsigned gas;
+ std::function gas;
std::function exec;
};
@@ -211,15 +210,6 @@ public:
/// Get the list of pending transactions.
Transactions const& pending() const { return m_transactions; }
- /// Get the list of pending transactions. TODO: PoC-7: KILL
- Manifest changesFromPending(unsigned _i) const { return m_receipts[_i].changes(); }
-
- /// Get the bloom filter of all changes happened in the block. TODO: PoC-7: KILL
- h256 oldBloom() const;
-
- /// Get the bloom filter of a particular transaction that happened in the block. TODO: PoC-7: KILL
- h256 oldBloom(unsigned _i) const { return m_receipts[_i].changes().bloom(); }
-
/// Get the transaction receipt for the transaction of the given index.
TransactionReceipt const& receipt(unsigned _i) const { return m_receipts[_i]; }
@@ -259,6 +249,9 @@ public:
/// the block since all state changes are ultimately reversed.
void cleanup(bool _fullCommit);
+ /// Info on precompiled contract accounts baked into the protocol.
+ static std::map const& precompiled() { return c_precompiled; }
+
private:
/// Undo the changes to the state for committing to mine.
void uncommitToMine();
@@ -283,12 +276,12 @@ private:
// We assume all instrinsic fees are paid up before this point.
/// Execute a contract-creation transaction.
- h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), SubState* o_sub = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
+ h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), SubState* o_sub = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Execute a call.
/// @a _gas points to the amount of gas to use for the call, and will lower it accordingly.
/// @returns false if the call ran out of gas before completion. true otherwise.
- bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), SubState* o_sub = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
+ bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), SubState* o_sub = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();
diff --git a/libethereum/TransactionReceipt.h b/libethereum/TransactionReceipt.h
index e24c224e7..b990459d9 100644
--- a/libethereum/TransactionReceipt.h
+++ b/libethereum/TransactionReceipt.h
@@ -38,9 +38,7 @@ class TransactionReceipt
{
public:
TransactionReceipt(bytesConstRef _rlp) { RLP r(_rlp); m_stateRoot = (h256)r[0]; m_gasUsed = (u256)r[1]; m_bloom = (LogBloom)r[2]; for (auto const& i: r[3]) m_log.emplace_back(i); }
- TransactionReceipt(h256 _root, u256 _gasUsed, LogEntries const& _log, Manifest const& _ms): m_stateRoot(_root), m_gasUsed(_gasUsed), m_bloom(eth::bloom(_log)), m_log(_log), m_changes(_ms) {}
-
- Manifest const& changes() const { return m_changes; }
+ TransactionReceipt(h256 _root, u256 _gasUsed, LogEntries const& _log): m_stateRoot(_root), m_gasUsed(_gasUsed), m_bloom(eth::bloom(_log)), m_log(_log) {}
h256 const& stateRoot() const { return m_stateRoot; }
u256 const& gasUsed() const { return m_gasUsed; }
@@ -62,8 +60,6 @@ private:
u256 m_gasUsed;
LogBloom m_bloom;
LogEntries m_log;
-
- Manifest m_changes; ///< TODO: PoC-7: KILL
};
using TransactionReceipts = std::vector;
diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h
index 4a175ff4e..24c7dfcda 100644
--- a/libevm/ExtVMFace.h
+++ b/libevm/ExtVMFace.h
@@ -85,7 +85,10 @@ struct SubState
}
};
-using OnOpFunc = std::function;
+class ExtVMFace;
+class VM;
+
+using OnOpFunc = std::function;
/**
* @brief Interface and null implementation of the class for specifying VM externalities.
@@ -146,11 +149,11 @@ public:
u256 value; ///< Value (in Wei) that was passed to this address.
u256 gasPrice; ///< Price of gas (that we already paid).
bytesConstRef data; ///< Current input data.
- bytes code; ///< Current code that is executing.
+ bytes code; ///< Current code that is executing.
BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
- unsigned depth; ///< Depth of the present call.
+ unsigned depth = 0; ///< Depth of the present call.
};
}
diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp
index 3e957118e..94eb956af 100644
--- a/libevm/FeeStructure.cpp
+++ b/libevm/FeeStructure.cpp
@@ -27,12 +27,14 @@ using namespace dev::eth;
u256 const dev::eth::c_stepGas = 1;
u256 const dev::eth::c_balanceGas = 20;
-u256 const dev::eth::c_sha3Gas = 20;
+u256 const dev::eth::c_sha3Gas = 10;
+u256 const dev::eth::c_sha3WordGas = 10;
u256 const dev::eth::c_sloadGas = 20;
u256 const dev::eth::c_sstoreSetGas = 300;
u256 const dev::eth::c_sstoreResetGas = 100;
u256 const dev::eth::c_sstoreRefundGas = 100;
u256 const dev::eth::c_createGas = 100;
+u256 const dev::eth::c_createDataGas = 5;
u256 const dev::eth::c_callGas = 20;
u256 const dev::eth::c_expGas = 1;
u256 const dev::eth::c_expByteGas = 1;
diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h
index 3fb8175e6..8ef384265 100644
--- a/libevm/FeeStructure.h
+++ b/libevm/FeeStructure.h
@@ -31,11 +31,13 @@ namespace eth
extern u256 const c_stepGas; ///< Once per operation, except for SSTORE, SLOAD, BALANCE, SHA3, CREATE, CALL.
extern u256 const c_balanceGas; ///< Once per BALANCE operation.
extern u256 const c_sha3Gas; ///< Once per SHA3 operation.
+extern u256 const c_sha3WordGas;
extern u256 const c_sloadGas; ///< Once per SLOAD operation.
extern u256 const c_sstoreSetGas; ///< Once per SSTORE operation if the zeroness changes from zero.
extern u256 const c_sstoreResetGas; ///< Once per SSTORE operation if the zeroness doesn't change.
extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operation if the zeroness changes to zero.
extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction.
+extern u256 const c_createDataGas;
extern u256 const c_callGas; ///< Once per CALL operation & message call transaction.
extern u256 const c_expGas; ///< Once per EXP instuction.
extern u256 const c_expByteGas; ///< Times ceil(log256(exponent)) for the EXP instruction.
diff --git a/libevm/VM.cpp b/libevm/VM.cpp
index bded9a10d..b8452e4f5 100644
--- a/libevm/VM.cpp
+++ b/libevm/VM.cpp
@@ -20,14 +20,14 @@
*/
#include "VM.h"
+#include
-using namespace std;
using namespace dev;
using namespace dev::eth;
-void VM::reset(u256 _gas)
+void VM::reset(u256 _gas) noexcept
{
- m_gas = _gas;
+ VMFace::reset(_gas);
m_curPC = 0;
m_jumpDests.clear();
}
diff --git a/libevm/VM.h b/libevm/VM.h
index 2885deb3b..6f3229920 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -28,21 +28,13 @@
#include
#include
#include "FeeStructure.h"
-#include "ExtVMFace.h"
+#include "VMFace.h"
namespace dev
{
namespace eth
{
-struct VMException: virtual Exception {};
-struct StepsDone: virtual VMException {};
-struct BreakPointHit: virtual VMException {};
-struct BadInstruction: virtual VMException {};
-struct BadJumpDestination: virtual VMException {};
-struct OutOfGas: virtual VMException {};
-struct StackTooSmall: virtual public VMException {};
-
// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash.
// Currently we just pull out the right (low-order in BE) 160-bits.
inline Address asAddress(u256 _item)
@@ -57,28 +49,27 @@ inline u256 fromAddress(Address _a)
/**
*/
-class VM
+class VM: public VMFace
{
public:
- /// Construct VM object.
- explicit VM(u256 _gas = 0) { reset(_gas); }
-
- void reset(u256 _gas = 0);
+ virtual void reset(u256 _gas = 0) noexcept override final;
- template
- bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1);
+ virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
void require(u256 _n) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); } }
void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
- u256 gas() const { return m_gas; }
u256 curPC() const { return m_curPC; }
bytes const& memory() const { return m_temp; }
u256s const& stack() const { return m_stack; }
private:
- u256 m_gas = 0;
+ friend class VMFactory;
+
+ /// Construct VM object.
+ explicit VM(u256 _gas): VMFace(_gas) {}
+
u256 m_curPC = 0;
bytes m_temp;
u256s m_stack;
@@ -86,10 +77,8 @@ private:
std::function m_onFail;
};
-}
-
-// INLINE:
-template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps)
+// TODO: Move it to cpp file. Not done to make review easier.
+inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps)
{
auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; };
@@ -164,7 +153,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::SLOAD:
require(1);
- runGas = c_sloadGas;
+ runGas = c_sloadGas;
break;
// These all operate on memory and therefore potentially expand it:
@@ -186,7 +175,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
case Instruction::SHA3:
require(2);
- runGas = c_sha3Gas;
+ runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas;
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
break;
case Instruction::CALLDATACOPY:
@@ -412,7 +401,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.pop_back();
break;
case Instruction::SDIV:
- m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0;
+ m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0;
m_stack.pop_back();
break;
case Instruction::MOD:
@@ -420,7 +409,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.pop_back();
break;
case Instruction::SMOD:
- m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0;
+ m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0;
m_stack.pop_back();
break;
case Instruction::EXP:
@@ -443,11 +432,11 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.pop_back();
break;
case Instruction::SLT:
- m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0;
+ m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::SGT:
- m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0;
+ m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0;
m_stack.pop_back();
break;
case Instruction::EQ:
@@ -870,4 +859,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
BOOST_THROW_EXCEPTION(StepsDone());
return bytesConstRef();
}
+
+}
}
diff --git a/libevm/VMFace.h b/libevm/VMFace.h
new file mode 100644
index 000000000..44ae03868
--- /dev/null
+++ b/libevm/VMFace.h
@@ -0,0 +1,55 @@
+/*
+ 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 .
+*/
+#pragma once
+
+#include
+#include
+#include "ExtVMFace.h"
+
+namespace dev
+{
+namespace eth
+{
+
+struct VMException: virtual Exception {};
+struct StepsDone: virtual VMException {};
+struct BreakPointHit: virtual VMException {};
+struct BadInstruction: virtual VMException {};
+struct BadJumpDestination: virtual VMException {};
+struct OutOfGas: virtual VMException {};
+struct StackTooSmall: virtual VMException {};
+
+/// EVM Virtual Machine interface
+class VMFace
+{
+public:
+ explicit VMFace(u256 _gas): m_gas(_gas) {}
+ virtual ~VMFace() = default;
+ VMFace(VMFace const&) = delete;
+ void operator=(VMFace const&) = delete;
+
+ virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; }
+ u256 gas() const noexcept { return m_gas; }
+
+ virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0;
+
+protected:
+ u256 m_gas = 0;
+};
+
+}
+}
diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp
new file mode 100644
index 000000000..af37ec710
--- /dev/null
+++ b/libevm/VMFactory.cpp
@@ -0,0 +1,42 @@
+/*
+ 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 .
+*/
+
+#include "VMFactory.h"
+#include "VM.h"
+
+namespace dev
+{
+namespace eth
+{
+namespace
+{
+ VMKind g_kind = VMKind::Interpreter;
+}
+
+void VMFactory::setKind(VMKind _kind)
+{
+ g_kind = _kind;
+}
+
+std::unique_ptr VMFactory::create(u256 _gas)
+{
+ asserts(g_kind == VMKind::Interpreter && "Only interpreter supported for now");
+ return std::unique_ptr(new VM(_gas));
+}
+
+}
+}
diff --git a/libevm/VMFactory.h b/libevm/VMFactory.h
new file mode 100644
index 000000000..d0d02e0c4
--- /dev/null
+++ b/libevm/VMFactory.h
@@ -0,0 +1,42 @@
+/*
+ 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 .
+*/
+#pragma once
+
+#include "VMFace.h"
+
+namespace dev
+{
+namespace eth
+{
+
+enum class VMKind: bool
+{
+ Interpreter,
+ JIT
+};
+
+class VMFactory
+{
+public:
+ VMFactory() = delete;
+
+ static std::unique_ptr create(u256 _gas);
+ static void setKind(VMKind _kind);
+};
+
+}
+}
diff --git a/liblll/CompilerState.cpp b/liblll/CompilerState.cpp
index c3dc2dda3..63351bc4c 100644
--- a/liblll/CompilerState.cpp
+++ b/liblll/CompilerState.cpp
@@ -72,6 +72,11 @@ void CompilerState::populateStandard()
"(def 'regname (name) { [32]'register [64]name (call allgas namereg 0 32 64 0 0) })"
"(def 'regcoin (name) { [32]name (call allgas coinreg 0 32 32 0 0) })"
"(def 'regcoin (name denom) { [32]name [64]denom (call allgas coinreg 0 32 64 0 0) })"
+ "(def 'ecrecover (r s v hash) { [0] r [32] s [64] v [96] hash (msg allgas 1 0 0 128) })"
+ "(def 'sha256 (data datasize) (msg allgas 2 0 data datasize))"
+ "(def 'ripemd160 (data datasize) (msg allgas 3 0 data datasize))"
+ "(def 'sha256 (val) { [0]:val (sha256 0 32) })"
+ "(def 'ripemd160 (val) { [0]:val (ripemd160 0 32) })"
"}";
CodeFragment::compile(s, *this);
}
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index 974313418..258336917 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -130,21 +130,17 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b
{
// We do not check the calldata size, everything is zero-padded.
unsigned dataOffset = 1;
- eth::Instruction load = _fromMemory ? eth::Instruction::MLOAD : eth::Instruction::CALLDATALOAD;
//@todo this can be done more efficiently, saving some CALLDATALOAD calls
for (ASTPointer const& var: _function.getParameters())
{
unsigned const numBytes = var->getType()->getCalldataEncodedSize();
- if (numBytes == 0 || numBytes > 32)
+ if (numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(var->getLocation())
<< errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
- if (numBytes == 32)
- m_context << u256(dataOffset) << load;
- else
- m_context << (u256(1) << ((32 - numBytes) * 8)) << u256(dataOffset)
- << load << eth::Instruction::DIV;
+ bool leftAligned = var->getType()->getCategory() == Type::Category::STRING;
+ CompilerUtils(m_context).loadFromMemory(dataOffset, numBytes, leftAligned, !_fromMemory);
dataOffset += numBytes;
}
return dataOffset;
@@ -160,14 +156,13 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
{
Type const& paramType = *parameters[i]->getType();
unsigned numBytes = paramType.getCalldataEncodedSize();
- if (numBytes == 0 || numBytes > 32)
+ if (numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(parameters[i]->getLocation())
<< errinfo_comment("Type " + paramType.toString() + " not yet supported."));
CompilerUtils(m_context).copyToStackTop(stackDepth, paramType);
- if (numBytes != 32)
- m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
- m_context << u256(dataOffset) << eth::Instruction::MSTORE;
+ bool const leftAligned = paramType.getCategory() == Type::Category::STRING;
+ CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned);
stackDepth -= paramType.getSizeOnStack();
dataOffset += numBytes;
}
diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp
index d4dfbe3c0..9f474896e 100644
--- a/libsolidity/CompilerUtils.cpp
+++ b/libsolidity/CompilerUtils.cpp
@@ -31,6 +31,46 @@ namespace dev
namespace solidity
{
+void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, bool _fromCalldata)
+{
+ if (_bytes == 0)
+ {
+ m_context << u256(0);
+ return;
+ }
+ eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD;
+ if (asserts(_bytes <= 32))
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory load of more than 32 bytes requested."));
+ if (_bytes == 32)
+ m_context << u256(_offset) << load;
+ else
+ {
+ // load data and add leading or trailing zeros by dividing/multiplying depending on alignment
+ u256 shiftFactor = u256(1) << ((32 - _bytes) * 8);
+ m_context << shiftFactor;
+ if (_leftAligned)
+ m_context << eth::Instruction::DUP1;
+ m_context << u256(_offset) << load << eth::Instruction::DIV;
+ if (_leftAligned)
+ m_context << eth::Instruction::MUL;
+ }
+}
+
+void CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftAligned)
+{
+ if (_bytes == 0)
+ {
+ m_context << eth::Instruction::POP;
+ return;
+ }
+ if (asserts(_bytes <= 32))
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory store of more than 32 bytes requested."));
+ if (_bytes != 32 && !_leftAligned)
+ // shift the value accordingly before storing
+ m_context << (u256(1) << ((32 - _bytes) * 8)) << eth::Instruction::MUL;
+ m_context << u256(_offset) << eth::Instruction::MSTORE;
+}
+
void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
{
unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable));
diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h
index 4da533752..928f0e2d3 100644
--- a/libsolidity/CompilerUtils.h
+++ b/libsolidity/CompilerUtils.h
@@ -35,6 +35,18 @@ class CompilerUtils
public:
CompilerUtils(CompilerContext& _context): m_context(_context) {}
+ /// Loads data from memory to the stack.
+ /// @param _offset offset in memory (or calldata)
+ /// @param _bytes number of bytes to load
+ /// @param _leftAligned if true, store left aligned on stack (otherwise right aligned)
+ /// @param _fromCalldata if true, load from calldata, not from memory
+ void loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, bool _fromCalldata = false);
+ /// Stores data from stack in memory.
+ /// @param _offset offset in memory
+ /// @param _bytes number of bytes to store
+ /// @param _leftAligned if true, data is left aligned on stack (otherwise right aligned)
+ void storeInMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false);
+
/// Moves the value that is at the top of the stack to a stack variable.
void moveToStackVariable(VariableDeclaration const& _variable);
/// Copies a variable of type @a _type from a stack depth of @a _stackDepth to the top of the stack.
diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp
index a19c9cfd8..3beb423de 100644
--- a/libsolidity/ExpressionCompiler.cpp
+++ b/libsolidity/ExpressionCompiler.cpp
@@ -239,14 +239,14 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(arguments[i]->getLocation())
<< errinfo_comment("Type " + type.toString() + " not yet supported."));
- if (numBytes != 32)
- m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
- m_context << u256(dataOffset) << eth::Instruction::MSTORE;
+ bool const leftAligned = type.getCategory() == Type::Category::STRING;
+ CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned);
dataOffset += numBytes;
}
//@todo only return the first return value for now
- unsigned retSize = function.getReturnParameterTypes().empty() ? 0
- : function.getReturnParameterTypes().front()->getCalldataEncodedSize();
+ Type const* firstType = function.getReturnParameterTypes().empty() ? nullptr :
+ function.getReturnParameterTypes().front().get();
+ unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
// CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top)
m_context << u256(retSize) << u256(0) << u256(dataOffset) << u256(0) << u256(0);
_functionCall.getExpression().accept(*this); // pushes addr and function index
@@ -254,11 +254,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
<< u256(25) << eth::Instruction::GAS << eth::Instruction::SUB
<< eth::Instruction::CALL
<< eth::Instruction::POP; // @todo do not ignore failure indicator
- if (retSize == 32)
- m_context << u256(0) << eth::Instruction::MLOAD;
- else if (retSize > 0)
- m_context << (u256(1) << ((32 - retSize) * 8))
- << u256(0) << eth::Instruction::MLOAD << eth::Instruction::DIV;
+ if (retSize > 0)
+ {
+ bool const leftAligned = firstType->getCategory() == Type::Category::STRING;
+ CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned);
+ }
break;
}
case Location::SEND:
@@ -281,7 +281,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arguments.front()->accept(*this);
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true);
// @todo move this once we actually use memory
- m_context << u256(0) << eth::Instruction::MSTORE << u256(32) << u256(0) << eth::Instruction::SHA3;
+ CompilerUtils(m_context).storeInMemory(0);
+ m_context << u256(32) << u256(0) << eth::Instruction::SHA3;
break;
case Location::ECRECOVER:
case Location::SHA256:
@@ -297,13 +298,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arguments[i]->accept(*this);
appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i], true);
// @todo move this once we actually use memory
- m_context << u256(i * 32) << eth::Instruction::MSTORE;
+ CompilerUtils(m_context).storeInMemory(i * 32);
}
m_context << u256(32) << u256(0) << u256(arguments.size() * 32) << u256(0) << u256(0)
<< contractAddress << u256(500) //@todo determine actual gas requirement
<< eth::Instruction::CALL
- << eth::Instruction::POP
- << u256(0) << eth::Instruction::MLOAD;
+ << eth::Instruction::POP;
+ CompilerUtils(m_context).loadFromMemory(0);
break;
}
default:
@@ -387,7 +388,8 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
*dynamic_cast(*_indexAccess.getBaseExpression().getType()).getKeyType(),
true);
// @todo move this once we actually use memory
- m_context << u256(32) << eth::Instruction::MSTORE << u256(0) << eth::Instruction::MSTORE;
+ CompilerUtils(m_context).storeInMemory(0);
+ CompilerUtils(m_context).storeInMemory(32);
m_context << u256(64) << u256(0) << eth::Instruction::SHA3;
m_currentLValue = LValue(m_context, LValue::STORAGE, *_indexAccess.getType());
@@ -425,10 +427,11 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
{
case Type::Category::INTEGER:
case Type::Category::BOOL:
+ case Type::Category::STRING:
m_context << _literal.getType()->literalValue(_literal);
break;
default:
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer and boolean literals implemented for now."));
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now."));
}
}
@@ -564,6 +567,11 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
return;
if (_typeOnStack.getCategory() == Type::Category::INTEGER)
appendHighBitsCleanup(dynamic_cast(_typeOnStack));
+ else if (_typeOnStack.getCategory() == Type::Category::STRING)
+ {
+ // nothing to do, strings are high-order-bit-aligned
+ //@todo clear lower-order bytes if we allow explicit conversion to shorter strings
+ }
else if (_typeOnStack != _targetType)
// All other types should not be convertible to non-equal types.
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested."));
diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h
index fb4577c8c..c0b173d46 100644
--- a/libsolidity/ExpressionCompiler.h
+++ b/libsolidity/ExpressionCompiler.h
@@ -35,6 +35,7 @@ namespace solidity {
class CompilerContext;
class Type;
class IntegerType;
+class StaticStringType;
/**
* Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream
@@ -75,7 +76,7 @@ private:
/// @}
/// Appends an implicit or explicit type conversion. For now this comprises only erasing
- /// higher-order bits (@see appendHighBitCleanup) when widening integer types.
+ /// higher-order bits (@see appendHighBitCleanup) when widening integer.
/// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be
/// necessary.
void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false);
diff --git a/libsolidity/Token.h b/libsolidity/Token.h
index c748d9892..51450f1a2 100644
--- a/libsolidity/Token.h
+++ b/libsolidity/Token.h
@@ -269,6 +269,39 @@ namespace solidity
K(ADDRESS, "address", 0) \
K(BOOL, "bool", 0) \
K(STRING_TYPE, "string", 0) \
+ K(STRING0, "string0", 0) \
+ K(STRING1, "string1", 0) \
+ K(STRING2, "string2", 0) \
+ K(STRING3, "string3", 0) \
+ K(STRING4, "string4", 0) \
+ K(STRING5, "string5", 0) \
+ K(STRING6, "string6", 0) \
+ K(STRING7, "string7", 0) \
+ K(STRING8, "string8", 0) \
+ K(STRING9, "string9", 0) \
+ K(STRING10, "string10", 0) \
+ K(STRING11, "string11", 0) \
+ K(STRING12, "string12", 0) \
+ K(STRING13, "string13", 0) \
+ K(STRING14, "string14", 0) \
+ K(STRING15, "string15", 0) \
+ K(STRING16, "string16", 0) \
+ K(STRING17, "string17", 0) \
+ K(STRING18, "string18", 0) \
+ K(STRING19, "string19", 0) \
+ K(STRING20, "string20", 0) \
+ K(STRING21, "string21", 0) \
+ K(STRING22, "string22", 0) \
+ K(STRING23, "string23", 0) \
+ K(STRING24, "string24", 0) \
+ K(STRING25, "string25", 0) \
+ K(STRING26, "string26", 0) \
+ K(STRING27, "string27", 0) \
+ K(STRING28, "string28", 0) \
+ K(STRING29, "string29", 0) \
+ K(STRING30, "string30", 0) \
+ K(STRING31, "string31", 0) \
+ K(STRING32, "string32", 0) \
K(TEXT, "text", 0) \
K(REAL, "real", 0) \
K(UREAL, "ureal", 0) \
diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp
index 6c971a742..00e530c3f 100644
--- a/libsolidity/Types.cpp
+++ b/libsolidity/Types.cpp
@@ -53,6 +53,8 @@ shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken)
return make_shared(0, IntegerType::Modifier::ADDRESS);
else if (_typeToken == Token::BOOL)
return make_shared();
+ else if (Token::STRING0 <= _typeToken && _typeToken <= Token::STRING32)
+ return make_shared(int(_typeToken) - int(Token::STRING0));
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
std::string(Token::toString(_typeToken)) + " to type."));
@@ -91,7 +93,8 @@ shared_ptr Type::forLiteral(Literal const& _literal)
case Token::NUMBER:
return IntegerType::smallestTypeForLiteral(_literal.getValue());
case Token::STRING_LITERAL:
- return shared_ptr(); // @todo add string literals
+ //@todo put larger strings into dynamic strings
+ return StaticStringType::smallestTypeForLiteral(_literal.getValue());
default:
return shared_ptr();
}
@@ -194,6 +197,44 @@ const MemberList IntegerType::AddressMemberList =
{"send", make_shared(TypePointers({make_shared(256)}),
TypePointers(), FunctionType::Location::SEND)}});
+shared_ptr StaticStringType::smallestTypeForLiteral(string const& _literal)
+{
+ if (_literal.length() <= 32)
+ return make_shared(_literal.length());
+ return shared_ptr();
+}
+
+StaticStringType::StaticStringType(int _bytes): m_bytes(_bytes)
+{
+ if (asserts(m_bytes >= 0 && m_bytes <= 32))
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid byte number for static string type: " +
+ dev::toString(m_bytes)));
+}
+
+bool StaticStringType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ if (_convertTo.getCategory() != getCategory())
+ return false;
+ StaticStringType const& convertTo = dynamic_cast(_convertTo);
+ return convertTo.m_bytes >= m_bytes;
+}
+
+bool StaticStringType::operator==(Type const& _other) const
+{
+ if (_other.getCategory() != getCategory())
+ return false;
+ StaticStringType const& other = dynamic_cast(_other);
+ return other.m_bytes == m_bytes;
+}
+
+u256 StaticStringType::literalValue(const Literal& _literal) const
+{
+ u256 value = 0;
+ for (char c: _literal.getValue())
+ value = (value << 8) | byte(c);
+ return value << ((32 - _literal.getValue().length()) * 8);
+}
+
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
// conversion to integer is fine, but not to address
diff --git a/libsolidity/Types.h b/libsolidity/Types.h
index dd89f311d..8e93bd31d 100644
--- a/libsolidity/Types.h
+++ b/libsolidity/Types.h
@@ -36,7 +36,7 @@ namespace dev
namespace solidity
{
-// @todo realMxN, string
+// @todo realMxN, dynamic strings, text, arrays
class Type; // forward
using TypePointer = std::shared_ptr;
@@ -178,6 +178,35 @@ private:
static const MemberList AddressMemberList;
};
+/**
+ * String type with fixed length, up to 32 bytes.
+ */
+class StaticStringType: public Type
+{
+public:
+ virtual Category getCategory() const override { return Category::STRING; }
+
+ /// @returns the smallest string type for the given literal or an empty pointer
+ /// if no type fits.
+ static std::shared_ptr smallestTypeForLiteral(std::string const& _literal);
+
+ StaticStringType(int _bytes);
+
+ virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual bool operator==(Type const& _other) const override;
+
+ virtual unsigned getCalldataEncodedSize() const override { return m_bytes; }
+ virtual bool isValueType() const override { return true; }
+
+ virtual std::string toString() const override { return "string" + dev::toString(m_bytes); }
+ virtual u256 literalValue(Literal const& _literal) const override;
+
+ int getNumBytes() const { return m_bytes; }
+
+private:
+ int m_bytes;
+};
+
/**
* The boolean type.
*/
diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp
index 0d54af089..afeca48a8 100644
--- a/libwhisper/Common.cpp
+++ b/libwhisper/Common.cpp
@@ -54,10 +54,16 @@ bool TopicFilter::matches(Envelope const& _e) const
{
for (TopicMask const& t: m_topicMasks)
{
- if (_e.topics().size() == t.size())
- for (unsigned i = 0; i < t.size(); ++i)
- if (((t[i].first ^ _e.topics()[i]) & t[i].second) != 0)
- goto NEXT_TOPICMASK;
+ for (unsigned i = 0; i < t.size(); ++i)
+ {
+ for (auto et: _e.topics())
+ if (((t[i].first ^ et) & t[i].second) == 0)
+ goto NEXT_TOPICPART;
+ // failed to match topicmask against any topics: move on to next mask
+ goto NEXT_TOPICMASK;
+ NEXT_TOPICPART:;
+ }
+ // all topicmasks matched.
return true;
NEXT_TOPICMASK:;
}
diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp
index caeeb6b67..a11688457 100644
--- a/test/createRandomTest.cpp
+++ b/test/createRandomTest.cpp
@@ -32,7 +32,7 @@
#include
#include
#include
-#include
+#include
#include "vm.h"
using namespace std;
@@ -142,14 +142,14 @@ void doMyTests(json_spirit::mValue& v)
}
bytes output;
- eth::VM vm(fev.gas);
+ auto vm = eth::VMFactory::create(fev.gas);
u256 gas;
bool vmExceptionOccured = false;
try
{
- output = vm.go(fev, fev.simpleTrace()).toBytes();
- gas = vm.gas();
+ output = vm->go(fev, fev.simpleTrace()).toBytes();
+ gas = vm->gas();
}
catch (eth::VMException const& _e)
{
diff --git a/test/genesis.cpp b/test/genesis.cpp
index 6839d42e2..2cd9221a8 100644
--- a/test/genesis.cpp
+++ b/test/genesis.cpp
@@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests)
BOOST_CHECK_EQUAL(BlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str()));
BOOST_CHECK_EQUAL(toHex(BlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str())));
- BOOST_CHECK_EQUAL(sha3(BlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str()));
+ BOOST_CHECK_EQUAL(BlockInfo::headerHash(BlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str()));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/jsonrpc.cpp b/test/jsonrpc.cpp
index d17c5a594..20ffc6d54 100644
--- a/test/jsonrpc.cpp
+++ b/test/jsonrpc.cpp
@@ -19,7 +19,7 @@
* @date 2014
*/
-#if ETH_JSONRPC
+#if ETH_JSONRPC && 0
#include
#include
diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp
index 3c77492a5..af8b58baa 100644
--- a/test/solidityEndToEndTest.cpp
+++ b/test/solidityEndToEndTest.cpp
@@ -363,6 +363,48 @@ BOOST_AUTO_TEST_CASE(small_signed_types)
testSolidityAgainstCpp(0, small_signed_types_cpp);
}
+BOOST_AUTO_TEST_CASE(strings)
+{
+ char const* sourceCode = "contract test {\n"
+ " function fixed() returns(string32 ret) {\n"
+ " return \"abc\\x00\\xff__\";\n"
+ " }\n"
+ " function pipeThrough(string2 small, bool one) returns(string16 large, bool oneRet) {\n"
+ " oneRet = one;\n"
+ " large = small;\n"
+ " }\n"
+ "}\n";
+ compileAndRun(sourceCode);
+ bytes expectation(32, 0);
+ expectation[0] = byte('a');
+ expectation[1] = byte('b');
+ expectation[2] = byte('c');
+ expectation[3] = byte(0);
+ expectation[4] = byte(0xff);
+ expectation[5] = byte('_');
+ expectation[6] = byte('_');
+ BOOST_CHECK(callContractFunction(0, bytes()) == expectation);
+ expectation = bytes(17, 0);
+ expectation[0] = 0;
+ expectation[1] = 2;
+ expectation[16] = 1;
+ BOOST_CHECK(callContractFunction(1, bytes({0x00, 0x02, 0x01})) == expectation);
+}
+
+BOOST_AUTO_TEST_CASE(empty_string_on_stack)
+{
+ char const* sourceCode = "contract test {\n"
+ " function run(string0 empty, uint8 inp) returns(uint16 a, string0 b, string4 c) {\n"
+ " var x = \"abc\";\n"
+ " var y = \"\";\n"
+ " var z = inp;\n"
+ " a = z; b = y; c = x;"
+ " }\n"
+ "}\n";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction(0, bytes({0x02})) == bytes({0x00, 0x02, 'a', 'b', 'c', 0x00}));
+}
+
BOOST_AUTO_TEST_CASE(state_smoke_test)
{
char const* sourceCode = "contract test {\n"
@@ -941,6 +983,34 @@ BOOST_AUTO_TEST_CASE(inter_contract_calls_with_local_vars)
BOOST_REQUIRE(callContractFunction(0, a, b) == toBigEndian(a * b + 9));
}
+BOOST_AUTO_TEST_CASE(strings_in_calls)
+{
+ char const* sourceCode = R"(
+ contract Helper {
+ function invoke(string3 x, bool stop) returns (string4 ret) {
+ return x;
+ }
+ }
+ contract Main {
+ Helper h;
+ function callHelper(string2 x, bool stop) returns (string5 ret) {
+ return h.invoke(x, stop);
+ }
+ function getHelper() returns (address addr) {
+ return address(h);
+ }
+ function setHelper(address addr) {
+ h = Helper(addr);
+ }
+ })";
+ compileAndRun(sourceCode, 0, "Helper");
+ u160 const helperAddress = m_contractAddress;
+ compileAndRun(sourceCode, 0, "Main");
+ BOOST_REQUIRE(callContractFunction(2, helperAddress) == bytes());
+ BOOST_REQUIRE(callContractFunction(1, helperAddress) == toBigEndian(helperAddress));
+ BOOST_CHECK(callContractFunction(0, bytes({0, 'a', 1})) == bytes({0, 'a', 0, 0, 0}));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp
index 783972296..03eaebb3a 100644
--- a/test/solidityNameAndTypeResolution.cpp
+++ b/test/solidityNameAndTypeResolution.cpp
@@ -226,6 +226,14 @@ BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion)
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
+BOOST_AUTO_TEST_CASE(large_string_literal)
+{
+ char const* text = "contract test {\n"
+ " function f() { var x = \"123456789012345678901234567890123\"; }"
+ "}\n";
+ BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+}
+
BOOST_AUTO_TEST_CASE(balance)
{
char const* text = "contract test {\n"
diff --git a/test/solidityOptimizerTest.cpp b/test/solidityOptimizerTest.cpp
index 69000a57f..388e0579c 100644
--- a/test/solidityOptimizerTest.cpp
+++ b/test/solidityOptimizerTest.cpp
@@ -48,7 +48,7 @@ public:
m_optimize = true;
bytes optimizedBytecode = compileAndRun(_sourceCode, _value, _contractName);
int sizeDiff = nonOptimizedBytecode.size() - optimizedBytecode.size();
- BOOST_CHECK_MESSAGE(sizeDiff == _expectedSizeDecrease, "Bytecode did only shrink by "
+ BOOST_CHECK_MESSAGE(sizeDiff == int(_expectedSizeDecrease), "Bytecode did only shrink by "
+ boost::lexical_cast(sizeDiff) + " bytes, expected: "
+ boost::lexical_cast(_expectedSizeDecrease));
m_optimizedContract = m_contractAddress;
diff --git a/test/trie.cpp b/test/trie.cpp
index 67f706917..3f072a6d1 100644
--- a/test/trie.cpp
+++ b/test/trie.cpp
@@ -59,8 +59,8 @@ BOOST_AUTO_TEST_CASE(trie_tests)
cnote << "Testing Trie...";
js::mValue v;
- string s = asString(contents(testPath + "/trietest.json"));
- BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?");
+ string s = asString(contents(testPath + "/trieanyorder.json"));
+ BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trieanyorder.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);
for (auto& i: v.get_obj())
{
@@ -88,12 +88,11 @@ BOOST_AUTO_TEST_CASE(trie_tests)
BOOST_REQUIRE(t.check(true));
}
BOOST_REQUIRE(!o["root"].is_null());
- BOOST_CHECK_EQUAL(o["root"].get_str(), toHex(t.root().asArray()));
+ BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray()));
}
}
}
-
inline h256 stringMapHash256(StringMap const& _s)
{
return hash256(_s);
diff --git a/test/vm.cpp b/test/vm.cpp
index 5c270f789..d8e85383c 100644
--- a/test/vm.cpp
+++ b/test/vm.cpp
@@ -21,6 +21,8 @@
*/
#include
+#include
+#include
#include "vm.h"
using namespace std;
@@ -241,10 +243,11 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
eth::OnOpFunc FakeExtVM::simpleTrace()
{
- return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt)
+
+ return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, dev::eth::VM* voidVM, dev::eth::ExtVMFace const* voidExt)
{
- FakeExtVM const& ext = *(FakeExtVM const*)voidExt;
- eth::VM& vm = *(eth::VM*)voidVM;
+ FakeExtVM const& ext = *static_cast(voidExt);
+ eth::VM& vm = *voidVM;
std::ostringstream o;
o << std::endl << " STACK" << std::endl;
@@ -297,14 +300,14 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
}
bytes output;
- VM vm(fev.gas);
+ auto vm = eth::VMFactory::create(fev.gas);
u256 gas;
bool vmExceptionOccured = false;
try
{
- output = vm.go(fev, fev.simpleTrace()).toBytes();
- gas = vm.gas();
+ output = vm->go(fev, fev.simpleTrace()).toBytes();
+ gas = vm->gas();
}
catch (VMException const& _e)
{
diff --git a/test/vm.h b/test/vm.h
index a52a02e31..3d4b88d54 100644
--- a/test/vm.h
+++ b/test/vm.h
@@ -80,9 +80,6 @@ public:
bytes thisTxData;
bytes thisTxCode;
u256 gas;
-
-private:
- eth::Manifest m_ms;
};
diff --git a/test/whisperTopic.cpp b/test/whisperTopic.cpp
index 493b37bc2..c5e59332d 100644
--- a/test/whisperTopic.cpp
+++ b/test/whisperTopic.cpp
@@ -32,7 +32,8 @@ BOOST_AUTO_TEST_SUITE(whisper)
BOOST_AUTO_TEST_CASE(topic)
{
- g_logVerbosity = 0;
+ cnote << "Testing Whisper...";
+// g_logVerbosity = 0;
bool started = false;
unsigned result = 0;
@@ -40,16 +41,16 @@ BOOST_AUTO_TEST_CASE(topic)
{
setThreadName("other");
- Host ph("Test", NetworkPreferences(30303, "", false, true));
+ Host ph("Test", NetworkPreferences(50303, "", false, true));
auto wh = ph.registerCapability(new WhisperHost());
ph.start();
started = true;
/// Only interested in odd packets
- auto w = wh->installWatch(BuildTopicMask()("odd"));
+ auto w = wh->installWatch(BuildTopicMask("odd"));
- for (int i = 0, last = 0; i < 100 && last < 81; ++i)
+ for (int i = 0, last = 0; i < 200 && last < 81; ++i)
{
for (auto i: wh->checkWatch(w))
{
@@ -65,10 +66,12 @@ BOOST_AUTO_TEST_CASE(topic)
while (!started)
this_thread::sleep_for(chrono::milliseconds(50));
- Host ph("Test", NetworkPreferences(30300, "", false, true));
+ Host ph("Test", NetworkPreferences(50300, "", false, true));
auto wh = ph.registerCapability(new WhisperHost());
+ this_thread::sleep_for(chrono::milliseconds(500));
ph.start();
- ph.connect("127.0.0.1", 30303);
+ this_thread::sleep_for(chrono::milliseconds(500));
+ ph.connect("127.0.0.1", 50303);
KeyPair us = KeyPair::create();
for (int i = 0; i < 10; ++i)
@@ -78,6 +81,8 @@ BOOST_AUTO_TEST_CASE(topic)
}
listener.join();
+// g_logVerbosity = 0;
+
BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81);
}
diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj
index 06f868023..cbacd51b5 100644
--- a/windows/LibEthereum.vcxproj
+++ b/windows/LibEthereum.vcxproj
@@ -368,6 +368,7 @@
true
true
+
@@ -568,4 +569,4 @@
-
+
\ No newline at end of file
diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters
index 114364008..76201d823 100644
--- a/windows/LibEthereum.vcxproj.filters
+++ b/windows/LibEthereum.vcxproj.filters
@@ -190,18 +190,14 @@
libdevcrypto
-
- libdevcrypto
-
-
- libdevcrypto
-
libethereum
libevmcore
+
+
@@ -438,6 +434,9 @@
libevmcore
+
+ libevm
+