Browse Source

Fixes for contract address states.

Minor fix for uncle rewards.
Assembler for EC-1 assembly.
Not-quite Test code for the VM.
cl-refactor
Gav Wood 11 years ago
parent
commit
8dc00e8b21
  1. 2
      CMakeLists.txt
  2. 19
      alethzero/MainWin.cpp
  3. 17
      libethereum/AddressState.h
  4. 180
      libethereum/Common.h
  5. 21
      libethereum/Dagger.cpp
  6. 23
      libethereum/Dagger.h
  7. 58
      libethereum/Instruction.cpp
  8. 79
      libethereum/Instruction.h
  9. 2
      libethereum/PeerNetwork.cpp
  10. 31
      libethereum/State.cpp
  11. 27
      libethereum/State.h
  12. 4
      libethereum/TrieDB.h
  13. 2
      test/main.cpp
  14. 85
      test/vm.cpp

2
CMakeLists.txt

@ -5,7 +5,7 @@ set(CMAKE_AUTOMOC ON)
cmake_policy(SET CMP0015 NEW) cmake_policy(SET CMP0015 NEW)
set(ETH_VERSION 0.2.9) set(ETH_VERSION 0.3.0)
set(ETH_BUILD_TYPE ${CMAKE_BUILD_TYPE}) set(ETH_BUILD_TYPE ${CMAKE_BUILD_TYPE})
# Default HEADLESS to 0. # Default HEADLESS to 0.

19
alethzero/MainWin.cpp

@ -3,6 +3,7 @@
#include <QtCore> #include <QtCore>
#include <libethereum/Dagger.h> #include <libethereum/Dagger.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/Instruction.h>
#include "MainWin.h" #include "MainWin.h"
#include "ui_Main.h" #include "ui_Main.h"
using namespace std; using namespace std;
@ -41,7 +42,7 @@ Main::Main(QWidget *parent) :
{ {
m_servers = QString::fromUtf8(_r->readAll()).split("\n", QString::SkipEmptyParts); m_servers = QString::fromUtf8(_r->readAll()).split("\n", QString::SkipEmptyParts);
}); });
QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc2.txt")); QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc3.txt"));
r.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1712.0 Safari/537.36"); r.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1712.0 Safari/537.36");
m_webCtrl.get(r); m_webCtrl.get(r);
srand(time(0)); srand(time(0));
@ -209,7 +210,7 @@ void Main::on_destination_textChanged()
void Main::on_data_textChanged() void Main::on_data_textChanged()
{ {
m_data = ui->data->toPlainText().split(QRegExp("[^0-9a-fA-Fx]+"), QString::SkipEmptyParts); m_data = ui->data->toPlainText().split(QRegExp("[^0-9a-zA-Z]+"), QString::SkipEmptyParts);
updateFee(); updateFee();
} }
@ -309,19 +310,7 @@ void Main::on_send_clicked()
m_client->unlock(); m_client->unlock();
Secret s = i.secret(); Secret s = i.secret();
Address r = Address(fromUserHex(ui->destination->text().toStdString())); Address r = Address(fromUserHex(ui->destination->text().toStdString()));
u256s data; m_client->transact(s, r, value(), assemble(ui->data->toPlainText().toStdString()));
data.reserve(m_data.size());
for (QString const& i: m_data)
{
u256 d = 0;
try
{
d = u256(i.toStdString());
}
catch (...) {}
data.push_back(d);
}
m_client->transact(s, r, value(), data);
refresh(); refresh();
return; return;
} }

17
libethereum/AddressState.h

