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. 29
      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)
set(ETH_VERSION 0.2.9)
set(ETH_VERSION 0.3.0)
set(ETH_BUILD_TYPE ${CMAKE_BUILD_TYPE})
# Default HEADLESS to 0.

19
alethzero/MainWin.cpp

@ -3,6 +3,7 @@
#include <QtCore>
#include <libethereum/Dagger.h>
#include <libethereum/Client.h>
#include <libethereum/Instruction.h>
#include "MainWin.h"
#include "ui_Main.h"
using namespace std;
@ -41,7 +42,7 @@ Main::Main(QWidget *parent) :
{
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");
m_webCtrl.get(r);
srand(time(0));
@ -209,7 +210,7 @@ void Main::on_destination_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();
}
@ -309,19 +310,7 @@ void Main::on_send_clicked()
m_client->unlock();
Secret s = i.secret();
Address r = Address(fromUserHex(ui->destination->text().toStdString()));
u256s data;
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);
m_client->transact(s, r, value(), assemble(ui->data->toPlainText().toStdString()));
refresh();
return;
}

17
libethereum/AddressState.h

@ -37,9 +37,14 @@ enum class AddressType
class AddressState
{
public:
AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0) {}
AddressState(u256 _balance, u256 _nonce): m_type(AddressType::Normal), m_balance(_balance), m_nonce(_nonce) {}
AddressState(u256 _balance, u256 _nonce, h256 _contractRoot): m_type(AddressType::Contract), m_balance(_balance), m_nonce(_nonce), m_contractRoot(_contractRoot) {}
AddressState(): m_type(AddressType::Dead), m_balance(0), m_nonce(0), m_haveMemory(false) {}
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_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 addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); }
@ -50,15 +55,17 @@ public:
u256 const& balance() const { return m_balance; }
u256& nonce() { 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; }
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; }
private:
AddressType m_type;
u256 m_balance;
u256 m_nonce;
bool m_haveMemory;
h256 m_contractRoot;
// TODO: change to unordered_map.
std::map<u256, u256> m_memory;

180
libethereum/Common.h

@ -32,6 +32,10 @@
#include <chrono>
#include <array>
#include <map>
#include <unordered_map>
#include <set>
#include <array>
#include <list>
#include <set>
#include <string>
#include <cassert>
@ -451,4 +455,180 @@ private:
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 <chrono>
#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
#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
#include "Common.h"
namespace eth
{
@ -60,4 +83,60 @@ enum class Instruction: uint8_t
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() << "] "
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_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong.

29
libethereum/State.cpp

@ -62,10 +62,10 @@ std::map<Address, AddressState> const& eth::genesisState()
if (s_ret.empty())
{
// Initialise.
s_ret[Address(fromUserHex("8a40bfaa73256b60764c1bf40675a99083efb075"))] = AddressState(u256(1) << 200, 0);
s_ret[Address(fromUserHex("93658b04240e4bd4046fd2d6d417d20f146f4b43"))] = AddressState(u256(1) << 200, 0);
s_ret[Address(fromUserHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0);
s_ret[Address(fromUserHex("80c01a26338f0d905e295fccb71fa9ea849ffa12"))] = 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, AddressType::Normal);
s_ret[Address(fromUserHex("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
s_ret[Address(fromUserHex("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"))] = AddressState(u256(1) << 200, 0, AddressType::Normal);
}
return s_ret;
}
@ -172,7 +172,7 @@ void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) con
// Populate memory.
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! :)
map<u256, u256>& mem = it->second.takeMemory();
map<u256, u256>& mem = it->second.setHaveMemory();
for (auto const& i: memdb)
if (mem.find(i.first) == mem.end())
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;
for (auto const& i: _uncleAddresses)
{
addBalance(i, m_blockReward * 4 / 3);
addBalance(i, m_blockReward * 3 / 4);
r += m_blockReward / 8;
}
addBalance(m_currentBlock.coinbaseAddress, r);
@ -614,8 +614,13 @@ void State::executeBare(Transaction const& _t, Address _sender)
if (_t.nonce != nonceReq)
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.
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)
throw NotEnoughCash();
@ -642,14 +647,14 @@ void State::executeBare(Transaction const& _t, Address _sender)
#endif
throw NotEnoughCash();
Address newAddress = low160(_t.sha3());
Address newAddress = right160(_t.sha3());
if (isContractAddress(newAddress) || isNormalAddress(newAddress))
throw ContractAddressCollision();
// All OK - set it up.
m_cache[newAddress] = AddressState(0, 0, sha3(RLPNull));
auto& mem = m_cache[newAddress].takeMemory();
m_cache[newAddress] = AddressState(0, 0, AddressType::Contract);
auto& mem = m_cache[newAddress].memory();
for (uint i = 0; i < _t.data.size(); ++i)
if (mem.find(i) == mem.end())
mem.insert(make_pair(i, _t.data[i]));
@ -671,7 +676,7 @@ void State::executeBare(Transaction const& _t, Address _sender)
// TODO: CHECK: check that this is correct.
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)
@ -685,7 +690,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s
throw StackTooSmall(_n, stack.size());
};
ensureCached(_myAddress, true, true);
auto& myMemory = m_cache[_myAddress].takeMemory();
auto& myMemory = m_cache[_myAddress].memory();
auto mem = [&](u256 _n) -> u256
{

27
libethereum/State.h

@ -57,6 +57,8 @@ struct FeeStructure
u256 m_txFee;
};
template <unsigned T> class UnitTest {};
/**
* @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).
@ -64,6 +66,7 @@ struct FeeStructure
*/
class State
{
template <unsigned T> friend class UnitTest;
public:
/// Construct state object.
State(Address _coinbaseAddress, Overlay const& _db);
@ -224,7 +227,7 @@ private:
BlockInfo m_currentBlock; ///< The current block's information.
bytes m_currentBytes; ///< The current block.
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_currentUncles;
@ -245,13 +248,16 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
{
_out << "--- " << _s.rootHash() << std::endl;
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);
if (it == _s.m_cache.end())
{
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
d.insert(i.first);
@ -260,7 +266,20 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
if (i.second.type() == AddressType::Dead)
_out << "[XXX " << i.first << std::endl;
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;
}

4
libethereum/TrieDB.h

@ -76,10 +76,10 @@ public:
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 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(); }
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:
using BasicMap::clear;

2
test/main.cpp

@ -27,6 +27,7 @@ int rlpTest();
int daggerTest();
int cryptoTest();
int stateTest();
int vmTest();
int hexPrefixTest();
int peerTest(int argc, char** argv);
@ -46,6 +47,7 @@ int main(int argc, char** argv)
trieTest();
daggerTest();
cryptoTest();
vmTest();
// stateTest();
// peerTest(argc, argv);
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