diff --git a/.gitignore b/.gitignore
index c18d5a01d..6fde7ca22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,3 +64,5 @@ profile
DerivedData
project.pbxproj
+
+evmjit
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index e25db4137..dbcd0f493 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -106,6 +106,8 @@ static QString contentsOfQResource(std::string const& res)
}
Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f");
+Address c_newConfig = Address("d5f9d8d94886e70b06e474c3fb14fd43e2f23970");
+Address c_nameReg = Address("ddd1cea741d548f90d86fb87a3ae6492e18c03a1");
Main::Main(QWidget *parent) :
QMainWindow(parent),
@@ -448,8 +450,29 @@ static Public stringToPublic(QString const& _a)
return Public();
}
+static Address g_newNameReg;
+
QString Main::pretty(dev::Address _a) const
{
+ static std::map
s_memos;
+
+ if (!s_memos.count(_a))
+ {
+ if (!g_newNameReg)
+ g_newNameReg = abiOut(ethereum()->call(c_newConfig, abiIn(1, (u256)1)));
+
+ if (g_newNameReg)
+ {
+ QString s = QString::fromStdString(toString(abiOut(ethereum()->call(g_newNameReg, abiIn(2, _a)))));
+ s_memos[_a] = s;
+ if (s.size())
+ return s;
+ }
+ }
+ else
+ if (s_memos[_a].size())
+ return s_memos[_a];
+
h256 n;
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
@@ -469,19 +492,47 @@ QString Main::render(dev::Address _a) const
return QString::fromStdString(_a.abridged());
}
-Address Main::fromString(QString const& _a) const
+string32 fromString(std::string const& _s)
+{
+ string32 ret;
+ for (unsigned i = 0; i < 32 && i <= _s.size(); ++i)
+ ret[i] = i < _s.size() ? _s[i] : 0;
+ return ret;
+}
+
+Address Main::fromString(QString const& _n) const
{
- if (_a == "(Create Contract)")
+ if (_n == "(Create Contract)")
return Address();
- string sn = _a.toStdString();
+ static std::map s_memos;
+
+ if (!s_memos.count(_n))
+ {
+ if (!g_newNameReg)
+ g_newNameReg = abiOut(ethereum()->call(c_newConfig, abiIn(1, (u256)1)));
+
+ if (g_newNameReg)
+ {
+ Address a = abiOut(ethereum()->call(g_newNameReg, abiIn(0, ::fromString(_n.toStdString()))));
+ s_memos[_n] = a;
+ if (a)
+ return a;
+ }
+ }
+ else
+ if (s_memos[_n])
+ return s_memos[_n];
+
+ string sn = _n.toStdString();
if (sn.size() > 32)
sn.resize(32);
h256 n;
memcpy(n.data(), sn.data(), sn.size());
memset(n.data() + sn.size(), 0, 32 - sn.size());
- if (_a.size())
+ if (_n.size())
{
+
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a);
@@ -489,8 +540,9 @@ Address Main::fromString(QString const& _a) const
if (h256 a = ethereum()->stateAt(m_nameReg, n))
return right160(a);
}
- if (_a.size() == 40)
- return Address(fromHex(_a.toStdString()));
+
+ if (_n.size() == 40)
+ return Address(fromHex(_n.toStdString()));
else
return Address();
}
@@ -1350,7 +1402,7 @@ void Main::on_debugCurrent_triggered()
{
unsigned txi = item->data(Qt::UserRole + 1).toInt();
m_executiveState = ethereum()->state(txi + 1, h);
- m_currentExecution = unique_ptr(new Executive(m_executiveState, 0));
+ m_currentExecution = unique_ptr(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = m_executiveState.pending()[txi];
m_executiveState = m_executiveState.fromPending(txi);
auto r = t.rlp();
@@ -1803,7 +1855,7 @@ void Main::on_debug_clicked()
{
Secret s = i.secret();
m_executiveState = ethereum()->postState();
- m_currentExecution = unique_ptr(new Executive(m_executiveState, 0));
+ m_currentExecution = unique_ptr(new Executive(m_executiveState, ethereum()->blockChain(), 0));
Transaction t = isCreation() ?
Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) :
Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s);
diff --git a/eth/main.cpp b/eth/main.cpp
index 1520e86c4..d55766cfd 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -89,6 +89,7 @@ void interactiveHelp()
<< " importConfig Import the config (.RLP) from the path provided." < Dumps a contract to /.evm." << endl
<< " dumptrace Dumps a transaction trace" << endl << "to . should be one of pretty, standard, standard+." << endl
+ << " dumpreceipt Dumps a transation receipt." << endl
<< " exit Exits the application." << endl;
}
@@ -606,6 +607,17 @@ int main(int argc, char** argv)
else
cwarn << "Require parameters: contract ENDOWMENT GASPRICE GAS CODEHEX";
}
+ else if (c && cmd == "dumpreceipt")
+ {
+ unsigned block;
+ unsigned index;
+ iss >> block >> index;
+ dev::eth::TransactionReceipt r = c->blockChain().receipts(c->blockChain().numberHash(block)).receipts[index];
+ auto rb = r.rlp();
+ cout << "RLP: " << RLP(rb) << endl;
+ cout << "Hex: " << toHex(rb) << endl;
+ cout << r << endl;
+ }
else if (c && cmd == "dumptrace")
{
unsigned block;
@@ -619,7 +631,7 @@ int main(int argc, char** argv)
dev::eth::State state =c->state(index + 1,c->blockChain().numberHash(block));
if (index < state.pending().size())
{
- Executive e(state, 0);
+ Executive e(state, c->blockChain(), 0);
Transaction t = state.pending()[index];
state = state.fromPending(index);
bytes r = t.rlp();
diff --git a/exp/main.cpp b/exp/main.cpp
index 27707decb..e714f29da 100644
--- a/exp/main.cpp
+++ b/exp/main.cpp
@@ -21,13 +21,13 @@
*/
#include
#include
+#include
#include
#include
#include
#include
#include
#include
-#include
#include
#include
#include
@@ -91,7 +91,7 @@ int main()
Transaction t(0, 10000, 10000, c, bytes(), 0, u.secret());
cnote << "Transaction: " << t;
cnote << s.balance(c);
- s.execute(t.rlp());
+ s.execute(LastHashes(), t.rlp());
cnote << "State after transaction: " << s;
cnote << before.diff(s);
}
diff --git a/libdevcore/Common.h b/libdevcore/Common.h
index 198119f24..11bee7aa5 100644
--- a/libdevcore/Common.h
+++ b/libdevcore/Common.h
@@ -74,6 +74,9 @@ using StringMap = std::map;
using u256Map = std::map;
using HexMap = std::map;
+// Fixed-length string types.
+using string32 = std::array;
+
// Null/Invalid values for convenience.
static const u256 Invalid256 = ~(u256)0;
static const bytes NullBytes;
diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp
index fc3910cfe..b3abe4300 100644
--- a/libdevcore/CommonData.cpp
+++ b/libdevcore/CommonData.cpp
@@ -123,180 +123,10 @@ bytes dev::asNibbles(std::string const& _s)
return ret;
}
-#if 0
-
-/* Following code is copyright 2012-2014 Luke Dashjr
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the standard MIT license. See COPYING for more details.
- */
-
-#include
-#include
-#include
-#include
-
-static const int8_t b58digits_map[] = {
- -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
- -1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
- 22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
- -1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
- 47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
-};
-
-bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
-{
- size_t binsz = *binszp;
- const unsigned char *b58u = (void*)b58;
- unsigned char *binu = bin;
- size_t outisz = (binsz + 3) / 4;
- uint32_t outi[outisz];
- uint64_t t;
- uint32_t c;
- size_t i, j;
- uint8_t bytesleft = binsz % 4;
- uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0;
- unsigned zerocount = 0;
-
- if (!b58sz)
- b58sz = strlen(b58);
-
- memset(outi, 0, outisz * sizeof(*outi));
-
- // Leading zeros, just count
- for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i)
- ++zerocount;
-
- for ( ; i < b58sz; ++i)
- {
- if (b58u[i] & 0x80)
- // High-bit set on invalid digit
- return false;
- if (b58digits_map[b58u[i]] == -1)
- // Invalid base58 digit
- return false;
- c = (unsigned)b58digits_map[b58u[i]];
- for (j = outisz; j--; )
- {
- t = ((uint64_t)outi[j]) * 58 + c;
- c = (t & 0x3f00000000) >> 32;
- outi[j] = t & 0xffffffff;
- }
- if (c)
- // Output number too big (carry to the next int32)
- return false;
- if (outi[0] & zeromask)
- // Output number too big (last int32 filled too far)
- return false;
- }
-
- j = 0;
- switch (bytesleft) {
- case 3:
- *(binu++) = (outi[0] & 0xff0000) >> 16;
- case 2:
- *(binu++) = (outi[0] & 0xff00) >> 8;
- case 1:
- *(binu++) = (outi[0] & 0xff);
- ++j;
- default:
- break;
- }
-
- for (; j < outisz; ++j)
- {
- *(binu++) = (outi[j] >> 0x18) & 0xff;
- *(binu++) = (outi[j] >> 0x10) & 0xff;
- *(binu++) = (outi[j] >> 8) & 0xff;
- *(binu++) = (outi[j] >> 0) & 0xff;
- }
-
- // Count canonical base58 byte count
- binu = bin;
- for (i = 0; i < binsz; ++i)
- {
- if (binu[i])
- break;
- --*binszp;
- }
- *binszp += zerocount;
-
- return true;
-}
-
-static
-bool my_dblsha256(void *hash, const void *data, size_t datasz)
+std::string dev::toString(string32 const& _s)
{
- uint8_t buf[0x20];
- return b58_sha256_impl(buf, data, datasz) && b58_sha256_impl(hash, buf, sizeof(buf));
-}
-
-int b58check(const void *bin, size_t binsz, const char *base58str, size_t b58sz)
-{
- unsigned char buf[32];
- const uint8_t *binc = bin;
- unsigned i;
- if (binsz < 4)
- return -4;
- if (!my_dblsha256(buf, bin, binsz - 4))
- return -2;
- if (memcmp(&binc[binsz - 4], buf, 4))
- return -1;
-
- // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
- for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
- {} // Just finding the end of zeros, nothing to do in loop
- if (binc[i] == '\0' || base58str[i] == '1')
- return -3;
-
- return binc[0];
-}
-
-static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
-
-bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
-{
- const uint8_t *bin = data;
- int carry;
- size_t i, j, high, zcount = 0;
- size_t size;
-
- while (zcount < binsz && !bin[zcount])
- ++zcount;
-
- size = (binsz - zcount) * 138 / 100 + 1;
- uint8_t buf[size];
- memset(buf, 0, size);
-
- for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
- {
- for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
- {
- carry += 256 * buf[j];
- buf[j] = carry % 58;
- carry /= 58;
- }
- }
-
- for (j = 0; j < size && !buf[j]; ++j);
-
- if (*b58sz <= zcount + size - j)
- {
- *b58sz = zcount + size - j + 1;
- return false;
- }
-
- if (zcount)
- memset(b58, '1', zcount);
- for (i = zcount; j < size; ++i, ++j)
- b58[i] = b58digits_ordered[buf[j]];
- b58[i] = '\0';
- *b58sz = i + 1;
-
- return true;
+ std::string ret;
+ for (unsigned i = 0; i < 32 && _s[i]; ++i)
+ ret.push_back(_s[i]);
+ return ret;
}
-
-#endif
diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h
index 87d2f5e28..6fab67452 100644
--- a/libdevcore/CommonData.h
+++ b/libdevcore/CommonData.h
@@ -236,4 +236,7 @@ inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b)
return ret += _b;
}
+/// Make normal string from fixed-length string.
+std::string toString(string32 const& _s);
+
}
diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h
index db46d62f6..2771c739a 100644
--- a/libdevcore/vector_ref.h
+++ b/libdevcore/vector_ref.h
@@ -41,6 +41,7 @@ public:
void retarget(_T const* _d, size_t _s) { m_data = _d; m_count = _s; }
void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); }
void copyTo(vector_ref::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
+ void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }
_T* begin() { return m_data; }
_T* end() { return m_data + m_count; }
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index e3346754b..d8967c084 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -27,6 +27,7 @@
#include
#include
#include "Defaults.h"
+#include "Executive.h"
#include "EthereumHost.h"
using namespace std;
using namespace dev;
@@ -343,7 +344,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
n = temp.transactionsFrom(toAddress(_secret));
}
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
- u256 gasUsed = temp.execute(t.rlp(), &out, false);
+ u256 gasUsed = temp.execute(m_bc, t.rlp(), &out, false);
(void)gasUsed; // TODO: do something with gasused which it returns.
}
catch (...)
@@ -353,6 +354,30 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat
return out;
}
+bytes Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice)
+{
+ try
+ {
+ State temp;
+// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret));
+ {
+ ReadGuard l(x_stateDB);
+ temp = m_postMine;
+ }
+ Executive e(temp, LastHashes(), 0);
+ if (!e.call(_dest, _dest, Address(), _value, _gasPrice, &_data, _gas, Address()))
+ {
+ e.go();
+ return e.out().toBytes();
+ }
+ }
+ catch (...)
+ {
+ // TODO: Some sort of notification of failure.
+ }
+ return bytes();
+}
+
Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
startWorking();
@@ -442,7 +467,7 @@ void Client::doWork()
// returns h256s as blooms, once for each transaction.
cwork << "postSTATE <== TQ";
- h512s newPendingBlooms = m_postMine.sync(m_tq);
+ h512s newPendingBlooms = m_postMine.sync(m_bc, m_tq);
if (newPendingBlooms.size())
{
for (auto i: newPendingBlooms)
diff --git a/libethereum/Client.h b/libethereum/Client.h
index e8c460093..6a3d7ec22 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -25,6 +25,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -105,6 +107,35 @@ struct WorkChannel: public LogChannel { static const char* name() { return "-W-"
#define cworkin dev::LogOutputStream()
#define cworkout dev::LogOutputStream()
+template struct ABISerialiser {};
+template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { return _t.asBytes(); } };
+template <> struct ABISerialiser { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } };
+template <> struct ABISerialiser { static bytes serialise(u160 const& _t) { return h160(_t).asBytes(); } };
+template <> struct ABISerialiser { static bytes serialise(string32 const& _t) { return bytesConstRef((byte const*)_t.data(), 32).toBytes(); } };
+
+inline bytes abiInAux() { return {}; }
+template bytes abiInAux(T const& _t, U const& ... _u)
+{
+ return ABISerialiser::serialise(_t) + abiInAux(_u ...);
+}
+
+template bytes abiIn(byte _id, T const& ... _t)
+{
+ return bytes(1, _id) + abiInAux(_t ...);
+}
+
+template struct ABIDeserialiser {};
+template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { FixedHash ret; io_t.cropped(0, N).populate(ret.ref()); return ret; } };
+template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } };
+template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(0, 20)); io_t = io_t.cropped(20); return ret; } };
+template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } };
+
+template T abiOut(bytes const& _data)
+{
+ bytesConstRef o(&_data);
+ return ABIDeserialiser::deserialise(o);
+}
+
/**
* @brief Main API hub for interfacing with Ethereum.
*/
@@ -135,6 +166,9 @@ public:
/// Makes the given call. Nothing is recorded into the state.
virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
+ /// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH.
+ virtual bytes call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether);
+
// Informational stuff
// [NEW API]
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index d16cf794c..3bc6ea93e 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -29,12 +29,19 @@
#include "State.h"
#include "ExtVM.h"
#include "Precompiled.h"
+#include "BlockChain.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
#define ETH_VMTRACE 1
+Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
+ m_s(_s),
+ m_lastHashes(_s.getLastHashes(_bc)),
+ m_depth(_level)
+{}
+
u256 Executive::gasUsed() const
{
return m_t.gas() - m_endGas;
@@ -123,7 +130,7 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen
{
m_vm = VMFactory::create(_gas);
bytes const& c = m_s.code(_codeAddress);
- m_ext = make_shared(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth);
+ m_ext = make_shared(m_s, m_lastHashes, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth);
}
else
m_endGas = _gas;
@@ -143,7 +150,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// Execute _init.
m_vm = VMFactory::create(_gas);
- m_ext = make_shared(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
+ m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
return _init.empty();
}
diff --git a/libethereum/Executive.h b/libethereum/Executive.h
index 8ccccddf8..0b154b4b5 100644
--- a/libethereum/Executive.h
+++ b/libethereum/Executive.h
@@ -34,6 +34,7 @@ namespace eth
{
class State;
+class BlockChain;
class ExtVM;
struct Manifest;
@@ -52,7 +53,9 @@ class Executive
{
public:
/// Basic constructor.
- Executive(State& _s, unsigned _level): m_s(_s), m_depth(_level) {}
+ Executive(State& _s, LastHashes const& _lh, unsigned _level): m_s(_s), m_lastHashes(_lh), m_depth(_level) {}
+ /// Basic constructor.
+ Executive(State& _s, BlockChain const& _bc, unsigned _level);
/// Basic destructor.
~Executive() = default;
@@ -102,6 +105,7 @@ public:
private:
State& m_s; ///< The state to which this operation/transaction is applied.
+ LastHashes m_lastHashes;
std::shared_ptr m_ext; ///< The VM externality object for the VM execution or null if no VM is required.
std::unique_ptr m_vm; ///< The VM object or null if no VM is required.
bytes m_precompiledOut; ///< Used for the output when there is no VM for a contract (i.e. precompiled).
diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp
index a005a030b..a8eba5a50 100644
--- a/libethereum/ExtVM.cpp
+++ b/libethereum/ExtVM.cpp
@@ -28,7 +28,7 @@ using namespace dev::eth;
bool ExtVM::call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256& io_gas, bytesRef _out, OnOpFunc const& _onOp, Address _myAddressOverride, Address _codeAddressOverride)
{
- Executive e(m_s, depth + 1);
+ Executive e(m_s, lastHashes, depth + 1);
if (!e.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, io_gas, origin))
{
e.go(_onOp);
@@ -45,7 +45,7 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc
// Increment associated nonce for sender.
m_s.noteSending(myAddress);
- Executive e(m_s, depth + 1);
+ Executive e(m_s, lastHashes, depth + 1);
if (!e.create(myAddress, _endowment, gasPrice, io_gas, _code, origin))
{
e.go(_onOp);
diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h
index cfe40874f..30cbf1a5a 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, 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)
+ ExtVM(State& _s, LastHashes const& _lh, 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, _lh, _depth), m_s(_s), m_origCache(_s.m_cache)
{
m_s.ensureCached(_myAddress, true, true);
}
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index e02b06bcd..dfd65c713 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -114,7 +114,7 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
m_ourAddress = bi.coinbaseAddress;
sync(_bc, bi.parentHash, bip);
- enact(&b);
+ enact(&b, _bc);
}
State::State(State const& _s):
@@ -319,7 +319,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
for (auto it = chain.rbegin(); it != chain.rend(); ++it)
{
auto b = _bc.block(*it);
- enact(&b);
+ enact(&b, _bc);
cleanup(true);
}
}
@@ -348,7 +348,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
sync(_bc, _bi.parentHash);
resetCurrent();
m_previousBlock = biParent;
- return enact(_block, &_bc);
+ return enact(_block, _bc);
}
map State::addresses() const
@@ -412,12 +412,14 @@ bool State::cull(TransactionQueue& _tq) const
return ret;
}
-h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
+h512s State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
// TRANSACTIONS
h512s ret;
auto ts = _tq.transactions();
+ auto lh = getLastHashes(_bc);
+
for (int goodTxs = 1; goodTxs;)
{
goodTxs = 0;
@@ -429,7 +431,7 @@ h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
uncommitToMine();
// boost::timer t;
- execute(i.second);
+ execute(lh, i.second);
ret.push_back(m_receipts.back().bloom());
_tq.noteGood(i);
++goodTxs;
@@ -467,7 +469,7 @@ h512s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
return ret;
}
-u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
+u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
{
// m_currentBlock is assumed to be prepopulated and reset.
@@ -496,6 +498,8 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
GenericTrieDB receiptsTrie(&rm);
receiptsTrie.init();
+ LastHashes lh = getLastHashes(_bc);
+
// All ok with the block generally. Play back the transactions now...
unsigned i = 0;
for (auto const& tr: RLP(_block)[1])
@@ -504,26 +508,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
k << i;
transactionsTrie.insert(&k.out(), tr.data());
-
-// cnote << m_state.root() << m_state;
-// cnote << *this;
- execute(tr.data());
+ execute(lh, tr.data());
RLPStream receiptrlp;
m_receipts.back().streamRLP(receiptrlp);
receiptsTrie.insert(&k.out(), &receiptrlp.out());
-/*
- if (tr[1].toHash() != m_state.root())
- {
- // Invalid state root
- cnote << m_state.root() << "\n" << m_state;
- cnote << *this;
- cnote << "INVALID: " << tr[1].toHash();
- BOOST_THROW_EXCEPTION(InvalidTransactionStateRoot());
- }
- if (tr[2].toInt() != gasUsed())
- BOOST_THROW_EXCEPTION(InvalidTransactionGasUsed());
-*/
++i;
}
@@ -535,7 +524,20 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
if (receiptsTrie.root() != m_currentBlock.receiptsRoot)
{
- cwarn << "Bad receipts state root!";
+ cwarn << "Bad receipts state root.";
+ cwarn << "Block:" << toHex(_block);
+ cwarn << "Block RLP:" << RLP(_block);
+ cwarn << "Want: " << receiptsTrie.root() << ", got: " << m_currentBlock.receiptsRoot;
+ for (unsigned j = 0; j < i; ++j)
+ {
+ RLPStream k;
+ k << j;
+ auto b = asBytes(receiptsTrie.at(&k.out()));
+ cwarn << j << ": ";
+ cwarn << "RLP: " << RLP(b);
+ cwarn << "Hex: " << toHex(b);
+ cwarn << TransactionReceipt(&b);
+ }
BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
}
@@ -551,7 +553,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
// Check uncles & apply their rewards to state.
set nonces = { m_currentBlock.nonce };
Addresses rewarded;
- set knownUncles = _bc ? _bc->allUnclesFrom(m_currentBlock.parentHash) : set();
+ set knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
for (auto const& i: RLP(_block)[2])
{
if (knownUncles.count(sha3(i.data())))
@@ -560,13 +562,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce)
BlockInfo uncle = BlockInfo::fromHeader(i.data());
if (nonces.count(uncle.nonce))
BOOST_THROW_EXCEPTION(DuplicateUncleNonce());
- if (_bc)
- {
- BlockInfo uncleParent(_bc->block(uncle.parentHash));
- if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6)
- BOOST_THROW_EXCEPTION(UncleTooOld());
- uncle.verifyParent(uncleParent);
- }
+
+ BlockInfo uncleParent(_bc.block(uncle.parentHash));
+ if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
+ BOOST_THROW_EXCEPTION(UncleTooOld());
+ uncle.verifyParent(uncleParent);
nonces.insert(uncle.nonce);
tdIncrease += uncle.difficulty;
@@ -648,7 +648,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
cnote << "PARANOIA root:" << s.rootHash();
// s.m_currentBlock.populate(&block.out(), false);
// s.m_currentBlock.verifyInternals(&block.out());
- s.enact(&block.out(), &_bc, false); // don't check nonce for this since we haven't mined it yet.
+ s.enact(&block.out(), _bc, false); // don't check nonce for this since we haven't mined it yet.
s.cleanup(false);
return true;
}
@@ -993,9 +993,21 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
-// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
+LastHashes State::getLastHashes(BlockChain const& _bc) const
+{
+ LastHashes ret;
+ ret.resize(256);
+ if (c_protocolVersion > 49)
+ {
+ unsigned n = (unsigned)m_previousBlock.number;
+ for (unsigned i = 0; i < 256; ++i)
+ ret[i] = _bc.numberHash(std::max(n, i) - i);
+ }
+ return ret;
+}
-u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
+// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
+u256 State::execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output, bool _commit)
{
#ifndef ETH_RELEASE
commit(); // get an updated hash
@@ -1008,7 +1020,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
auto h = rootHash();
#endif
- Executive e(*this, 0);
+ Executive e(*this, _lh, 0);
e.setup(_rlp);
u256 startGasUsed = gasUsed();
diff --git a/libethereum/State.h b/libethereum/State.h
index 763a67451..0473893c4 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -143,14 +143,18 @@ public:
/// @returns a list of bloom filters one for each transaction placed from the queue into the state.
/// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue
/// changed and the pointer is non-null
- h512s sync(TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr);
+ h512s sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr);
/// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const;
+ LastHashes getLastHashes(BlockChain const& _bc) const;
+
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
- u256 execute(bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(&_rlp, o_output, _commit); }
- u256 execute(bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
+ u256 execute(BlockChain const& _bc, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), &_rlp, o_output, _commit); }
+ u256 execute(BlockChain const& _bc, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(getLastHashes(_bc), _rlp, o_output, _commit); }
+ u256 execute(LastHashes const& _lh, bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true) { return execute(_lh, &_rlp, o_output, _commit); }
+ u256 execute(LastHashes const& _lh, bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true);
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); }
@@ -268,9 +272,9 @@ private:
/// Retrieve all information about a given address into a cache.
void ensureCached(std::map& _cache, Address _a, bool _requireCode, bool _forceCreate) const;
- /// Execute the given block, assuming it corresponds to m_currentBlock. If _bc is passed, it will be used to check the uncles.
+ /// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure.
- u256 enact(bytesConstRef _block, BlockChain const* _bc = nullptr, bool _checkNonce = true);
+ u256 enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce = true);
/// Finalise the block, applying the earned rewards.
void applyRewards(Addresses const& _uncleAddresses);
diff --git a/libethereum/TransactionReceipt.cpp b/libethereum/TransactionReceipt.cpp
index 0fb104490..868b00558 100644
--- a/libethereum/TransactionReceipt.cpp
+++ b/libethereum/TransactionReceipt.cpp
@@ -49,3 +49,19 @@ void TransactionReceipt::streamRLP(RLPStream& _s) const
for (LogEntry const& l: m_log)
l.streamRLP(_s);
}
+
+std::ostream& dev::operator<<(std::ostream& _out, TransactionReceipt const& _r)
+{
+ _out << "Root: " << _r.stateRoot() << std::endl;
+ _out << "Gas used: " << _r.gasUsed() << std::endl;
+ _out << "Logs: " << _r.log().size() << " entries:" << std::endl;
+ for (LogEntry const& i: _r.log())
+ {
+ _out << "Address " << i.address << ". Topics:" << std::endl;
+ for (auto const& j: i.topics)
+ _out << " " << j << std::endl;
+ _out << " Data: " << toHex(i.data) << std::endl;
+ }
+ _out << "Bloom: " << _r.bloom() << std::endl;
+ return _out;
+}
diff --git a/libethereum/TransactionReceipt.h b/libethereum/TransactionReceipt.h
index 23995c75a..ebf591995 100644
--- a/libethereum/TransactionReceipt.h
+++ b/libethereum/TransactionReceipt.h
@@ -58,4 +58,7 @@ private:
using TransactionReceipts = std::vector;
}
+
+std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r);
+
}
diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp
index 8a08a290c..ebef1fdb0 100644
--- a/libevm/ExtVMFace.cpp
+++ b/libevm/ExtVMFace.cpp
@@ -25,7 +25,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
-ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth):
+ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth):
myAddress(_myAddress),
caller(_caller),
origin(_origin),
@@ -33,6 +33,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256
gasPrice(_gasPrice),
data(_data),
code(_code),
+ lastHashes(_lh),
previousBlock(_previousBlock),
currentBlock(_currentBlock),
depth(_depth)
diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h
index 84dee4272..a4ec80ed8 100644
--- a/libevm/ExtVMFace.h
+++ b/libevm/ExtVMFace.h
@@ -93,6 +93,8 @@ struct SubState
class ExtVMFace;
class VM;
+using LastHashes = std::vector;
+
using OnOpFunc = std::function;
/**
@@ -105,7 +107,7 @@ public:
ExtVMFace() = default;
/// Full constructor.
- ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth);
+ ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth);
virtual ~ExtVMFace() = default;
@@ -145,6 +147,9 @@ public:
/// Revert any changes made (by any of the other calls).
virtual void revert() {}
+ /// Hash of a block if within the last 256 blocks, or h256() otherwise.
+ h256 prevhash(u256 _number) { return _number < currentBlock.number && _number > (std::max(257, currentBlock.number) - 257) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } // TODO: CHECK!!!
+
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; }
@@ -155,7 +160,8 @@ public:
u256 gasPrice; ///< Price of gas (that we already paid).
bytesConstRef data; ///< Current input data.
bytes code; ///< Current code that is executing.
- BlockInfo previousBlock; ///< The previous block's information.
+ LastHashes lastHashes; ///< Most recent 256 blocks' hashes.
+ BlockInfo previousBlock; ///< The previous block's information. TODO: PoC-8: REMOVE
BlockInfo currentBlock; ///< The current block's information.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
unsigned depth = 0; ///< Depth of the present call.
diff --git a/libevm/VM.h b/libevm/VM.h
index 1f3fc17d5..64353e2db 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -198,7 +198,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
require(1);
runGas = c_balanceGas;
break;
-
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
@@ -240,6 +239,11 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
break;
}
+ case Instruction::PREVHASH:
+ if (c_protocolVersion > 49)
+ require(1);
+ break;
+
case Instruction::PC:
case Instruction::MSIZE:
case Instruction::GAS:
@@ -251,7 +255,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
case Instruction::CALLDATASIZE:
case Instruction::CODESIZE:
case Instruction::GASPRICE:
- case Instruction::PREVHASH:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
case Instruction::NUMBER:
@@ -581,7 +584,10 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
m_stack.push_back(_ext.gasPrice);
break;
case Instruction::PREVHASH:
- m_stack.push_back(_ext.previousBlock.hash);
+ if (c_protocolVersion > 49)
+ m_stack.back() = (u256)_ext.prevhash(m_stack.back());
+ else
+ m_stack.push_back(_ext.previousBlock.hash);
break;
case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);
diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp
index cb0a60a92..bf08cfe00 100644
--- a/libp2p/Session.cpp
+++ b/libp2p/Session.cpp
@@ -195,7 +195,7 @@ bool Session::interpret(RLP const& _r)
// "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments"
stringstream capslog;
for (auto cap: caps)
- capslog << "(" << hex << cap.first << "," << hex << cap.second << ")";
+ capslog << "(" << cap.first << "," << dec << cap.second << ")";
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort;
diff --git a/mix/AssemblyDebuggerModel.cpp b/mix/AssemblyDebuggerModel.cpp
index 1e07760e1..17abf5700 100644
--- a/mix/AssemblyDebuggerModel.cpp
+++ b/mix/AssemblyDebuggerModel.cpp
@@ -38,7 +38,7 @@ AssemblyDebuggerModel::AssemblyDebuggerModel():
m_baseState(Address(), m_overlayDB, BaseState::Empty)
{
m_baseState.addBalance(m_userAccount.address(), 10000000 * ether);
- m_currentExecution = std::unique_ptr(new Executive(m_executiveState, 0));
+ m_currentExecution = std::unique_ptr(new Executive(m_executiveState, LastHashes(), 0));
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::bytesConstRef _rawTransaction)
diff --git a/test/solidityExecutionFramework.h b/test/solidityExecutionFramework.h
index 91ee7ad6a..9f25b3725 100644
--- a/test/solidityExecutionFramework.h
+++ b/test/solidityExecutionFramework.h
@@ -117,7 +117,7 @@ private:
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0)
{
m_state.addBalance(m_sender, _value); // just in case
- eth::Executive executive(m_state, 0);
+ eth::Executive executive(m_state, eth::LastHashes(), 0);
eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec())
: eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
bytes transactionRLP = t.rlp();
diff --git a/test/state.cpp b/test/state.cpp
index b1ad8d44e..133468226 100644
--- a/test/state.cpp
+++ b/test/state.cpp
@@ -62,7 +62,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
try
{
- theState.execute(tx, &output);
+ theState.execute(LastHashes(), tx, &output);
}
catch (Exception const& _e)
{
diff --git a/test/stateOriginal.cpp b/test/stateOriginal.cpp
index 8344894f4..a49c55061 100644
--- a/test/stateOriginal.cpp
+++ b/test/stateOriginal.cpp
@@ -69,7 +69,7 @@ int stateTest()
assert(t.sender() == myMiner.address());
tx = t.rlp();
}
- s.execute(tx);
+ s.execute(bc, tx);
cout << s;
diff --git a/test/vm.cpp b/test/vm.cpp
index 920f0582c..18bf57977 100644
--- a/test/vm.cpp
+++ b/test/vm.cpp
@@ -33,7 +33,7 @@ using namespace dev::eth;
using namespace dev::test;
FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix.
- ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, _depth) {}
+ ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, LastHashes(), _depth) {}
h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&)
{