@ -37,9 +37,14 @@ enum class AddressType
class AddressState class AddressState
{ {
public: public:
AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0) {} AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0), m_haveMemory(false) {}
AddressState(u256 _balance, u256 _nonce): m_type(AddressType::Normal), m_balance(_balance), m_nonce(_nonce) {} AddressState(u256 _balance, u256 _nonce, AddressType _type = AddressType::Normal): m_type(_type), m_balance(_balance), m_nonce(_nonce), m_haveMemory(true) {}
AddressState(u256 _balance, u256 _nonce, h256 _contractRoot): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_contractRoot(_contractRoot) {} AddressState(u256 _balance, u256 _nonce, h256 _contractRoot): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_haveMemory(false), m_contractRoot(_contractRoot) {}
AddressState(u256 _balance, u256 _nonce, u256s _memory): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_haveMemory(true)
{
for (unsigned i = 0; i < _memory.size(); ++i)
m_memory[(u256)i] = _memory[i];
}
void incNonce() { m_nonce++; } void incNonce() { m_nonce++; }
void addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); } void addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); }
@ -50,15 +55,17 @@ public:
u256 const& balance() const { return m_balance; } u256 const& balance() const { return m_balance; }
u256& nonce() { return m_nonce; } u256& nonce() { return m_nonce; }
u256 const& nonce() const { return m_nonce; } u256 const& nonce() const { return m_nonce; }
bool haveMemory() const { return m_memory.empty() && m_contractRoot != h256(); } // TODO: best to switch to m_haveMemory flag rather than try to infer. bool haveMemory() const { return m_haveMemory; }
std::map<u256, u256>& setHaveMemory() { assert(m_type == AddressType::Contract); m_haveMemory = true; m_contractRoot = h256(); return m_memory; }
h256 oldRoot() const { assert(!haveMemory()); return m_contractRoot; } h256 oldRoot() const { assert(!haveMemory()); return m_contractRoot; }
std::map<u256, u256>& takeMemory() { assert(m_type == AddressType::Contract && haveMemory()); m_contractRoot = h256(); return m_memory; } std::map<u256, u256>& memory() { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; }
std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; } std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && haveMemory()); return m_memory; }
private: private:
AddressType m_type; AddressType m_type;
u256 m_balance; u256 m_balance;
u256 m_nonce; u256 m_nonce;
bool m_haveMemory;
h256 m_contractRoot; h256 m_contractRoot;
// TODO: change to unordered_map. // TODO: change to unordered_map.
std::map<u256, u256> m_memory; std::map<u256, u256> m_memory;

180
libethereum/Common.h

@ -32,6 +32,10 @@
#include <chrono> #include <chrono>
#include <array> #include <array>
#include <map> #include <map>
#include <unordered_map>
#include <set>
#include <array>
#include <list>
#include <set> #include <set>
#include <string> #include <string>
#include <cassert> #include <cassert>
@ -451,4 +455,180 @@ private:
Address m_address; Address m_address;
}; };
static const u256 Uether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Vether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Dether = ((((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Nether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Yether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Zether = (((u256(1000000000) * 1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Eether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000000;
static const u256 Pether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000000;
static const u256 Tether = ((u256(1000000000) * 1000000000) * 1000000000) * 1000;
static const u256 Gether = (u256(1000000000) * 1000000000) * 1000000000;
static const u256 Mether = (u256(1000000000) * 1000000000) * 1000000;
static const u256 Kether = (u256(1000000000) * 1000000000) * 1000;
static const u256 ether = u256(1000000000) * 1000000000;
static const u256 finney = u256(1000000000) * 1000000;
static const u256 szabo = u256(1000000000) * 1000;
static const u256 Gwei = u256(1000000000);
static const u256 Mwei = u256(1000000);
static const u256 Kwei = u256(1000);
static const u256 wei = u256(1);
// Stream IO
template <class S, class T> struct StreamOut { static S& bypass(S& _out, T const& _t) { _out << _t; return _out; } };
template <class S> struct StreamOut<S, uint8_t> { static S& bypass(S& _out, uint8_t const& _t) { _out << (int)_t; return _out; } };
template <class S, class T>
inline S& streamout(S& _out, std::vector<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
for (auto i = ++_e.begin(); i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::vector<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, unsigned long Z>
inline S& streamout(S& _out, std::array<T, Z> const& _e)
{
_out << "[";
if (!_e.empty())
{
StreamOut<S, T>::bypass(_out, _e.front());
auto i = _e.begin();
for (++i; i != _e.end(); ++i)
StreamOut<S, T>::bypass(_out << ",", *i);
}
_out << "]";
return _out;
}
template <class T, unsigned long Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
inline S& streamout(S& _out, std::list<T> const& _e)
{
_out << "[";
if (!_e.empty())
{
_out << _e.front();
for (auto i = ++_e.begin(); i != _e.end(); ++i)
_out << "," << *i;
}
_out << "]";
return _out;
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::list<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
inline S& streamout(S& _out, std::pair<T, U> const& _e)
{
_out << "(" << _e.first << "," << _e.second << ")";
return _out;
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::pair<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T1, class T2, class T3>
inline S& streamout(S& _out, std::tuple<T1, T2, T3> const& _t)
{
_out << "(" << std::get<0>(_t) << "," << std::get<1>(_t) << "," << std::get<2>(_t) << ")";
return _out;
}
template <class T1, class T2, class T3> inline std::ostream& operator<<(std::ostream& _out, std::tuple<T1, T2, T3> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::unordered_map<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : "; ") << p.first << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::unordered_map<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::set<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::set<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T>
S& streamout(S& _out, std::multiset<T> const& _v)
{
if (_v.empty())
return _out << "{}";
int i = 0;
for (auto p: _v)
_out << (!(i++) ? "{ " : ", ") << p;
return _out << " }";
}
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::multiset<T> const& _e) { streamout(_out, _e); return _out; }
template <class S, class T, class U>
S& streamout(S& _out, std::multimap<T, U> const& _v)
{
if (_v.empty())
return _out << "{}";
T l;
int i = 0;
for (auto p: _v)
if (!(i++))
_out << "{ " << (l = p.first) << " => " << p.second;
else if (l == p.first)
_out << ", " << p.second;
else
_out << "; " << (l = p.first) << " => " << p.second;
return _out << " }";
}
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e) { streamout(_out, _e); return _out; }
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p) { if (_p) _out << "@" << (*_p); else _out << "nullptr"; return _out; }
} }

21
libethereum/Dagger.cpp

@ -1,3 +1,24 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Dagger.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <boost/detail/endian.hpp> #include <boost/detail/endian.hpp>
#include <chrono> #include <chrono>
#include <array> #include <array>

23
libethereum/Dagger.h

@ -1,3 +1,26 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Dagger.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Dagger algorithm. Or not.
*/
#pragma once #pragma once
#include "Common.h" #include "Common.h"

58
libethereum/Instruction.cpp

@ -0,0 +1,58 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Instruction.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Instruction.h"
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace eth;
u256s eth::assemble(std::string const& _code)
{
u256s ret;
char const* d = _code.data();
char const* e = _code.data() + _code.size();
while (d != e)
{
// skip to next token
for (; d != e && !isalnum(*d); ++d) {}
if (d == e)
break;
char const* s = d;
for (; d != e && isalnum(*d); ++d) {}
string t = string(s, d - s);
if (isdigit(t[0]))
ret.push_back(u256(t));
else
{
boost::algorithm::to_upper(t);
auto it = c_instructions.find(t);
if (it != c_instructions.end())
ret.push_back((u256)it->second);
else
cwarn << "Unknown assembler token" << t;
}
}
return ret;
}

79
libethereum/Instruction.h

@ -1,5 +1,28 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Instruction.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once #pragma once
#include "Common.h"
namespace eth namespace eth
{ {
@ -60,4 +83,60 @@ enum class Instruction: uint8_t
SUICIDE = 0xff SUICIDE = 0xff
}; };
static const std::map<std::string, Instruction> c_instructions =
{
{ "STOP", (Instruction)0x00 },
{ "ADD", (Instruction)0x01 },
{ "SUB", (Instruction)0x02 },
{ "MUL", (Instruction)0x03 },
{ "DIV", (Instruction)0x04 },
{ "SDIV", (Instruction)0x05 },
{ "MOD", (Instruction)0x06 },
{ "SMOD", (Instruction)0x07 },
{ "EXP", (Instruction)0x08 },
{ "NEG", (Instruction)0x09 },
{ "LT", (Instruction)0x0a },
{ "LE", (Instruction)0x0b },
{ "GT", (Instruction)0x0c },
{ "GE", (Instruction)0x0d },
{ "EQ", (Instruction)0x0e },
{ "NOT", (Instruction)0x0f },
{ "MYADDRESS", (Instruction)0x10 },
{ "TXSENDER", (Instruction)0x11 },
{ "TXVALUE", (Instruction)0x12 },
{ "TXFEE", (Instruction)0x13 },
{ "TXDATAN", (Instruction)0x14 },
{ "TXDATA", (Instruction)0x15 },
{ "BLK_PREVHASH", (Instruction)0x16 },
{ "BLK_COINBASE", (Instruction)0x17 },
{ "BLK_TIMESTAMP", (Instruction)0x18 },
{ "BLK_NUMBER", (Instruction)0x19 },
{ "BLK_DIFFICULTY", (Instruction)0x1a },
{ "SHA256", (Instruction)0x20 },
{ "RIPEMD160", (Instruction)0x21 },
{ "ECMUL", (Instruction)0x22 },
{ "ECADD", (Instruction)0x23 },
{ "ECSIGN", (Instruction)0x24 },
{ "ECRECOVER", (Instruction)0x25 },
{ "ECVALID", (Instruction)0x26 },
{ "SHA3", (Instruction)0x27 },
{ "PUSH", (Instruction)0x30 },
{ "POP", (Instruction)0x31 },
{ "DUP", (Instruction)0x32 },
{ "DUPN", (Instruction)0x33 },
{ "SWAP", (Instruction)0x34 },
{ "SWAPN", (Instruction)0x35 },
{ "LOAD", (Instruction)0x36 },
{ "STORE", (Instruction)0x37 },
{ "JMP", (Instruction)0x40 },
{ "JMPI", (Instruction)0x41 },
{ "IND", (Instruction)0x42 },
{ "EXTRO", (Instruction)0x50 },
{ "BALANCE", (Instruction)0x51 },
{ "MKTX", (Instruction)0x60 },
{ "SUICIDE", (Instruction)0xff }
};
u256s assemble(std::string const& _code);
} }

2
libethereum/PeerNetwork.cpp

@ -43,7 +43,7 @@ using namespace eth;
#define clogS(X) eth::LogOutputStream<X, true>(false) << "| " << std::setw(2) << m_socket.native_handle() << "] " #define clogS(X) eth::LogOutputStream<X, true>(false) << "| " << std::setw(2) << m_socket.native_handle() << "] "
static const int c_protocolVersion = 4; static const int c_protocolVersion = 5;
static const eth::uint c_maxHashes = 32; ///< Maximum number of hashes GetChain will ever send. static const eth::uint c_maxHashes = 32; ///< Maximum number of hashes GetChain will ever send.
static const eth::uint c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong. static const eth::uint c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong.

31
libethereum/State.cpp

@ -62,10 +62,10 @@ std::map<Address, AddressState> const& eth::genesisState()
if (s_ret.empty()) if (s_ret.empty())
{ {
// Initialise. // Initialise.
s_ret[Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0); s_ret[Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("93658b04240e4bd4046fd2d6d417d20f146f4b43"))] = AddressState(u256(1) << 200, 0); s_ret[Address(fromUserHex("93658b04240e4bd4046fd2d6d417d20f146f4b43"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0); s_ret[Address(fromUserHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("80c01a26338f0d905e295fccb71fa9ea849ffa12"))] = AddressState(u256(1) << 200, 0); s_ret[Address(fromUserHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
} }
return s_ret; return s_ret;
} }
@ -172,7 +172,7 @@ void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) con
// Populate memory. // Populate memory.
assert(it->second.type() == AddressType::Contract); assert(it->second.type() == AddressType::Contract);
TrieDB<u256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :) TrieDB<u256, Overlay> memdb(const_cast<Overlay*>(&m_db), it->second.oldRoot()); // promise we won't alter the overlay! :)
map<u256, u256>& mem = it->second.takeMemory(); map<u256, u256>& mem = it->second.setHaveMemory();
for (auto const& i: memdb) for (auto const& i: memdb)
if (mem.find(i.first) == mem.end()) if (mem.find(i.first) == mem.end())
mem.insert(make_pair(i.first, RLP(i.second).toInt<u256>())); mem.insert(make_pair(i.first, RLP(i.second).toInt<u256>()));
@ -599,7 +599,7 @@ void State::applyRewards(Addresses const& _uncleAddresses)
u256 r = m_blockReward; u256 r = m_blockReward;
for (auto const& i: _uncleAddresses) for (auto const& i: _uncleAddresses)
{ {
addBalance(i, m_blockReward * 4 / 3); addBalance(i, m_blockReward * 3 / 4);
r += m_blockReward / 8; r += m_blockReward / 8;
} }
addBalance(m_currentBlock.coinbaseAddress, r); addBalance(m_currentBlock.coinbaseAddress, r);
@ -614,8 +614,13 @@ void State::executeBare(Transaction const& _t, Address _sender)
if (_t.nonce != nonceReq) if (_t.nonce != nonceReq)
throw InvalidNonce(nonceReq, _t.nonce); throw InvalidNonce(nonceReq, _t.nonce);
unsigned nonZeroData = 0;
for (auto i: _t.data)
if (i)
nonZeroData++;
u256 fee = _t.receiveAddress ? m_fees.m_txFee : (nonZeroData * m_fees.m_memoryFee + m_fees.m_newContractFee);
// Not considered invalid - just pointless. // Not considered invalid - just pointless.
u256 fee = _t.receiveAddress ? m_fees.m_txFee : (_t.data.size() * m_fees.m_memoryFee + m_fees.m_newContractFee);
if (balance(_sender) < _t.value + fee) if (balance(_sender) < _t.value + fee)
throw NotEnoughCash(); throw NotEnoughCash();
@ -642,20 +647,20 @@ void State::executeBare(Transaction const& _t, Address _sender)
#endif #endif
throw NotEnoughCash(); throw NotEnoughCash();
Address newAddress = low160(_t.sha3()); Address newAddress = right160(_t.sha3());
if (isContractAddress(newAddress) || isNormalAddress(newAddress)) if (isContractAddress(newAddress) || isNormalAddress(newAddress))
throw ContractAddressCollision(); throw ContractAddressCollision();
// All OK - set it up. // All OK - set it up.
m_cache[newAddress] = AddressState(0, 0, sha3(RLPNull)); m_cache[newAddress] = AddressState(0, 0, AddressType::Contract);
auto& mem = m_cache[newAddress].takeMemory(); auto& mem = m_cache[newAddress].memory();
for (uint i = 0; i < _t.data.size(); ++i) for (uint i = 0; i < _t.data.size(); ++i)
if (mem.find(i) == mem.end()) if (mem.find(i) == mem.end())
mem.insert(make_pair(i, _t.data[i])); mem.insert(make_pair(i, _t.data[i]));
else else
mem.at(i) = _t.data[i]; mem.at(i) = _t.data[i];
#if ETH_SENDER_PAYS_SETUP #if ETH_SENDER_PAYS_SETUP
subBalance(_sender, _t.value + fee); subBalance(_sender, _t.value + fee);
addBalance(newAddress, _t.value); addBalance(newAddress, _t.value);
@ -671,7 +676,7 @@ void State::executeBare(Transaction const& _t, Address _sender)
// TODO: CHECK: check that this is correct. // TODO: CHECK: check that this is correct.
inline Address asAddress(u256 _item) inline Address asAddress(u256 _item)
{ {
return left160(h256(_item)); return right160(h256(_item));
} }
void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, u256* _totalFee) void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, u256* _totalFee)
@ -685,7 +690,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
throw StackTooSmall(_n, stack.size()); throw StackTooSmall(_n, stack.size());
}; };
ensureCached(_myAddress, true, true); ensureCached(_myAddress, true, true);
auto& myMemory = m_cache[_myAddress].takeMemory(); auto& myMemory = m_cache[_myAddress].memory();
auto mem = [&](u256 _n) -> u256 auto mem = [&](u256 _n) -> u256
{ {

27
libethereum/State.h

@ -57,6 +57,8 @@ struct FeeStructure
u256 m_txFee; u256 m_txFee;
}; };
template <unsigned T> class UnitTest {};
/** /**
* @brief Model of the current state of the ledger. * @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block). * Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@ -64,6 +66,7 @@ struct FeeStructure
*/ */
class State class State
{ {
template <unsigned T> friend class UnitTest;
public: public:
/// Construct state object. /// Construct state object.
State(Address _coinbaseAddress, Overlay const& _db); State(Address _coinbaseAddress, Overlay const& _db);
@ -224,7 +227,7 @@ private:
BlockInfo m_currentBlock; ///< The current block's information. BlockInfo m_currentBlock; ///< The current block's information.
bytes m_currentBytes; ///< The current block. bytes m_currentBytes; ///< The current block.
uint m_currentNumber; uint m_currentNumber;
h256 m_committedPreviousHash; ///< Hash of previous block that we are committing to mine. h256 m_committedPreviousHash; ///< Hash of previous block that we are committing to mine.
bytes m_currentTxs; bytes m_currentTxs;
bytes m_currentUncles; bytes m_currentUncles;
@ -245,13 +248,16 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
{ {
_out << "--- " << _s.rootHash() << std::endl; _out << "--- " << _s.rootHash() << std::endl;
std::set<Address> d; std::set<Address> d;
for (auto const& i: TrieDB<Address, Overlay>(const_cast<Overlay*>(&_s.m_db), _s.m_currentBlock.stateRoot)) for (auto const& i: TrieDB<Address, Overlay>(const_cast<Overlay*>(&_s.m_db), _s.rootHash()))
{ {
auto it = _s.m_cache.find(i.first); auto it = _s.m_cache.find(i.first);
if (it == _s.m_cache.end()) if (it == _s.m_cache.end())
{ {
RLP r(i.second); RLP r(i.second);
_out << "[ " << (r.itemCount() == 3 ? "CONTRACT] " : " NORMAL] ") << i.first << ": " << std::dec << r[1].toInt<u256>() << "@" << r[0].toInt<u256>() << std::endl; _out << "[ " << (r.itemCount() == 3 ? "CONTRACT] " : " NORMAL] ") << i.first << ": " << std::dec << r[1].toInt<u256>() << "@" << r[0].toInt<u256>();
if (r.itemCount() == 3)
_out << " &" << r[2].toHash<h256>();
_out << std::endl;
} }
else else
d.insert(i.first); d.insert(i.first);
@ -260,7 +266,20 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
if (i.second.type() == AddressType::Dead) if (i.second.type() == AddressType::Dead)
_out << "[XXX " << i.first << std::endl; _out << "[XXX " << i.first << std::endl;
else else
_out << (d.count(i.first) ? "[ ! " : "[ * ") << (i.second.type() == AddressType::Contract ? "CONTRACT] " : " NORMAL] ") << i.first << ": " << std::dec << i.second.nonce() << "@" << i.second.balance() << std::endl; {
_out << (d.count(i.first) ? "[ ! " : "[ * ") << (i.second.type() == AddressType::Contract ? "CONTRACT] " : " NORMAL] ") << i.first << ": " << std::dec << i.second.nonce() << "@" << i.second.balance();
if (i.second.type() == AddressType::Contract)
{
if (i.second.haveMemory())
{
_out << std::endl;
_out << i.second.memory();
}
else
_out << " &" << i.second.oldRoot();
}
_out << std::endl;
}
return _out; return _out;
} }

4
libethereum/TrieDB.h

@ -76,10 +76,10 @@ public:
ldb::DB* db() const { return m_db.get(); } ldb::DB* db() const { return m_db.get(); }
void setDB(ldb::DB* _db, bool _clearOverlay = true) { m_db = std::shared_ptr<ldb::DB>(_db); if (_clearOverlay) m_over.clear(); } void setDB(ldb::DB* _db, bool _clearOverlay = true) { m_db = std::shared_ptr<ldb::DB>(_db); if (_clearOverlay) m_over.clear(); }
void commit() { for (auto const& i: m_over) m_db->Put(m_writeOptions, ldb::Slice((char const*)i.first.data(), i.first.size), ldb::Slice(i.second.data(), i.second.size())); m_over.clear(); m_refCount.clear(); } void commit() { if (m_db) { for (auto const& i: m_over) m_db->Put(m_writeOptions, ldb::Slice((char const*)i.first.data(), i.first.size), ldb::Slice(i.second.data(), i.second.size())); m_over.clear(); m_refCount.clear(); } }
void rollback() { m_over.clear(); m_refCount.clear(); } void rollback() { m_over.clear(); m_refCount.clear(); }
std::string lookup(h256 _h) const { std::string ret = BasicMap::lookup(_h); if (ret.empty()) m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); return ret; } std::string lookup(h256 _h) const { std::string ret = BasicMap::lookup(_h); if (ret.empty() && m_db) m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); return ret; }
private: private:
using BasicMap::clear; using BasicMap::clear;

2
test/main.cpp

@ -27,6 +27,7 @@ int rlpTest();
int daggerTest(); int daggerTest();
int cryptoTest(); int cryptoTest();
int stateTest(); int stateTest();
int vmTest();
int hexPrefixTest(); int hexPrefixTest();
int peerTest(int argc, char** argv); int peerTest(int argc, char** argv);
@ -46,6 +47,7 @@ int main(int argc, char** argv)
trieTest(); trieTest();
daggerTest(); daggerTest();
cryptoTest(); cryptoTest();
vmTest();
// stateTest(); // stateTest();
// peerTest(argc, argv); // peerTest(argc, argv);
return 0; return 0;

85
test/vm.cpp

@ -0,0 +1,85 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file state.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* State test functions.
*/
#include <boost/algorithm/string.hpp>
#include <secp256k1.h>
#include <BlockChain.h>
#include <State.h>
#include <Defaults.h>
#include <Instruction.h>
using namespace std;
using namespace eth;
namespace eth
{
template <> class UnitTest<1>
{
public:
int operator()()
{
KeyPair p = KeyPair::create();
Overlay o;
State s(p.address(), o);
cout << s;
s.addBalance(p.address(), Uether);
cout << s;
Transaction c;
c.receiveAddress = Address();
c.nonce = 0;
c.data = assemble("txsender load txvalue add txsender store stop");
c.value = ether;
c.sign(p.secret());
s.execute(c.rlp());
Address ca = right160(c.sha3());
cout << s;
s.commit();
cout << s;
cout << s.m_db;
c.receiveAddress = ca;
c.nonce = 1;
c.data = {};
c.value = 69 * wei;
c.sign(p.secret());
s.execute(c.rlp());
cout << s;
return 0;
}
};
}
int vmTest()
{
return UnitTest<1>()();
}
Loading…
Cancel
Save