Browse Source

Much change - beginning the bigger-picture stuff.

cl-refactor
Gav Wood 11 years ago
parent
commit
30285da6cb
  1. 2
      libethereum/Common.cpp
  2. 31
      libethereum/Common.h
  3. 106
      libethereum/RLP.h
  4. 85
      libethereum/Trie.cpp
  5. 2
      libethereum/Trie.h
  6. 196
      libethereum/VirtualMachine.cpp
  7. 170
      libethereum/VirtualMachine.h
  8. 51
      libethereum/foreign.h
  9. 14
      libethereum/sha256.cpp
  10. 1
      libethereum/sha256.h

2
libethereum/Common.cpp

@ -10,7 +10,7 @@ using namespace eth;
((uint32_t) *((strptr)+1) << 8) | \
((uint32_t) *(strptr)))
u256 eth::ripemd160(fConstBytes _message)
u256 eth::ripemd160(bytesConstRef _message)
/*
* returns RMD(message)
* message should be a string terminated by '\0'

31
libethereum/Common.h

@ -4,7 +4,7 @@
#include <sstream>
#include <cstdint>
#include <boost/multiprecision/cpp_int.hpp>
#include "foreign.h"
#include "vector_ref.h"
namespace eth
{
@ -12,15 +12,18 @@ namespace eth
using byte = uint8_t;
using bytes = std::vector<byte>;
using fBytes = foreign<byte>;
using fConstBytes = foreign<byte const>;
using bytesRef = vector_ref<byte>;
using bytesConstRef = vector_ref<byte const>;
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using uint = uint64_t;
using sint = int64_t;
using u256s = std::vector<u256>;
using u160s = std::vector<u160>;
template <class _T> std::string toString(_T const& _t) { std::ostringstream o; o << _t; return o.str(); }
@ -57,15 +60,27 @@ inline bytes toHex(std::string const& _s)
return ret;
}
inline std::string toBigEndianString(u256 _val)
template <class _T>
inline std::string toBigEndianString(_T _val, uint _s)
{
std::string ret;
ret.resize(32);
for (int i = 0; i < 32; ++i, _val >>= 8)
ret[31 - i] = (char)(uint8_t)_val;
ret.resize(_s);
for (uint i = 0; i < _s; ++i, _val >>= 8)
ret[_s - 1 - i] = (char)(uint8_t)_val;
return ret;
}
inline std::string toBigEndianString(u256 _val) { return toBigEndianString(_val, 32); }
inline std::string toBigEndianString(u160 _val) { return toBigEndianString(_val, 20); }
template <class _T>
inline std::string toCompactBigEndianString(_T _val)
{
int i;
for (i = 0; _val; ++i, _val >>= 8) {}
return toBigEndianString(_val, i);
}
template <class _T, class _U> uint commonPrefix(_T const& _t, _U const& _u)
{
uint s = std::min<uint>(_t.size(), _u.size());
@ -75,6 +90,6 @@ template <class _T, class _U> uint commonPrefix(_T const& _t, _U const& _u)
return s;
}
u256 ripemd160(fConstBytes _message);
u256 ripemd160(bytesConstRef _message);
}

106
libethereum/RLP.h

@ -1,8 +1,9 @@
#pragma once
#include <exception>
#include <iostream>
#include <iomanip>
#include "foreign.h"
#include "vector_ref.h"
#include "Common.h"
namespace eth
@ -20,20 +21,24 @@ typedef std::vector<RLP> RLPs;
class RLP
{
public:
class BadCast: public std::exception {};
/// Construct a null node.
RLP() {}
/// Construct a node of value given in the bytes.
explicit RLP(fConstBytes _d): m_data(_d) {}
explicit RLP(bytesConstRef _d): m_data(_d) {}
/// Construct a node of value given in the bytes.
explicit RLP(bytes const& _d): m_data(const_cast<bytes*>(&_d)) {} // a bit horrible, but we know we won't be altering the data. TODO: allow vector<T> const* to be passed to foreign<T const>.
explicit RLP(bytes const& _d): m_data(const_cast<bytes*>(&_d)) {} // a bit horrible, but we know we won't be altering the data. TODO: allow vector<T> const* to be passed to vector_ref<T const>.
/// Construct a node to read RLP data in the bytes given.
RLP(byte const* _b, uint _s): m_data(fConstBytes(_b, _s)) {}
RLP(byte const* _b, uint _s): m_data(bytesConstRef(_b, _s)) {}
/// Construct a node to read RLP data in the string.
explicit RLP(std::string const& _s): m_data(fConstBytes((byte const*)_s.data(), _s.size())) {}
explicit RLP(std::string const& _s): m_data(bytesConstRef((byte const*)_s.data(), _s.size())) {}
bytesConstRef data() const { return m_data; }
/// @returns true if the RLP is non-null.
explicit operator bool() const { return !isNull(); }
@ -67,6 +72,7 @@ public:
/// @returns the number of items in the list, or zero if it isn't a list.
uint itemCount() const { return isList() ? items() : 0; }
uint itemCountStrict() const { if (!isList()) throw BadCast(); return items(); }
/// @returns the number of characters in the string, or zero if it isn't a string.
uint stringSize() const { return isString() ? items() : 0; }
@ -80,10 +86,68 @@ public:
{
if (!isList() || itemCount() <= _i)
return RLP();
fConstBytes d = payload();
for (uint64_t i = 0; i < _i; ++i, d = d.cropped(RLP(d).size())) {}
return RLP(d);
if (_i < m_lastIndex)
{
m_lastEnd = RLP(payload()).actualSize();
m_lastItem = payload().cropped(m_lastEnd);
m_lastIndex = 0;
}
for (; m_lastIndex < _i; ++m_lastIndex)
{
m_lastItem = payload().cropped(m_lastEnd);
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize());
m_lastEnd += m_lastItem.size();
}
return RLP(m_lastItem);
}
typedef RLP element_type;
class iterator
{
friend class RLP;
public:
typedef RLP value_type;
typedef RLP element_type;
iterator& operator++()
{
if (m_remaining)
{
m_lastItem.retarget(m_lastItem.next().data(), m_remaining);
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize());
m_remaining -= std::min<uint>(m_remaining, m_lastItem.size());
}
return *this;
}
iterator operator++(int) { auto ret = *this; operator++(); return ret; }
RLP operator*() const { return RLP(m_lastItem); }
bool operator==(iterator const& _cmp) const { return m_lastItem == _cmp.m_lastItem; }
bool operator!=(iterator const& _cmp) const { return !operator==(_cmp); }
private:
iterator() {}
iterator(bytesConstRef _payload, bool _begin)
{
if (_begin)
{
m_lastItem = _payload.cropped(RLP(_payload).actualSize());
m_remaining = _payload.size() - m_lastItem.size();
}
else
{
m_lastItem = _payload.cropped(m_lastItem.size());
m_remaining = 0;
}
}
uint m_remaining = 0;
bytesConstRef m_lastItem;
};
friend class iterator;
iterator begin() const { return iterator(payload(), true); }
iterator end() const { return iterator(payload(), false); }
explicit operator std::string() const { return toString(); }
explicit operator RLPs() const { return toList(); }
@ -115,6 +179,12 @@ public:
uint toSlimInt() const { return toInt<uint>(); }
u256 toFatInt() const { return toInt<u256>(); }
bigint toBigInt() const { return toInt<bigint>(); }
uint toSlimIntStrict() const { if (!isSlimInt()) throw BadCast(); return toInt<uint>(); }
u256 toFatIntStrict() const { if (!isFatInt() && !isSlimInt()) throw BadCast(); return toInt<u256>(); }
bigint toBigIntStrict() const { if (!isInt()) throw BadCast(); return toInt<bigint>(); }
uint toSlimIntFromString() const { if (!isString()) throw BadCast(); return toInt<uint>(); }
u256 toFatIntFromString() const { if (!isString()) throw BadCast(); return toInt<u256>(); }
bigint toBigIntFromString() const { if (!isString()) throw BadCast(); return toInt<bigint>(); }
RLPs toList() const
{
@ -122,9 +192,8 @@ public:
if (!isList())
return ret;
uint64_t c = items();
fConstBytes d = payload();
for (uint64_t i = 0; i < c; ++i, d = d.cropped(RLP(d).size()))
ret.push_back(RLP(d));
for (uint64_t i = 0; i < c; ++i)
ret.push_back(operator[](i));
return ret;
}
@ -144,7 +213,7 @@ private:
/// Direct-length list.
bool isSmallList() const { assert(!isNull()); return m_data[0] >= 0x80 && m_data[0] < 0xb8; }
uint size() const
uint actualSize() const
{
if (isNull())
return 0;
@ -154,9 +223,9 @@ private:
return payload().data() - m_data.data() + items();
if (isList())
{
fConstBytes d = payload();
bytesConstRef d = payload();
uint64_t c = items();
for (uint64_t i = 0; i < c; ++i, d = d.cropped(RLP(d).size())) {}
for (uint64_t i = 0; i < c; ++i, d = d.cropped(RLP(d).actualSize())) {}
return d.data() - m_data.data();
}
return 0;
@ -176,14 +245,17 @@ private:
return ret;
}
fConstBytes payload() const
bytesConstRef payload() const
{
assert(isString() || isList());
auto n = (m_data[0] & 0x3f);
return m_data.cropped(1 + (n < 0x38 ? 0 : (n - 0x37)));
}
fConstBytes m_data;
bytesConstRef m_data;
mutable uint m_lastIndex = (uint)-1;
mutable uint m_lastEnd;
mutable bytesConstRef m_lastItem;
};
struct RLPList { RLPList(uint _count): count(_count) {} uint count; };
@ -376,7 +448,7 @@ inline std::ostream& operator<<(std::ostream& _out, eth::RLP _d)
{
_out << "[";
int j = 0;
for (auto i: _d.toList())
for (auto i: _d)
_out << (j++ ? ", " : " ") << i;
_out << " ]";
}

85
libethereum/Trie.cpp

@ -62,7 +62,7 @@ u256 hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i
rlp << RLPList(2) << hexPrefixEncode(_begin->first, true, _preLen) << _begin->second;
#if ENABLE_DEBUG_PRINT
if (g_hashDebug)
std::cerr << s_indent << asHex(fConstBytes(_begin->first.data() + _preLen, _begin->first.size() - _preLen), 1) << ": " << _begin->second << " = " << sha256(rlp.out()) << std::endl;
std::cerr << s_indent << asHex(bytesConstRef(_begin->first.data() + _preLen, _begin->first.size() - _preLen), 1) << ": " << _begin->second << " = " << sha256(rlp.out()) << std::endl;
#endif
}
else
@ -83,9 +83,9 @@ u256 hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i
// if they all have the same next nibble, we also want a pair.
#if ENABLE_DEBUG_PRINT
if (g_hashDebug)
std::cerr << s_indent << asHex(fConstBytes(_begin->first.data() + _preLen, sharedPre), 1) << ": " << std::endl;
std::cerr << s_indent << asHex(bytesConstRef(_begin->first.data() + _preLen, sharedPre), 1) << ": " << std::endl;
#endif
rlp << RLPList(2) << hexPrefixEncode(_begin->first, false, _preLen, sharedPre) << toBigEndianString(hash256aux(_s, _begin, _end, sharedPre));
rlp << RLPList(2) << hexPrefixEncode(_begin->first, false, _preLen, sharedPre) << toCompactBigEndianString(hash256aux(_s, _begin, _end, sharedPre));
#if ENABLE_DEBUG_PRINT
if (g_hashDebug)
std::cerr << s_indent << "= " << sha256(rlp.out()) << std::endl;
@ -116,7 +116,7 @@ u256 hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i
if (g_hashDebug)
std::cerr << s_indent << std::hex << i << ": " << std::endl;
#endif
rlp << toBigEndianString(hash256aux(_s, b, n, _preLen + 1));
rlp << toCompactBigEndianString(hash256aux(_s, b, n, _preLen + 1));
}
b = n;
}
@ -149,6 +149,17 @@ u256 hash256(StringMap const& _s)
return hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0);
}
u256 hash256(u256Map const& _s)
{
// build patricia tree.
if (_s.empty())
return sha256(RLPNull);
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(toBigEndianString(i->first))] = rlp(i->second);
return hash256aux(hexMap, hexMap.cbegin(), hexMap.cend(), 0);
}
class TrieNode
{
@ -156,9 +167,9 @@ public:
TrieNode() {}
virtual ~TrieNode() {}
virtual std::string const& at(fConstBytes _key) const = 0;
virtual TrieNode* insert(fConstBytes _key, std::string const& _value) = 0;
virtual TrieNode* remove(fConstBytes _key) = 0;
virtual std::string const& at(bytesConstRef _key) const = 0;
virtual TrieNode* insert(bytesConstRef _key, std::string const& _value) = 0;
virtual TrieNode* remove(bytesConstRef _key) = 0;
virtual bytes rlp() const = 0;
#if ENABLE_DEBUG_PRINT
@ -173,7 +184,7 @@ protected:
virtual void debugPrintBody(std::string const& _indent = "") const = 0;
#endif
static TrieNode* newBranch(fConstBytes _k1, std::string const& _v1, fConstBytes _k2, std::string const& _v2);
static TrieNode* newBranch(bytesConstRef _k1, std::string const& _v1, bytesConstRef _k2, std::string const& _v2);
private:
mutable u256 m_sha256 = 0;
@ -184,7 +195,7 @@ static const std::string c_nullString;
class TrieExtNode: public TrieNode
{
public:
TrieExtNode(fConstBytes _bytes): m_ext(_bytes.begin(), _bytes.end()) {}
TrieExtNode(bytesConstRef _bytes): m_ext(_bytes.begin(), _bytes.end()) {}
bytes m_ext;
};
@ -231,9 +242,9 @@ public:
}
#endif
virtual std::string const& at(fConstBytes _key) const override;
virtual TrieNode* insert(fConstBytes _key, std::string const& _value) override;
virtual TrieNode* remove(fConstBytes _key) override;
virtual std::string const& at(bytesConstRef _key) const override;
virtual TrieNode* insert(bytesConstRef _key, std::string const& _value) override;
virtual TrieNode* remove(bytesConstRef _key) override;
virtual bytes rlp() const override;
private:
@ -249,7 +260,7 @@ private:
class TrieLeafNode: public TrieExtNode
{
public:
TrieLeafNode(fConstBytes _key, std::string const& _value): TrieExtNode(_key), m_value(_value) {}
TrieLeafNode(bytesConstRef _key, std::string const& _value): TrieExtNode(_key), m_value(_value) {}
#if ENABLE_DEBUG_PRINT
virtual void debugPrintBody(std::string const& _indent) const
@ -264,13 +275,13 @@ public:
}
#endif
virtual std::string const& at(fConstBytes _key) const override { return contains(_key) ? m_value : c_nullString; }
virtual TrieNode* insert(fConstBytes _key, std::string const& _value) override;
virtual TrieNode* remove(fConstBytes _key) override;
virtual std::string const& at(bytesConstRef _key) const override { return contains(_key) ? m_value : c_nullString; }
virtual TrieNode* insert(bytesConstRef _key, std::string const& _value) override;
virtual TrieNode* remove(bytesConstRef _key) override;
virtual bytes rlp() const override { return rlpListBytes(hexPrefixEncode(m_ext, true), m_value); }
private:
bool contains(fConstBytes _key) const { return _key.size() == m_ext.size() && !memcmp(_key.data(), m_ext.data(), _key.size()); }
bool contains(bytesConstRef _key) const { return _key.size() == m_ext.size() && !memcmp(_key.data(), m_ext.data(), _key.size()); }
std::string m_value;
};
@ -278,7 +289,7 @@ private:
class TrieInfixNode: public TrieExtNode
{
public:
TrieInfixNode(fConstBytes _key, TrieNode* _next): TrieExtNode(_key), m_next(_next) {}
TrieInfixNode(bytesConstRef _key, TrieNode* _next): TrieExtNode(_key), m_next(_next) {}
virtual ~TrieInfixNode() { delete m_next; }
#if ENABLE_DEBUG_PRINT
@ -289,18 +300,18 @@ public:
}
#endif
virtual std::string const& at(fConstBytes _key) const override { assert(m_next); return contains(_key) ? m_next->at(_key.cropped(m_ext.size())) : c_nullString; }
virtual TrieNode* insert(fConstBytes _key, std::string const& _value) override;
virtual TrieNode* remove(fConstBytes _key) override;
virtual bytes rlp() const override { assert(m_next); return rlpListBytes(hexPrefixEncode(m_ext, false), toBigEndianString(m_next->sha256())); }
virtual std::string const& at(bytesConstRef _key) const override { assert(m_next); return contains(_key) ? m_next->at(_key.cropped(m_ext.size())) : c_nullString; }
virtual TrieNode* insert(bytesConstRef _key, std::string const& _value) override;
virtual TrieNode* remove(bytesConstRef _key) override;
virtual bytes rlp() const override { assert(m_next); return rlpListBytes(hexPrefixEncode(m_ext, false), toCompactBigEndianString(m_next->sha256())); }
private:
bool contains(fConstBytes _key) const { return _key.size() >= m_ext.size() && !memcmp(_key.data(), m_ext.data(), m_ext.size()); }
bool contains(bytesConstRef _key) const { return _key.size() >= m_ext.size() && !memcmp(_key.data(), m_ext.data(), m_ext.size()); }
TrieNode* m_next;
};
TrieNode* TrieNode::newBranch(fConstBytes _k1, std::string const& _v1, fConstBytes _k2, std::string const& _v2)
TrieNode* TrieNode::newBranch(bytesConstRef _k1, std::string const& _v1, bytesConstRef _k2, std::string const& _v2)
{
uint prefix = commonPrefix(_k1, _k2);
@ -319,7 +330,7 @@ TrieNode* TrieNode::newBranch(fConstBytes _k1, std::string const& _v1, fConstByt
return ret;
}
std::string const& TrieBranchNode::at(fConstBytes _key) const
std::string const& TrieBranchNode::at(bytesConstRef _key) const
{
if (_key.empty())
return m_value;
@ -328,7 +339,7 @@ std::string const& TrieBranchNode::at(fConstBytes _key) const
return c_nullString;
}
TrieNode* TrieBranchNode::insert(fConstBytes _key, std::string const& _value)
TrieNode* TrieBranchNode::insert(bytesConstRef _key, std::string const& _value)
{
assert(_value.size());
mark();
@ -342,7 +353,7 @@ TrieNode* TrieBranchNode::insert(fConstBytes _key, std::string const& _value)
return this;
}
TrieNode* TrieBranchNode::remove(fConstBytes _key)
TrieNode* TrieBranchNode::remove(bytesConstRef _key)
{
if (_key.empty())
if (m_value.size())
@ -367,7 +378,7 @@ TrieNode* TrieBranchNode::rejig()
if (n == (byte)-1 && m_value.size())
{
// switch to leaf
auto r = new TrieLeafNode(fConstBytes(), m_value);
auto r = new TrieLeafNode(bytesConstRef(), m_value);
delete this;
return r;
}
@ -379,7 +390,7 @@ TrieNode* TrieBranchNode::rejig()
// switch to infix
m_nodes[n] = nullptr;
delete this;
return new TrieInfixNode(fConstBytes(&n, 1), b);
return new TrieInfixNode(bytesConstRef(&n, 1), b);
}
else
{
@ -401,7 +412,7 @@ bytes TrieBranchNode::rlp() const
RLPStream s;
s << RLPList(17);
for (auto i: m_nodes)
s << (i ? toBigEndianString(i->sha256()) : "");
s << (i ? toCompactBigEndianString(i->sha256()) : "");
s << m_value;
return s.out();
}
@ -420,7 +431,7 @@ byte TrieBranchNode::activeBranch() const
return n;
}
TrieNode* TrieInfixNode::insert(fConstBytes _key, std::string const& _value)
TrieNode* TrieInfixNode::insert(bytesConstRef _key, std::string const& _value)
{
assert(_value.size());
mark();
@ -458,7 +469,7 @@ TrieNode* TrieInfixNode::insert(fConstBytes _key, std::string const& _value)
}
}
TrieNode* TrieInfixNode::remove(fConstBytes _key)
TrieNode* TrieInfixNode::remove(bytesConstRef _key)
{
if (contains(_key))
{
@ -485,7 +496,7 @@ TrieNode* TrieInfixNode::remove(fConstBytes _key)
return this;
}
TrieNode* TrieLeafNode::insert(fConstBytes _key, std::string const& _value)
TrieNode* TrieLeafNode::insert(bytesConstRef _key, std::string const& _value)
{
assert(_value.size());
mark();
@ -497,13 +508,13 @@ TrieNode* TrieLeafNode::insert(fConstBytes _key, std::string const& _value)
else
{
// create new trie.
auto n = TrieNode::newBranch(_key, _value, fConstBytes(&m_ext), m_value);
auto n = TrieNode::newBranch(_key, _value, bytesConstRef(&m_ext), m_value);
delete this;
return n;
}
}
TrieNode* TrieLeafNode::remove(fConstBytes _key)
TrieNode* TrieLeafNode::remove(bytesConstRef _key)
{
if (contains(_key))
{
@ -541,7 +552,7 @@ std::string const& Trie::at(std::string const& _key) const
if (!m_root)
return c_nullString;
auto h = toHex(_key);
return m_root->at(fConstBytes(&h));
return m_root->at(bytesConstRef(&h));
}
void Trie::insert(std::string const& _key, std::string const& _value)
@ -549,7 +560,7 @@ void Trie::insert(std::string const& _key, std::string const& _value)
if (_value.empty())
remove(_key);
auto h = toHex(_key);
m_root = m_root ? m_root->insert(&h, _value) : new TrieLeafNode(fConstBytes(&h), _value);
m_root = m_root ? m_root->insert(&h, _value) : new TrieLeafNode(bytesConstRef(&h), _value);
}
void Trie::remove(std::string const& _key)

2
libethereum/Trie.h

@ -8,9 +8,11 @@ namespace eth
{
using StringMap = std::map<std::string, std::string>;
using u256Map = std::map<u256, u256>;
using HexMap = std::map<bytes, std::string>;
u256 hash256(StringMap const& _s);
u256 hash256(u256Map const& _s);
std::string hexPrefixEncode(bytes const& _hexVector, bool _terminated = false, int _begin = 0, int _end = -1);
class TrieNode;

196
libethereum/VirtualMachine.cpp

@ -12,130 +12,96 @@ u256 const State::c_extroFee = 0;
u256 const State::c_cryptoFee = 0;
u256 const State::c_newContractFee = 0;
u256 extractSender(u256 _v, u256 _r, u256 _s)
{
// TODO...
return _s;
}
template <class _T>
inline _T low160(_T const& _t)
{
return _t & ((((_T)1) << 160) - 1);
Transaction::Transaction(bytes const& _rlpData)
{
RLP rlp(_rlpData);
nonce = rlp[0].toFatIntFromString();
receiveAddress = as160(rlp[1].toFatIntFromString());
value = rlp[2].toFatIntStrict();
fee = rlp[3].toFatIntStrict();
data.reserve(rlp[4].itemCountStrict());
for (auto const& i: rlp[4])
data.push_back(i.toFatIntStrict());
vrs = Signature{ rlp[5].toFatIntFromString(), rlp[6].toFatIntFromString(), rlp[7].toFatIntFromString() };
}
bool State::transact(bytes const& _rlp)
bytes Transaction::rlp() const
{
RLP rlp(_rlp);
if (!rlp.isList())
return false;
RLPs items = rlp.toList();
// if (!items[0].isFixedInt())
// return false;
if (!items[0].isString())
return false;
u256 nonce = items[0].toFatInt();
// if (!(items[1].isEmpty() || items[1].isFixedInt()))
// return false;
if (!items[1].isString())
return false;
u256 address = items[1].toFatInt();
if (!items[2].isFixedInt())
return false;
u256 value = items[2].toFatInt();
if (!items[3].isFixedInt())
return false;
u256 fee = items[3].toFatInt();
if (!items[4].isList())
return false;
u256s data;
data.reserve(items[4].itemCount());
for (auto const& i: items[4].toList())
if (i.isFixedInt())
data.push_back(i.toFatInt());
RLPStream rlp;
rlp << RLPList(8);
if (nonce)
rlp << nonce;
else
return false;
if (!items[5].isString())
return false;
u256 v = items[5].toFatInt();
if (!items[6].isString())
return false;
u256 r = items[6].toFatInt();
if (!items[7].isString())
return false;
u256 s = items[7].toFatInt();
rlp << "";
if (receiveAddress)
rlp << toCompactBigEndianString(receiveAddress);
else
rlp << "";
rlp << value << fee << data << toCompactBigEndianString(vrs.v) << toCompactBigEndianString(vrs.r) << toCompactBigEndianString(vrs.s);
return rlp.out();
}
u256 sender;
try
// Entry point for a user-originated transaction.
bool State::execute(Transaction const& _t)
{
sender = extractSender(v, r, s);
return execute(_t, _t.vrs.address());
}
catch (...)
bool State::execute(Transaction const& _t, u160 _sender)
{
// Invalid signiture.
// Error reporting?
return false;
}
// Entry point for a contract-originated transaction.
if (nonce != transactionsFrom(sender))
if (_t.nonce != transactionsFrom(_sender))
{
// Nonce is wrong.
// Error reporting?
return false;
}
if (balance(sender) < value + fee)
if (balance(_sender) < _t.value + _t.fee)
{
// Sender balance too low.
// Error reporting?
return false;
}
if (address)
if (_t.receiveAddress)
{
assert(subBalance(sender, value));
addBalance(address, value);
assert(subBalance(_sender, _t.value));
addBalance(_t.receiveAddress, _t.value);
if (isContractAddress(address))
if (isContractAddress(_t.receiveAddress))
{
bool ret = true;
u256 minerFee = 0;
try
{
execute(address, sender, value, fee, data, &minerFee);
execute(_t.receiveAddress, _sender, _t.value, _t.fee, _t.data, &minerFee);
addBalance(m_minerAddress, minerFee);
return true;
}
catch (...)
{
// Execution error.
// Error reporting?
ret = false;
}
addBalance(m_minerAddress, minerFee);
return ret;
throw ExecutionException();
}
}
else
return true;
}
else
{
if (fee < data.size() * c_memoryFee + c_newContractFee)
if (_t.fee < _t.data.size() * c_memoryFee + c_newContractFee)
{
// Fee too small.
// Error reporting?
return false;
}
u256 newAddress = low160(sha256(_rlp));
u160 newAddress = low160(_t.sha256());
if (isContractAddress(newAddress))
{
// Contract collision.
@ -143,19 +109,23 @@ bool State::transact(bytes const& _rlp)
return false;
}
auto& mem = m_contractMemory[newAddress];
for (uint i = 0; i < data.size(); ++i)
mem[i] = data[i];
assert(subBalance(sender, value));
addBalance(newAddress, value);
//
auto& mem = m_current[newAddress].memory();
for (uint i = 0; i < _t.data.size(); ++i)
mem[i] = _t.data[i];
assert(subBalance(_sender, _t.value));
addBalance(newAddress, _t.value);
return true;
}
}
void State::execute(u256 _myAddress, u256 _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* _totalFee)
void State::execute(u160 _myAddress, u160 _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* _totalFee)
{
std::vector<u256> stack;
auto& myMemory = ensureMemory(_myAddress);
auto m = m_current.find(_myAddress);
if (m == m_current.end())
throw NoSuchContract();
auto& myMemory = m->second.memory();
auto require = [&](u256 _n)
{
@ -334,7 +304,7 @@ void State::execute(u256 _myAddress, u256 _txSender, u256 _txValue, u256 _txFee,
stack.push_back(m_previousBlock.hash);
break;
case Instruction::BLK_COINBASE:
stack.push_back(m_currentBlock.coinbase);
stack.push_back(m_currentBlock.coinbaseAddress);
break;
case Instruction::BLK_TIMESTAMP:
stack.push_back(m_currentBlock.timestamp);
@ -363,7 +333,8 @@ void State::execute(u256 _myAddress, u256 _txSender, u256 _txValue, u256 _txFee,
if (inst == Instruction::SHA256)
stack.back() = sha256(b);
else
// NOTE: this aligns to right of 256-bit container (low-order bytes). This won't work if they're treated as byte-arrays and thus left-aligned in a 256-bit container.
// NOTE: this aligns to right of 256-bit container (low-order bytes).
// This won't work if they're treated as byte-arrays and thus left-aligned in a 256-bit container.
stack.back() = ripemd160(&b);
break;
}
@ -447,69 +418,52 @@ void State::execute(u256 _myAddress, u256 _txSender, u256 _txValue, u256 _txFee,
require(2);
auto memoryAddress = stack.back();
stack.pop_back();
auto contractAddress = stack.back();
stack.back() = memory(contractAddress, memoryAddress);
u160 contractAddress = as160(stack.back());
stack.back() = contractMemory(contractAddress, memoryAddress);
break;
}
case Instruction::BALANCE:
{
require(1);
stack.back() = balance(stack.back());
stack.back() = balance(as160(stack.back()));
break;
}
case Instruction::MKTX:
{
require(4);
auto dest = stack.back();
stack.pop_back();
auto value = stack.back();
Transaction t;
t.receiveAddress = as160(stack.back());
stack.pop_back();
auto fee = stack.back();
t.value = stack.back();
stack.pop_back();
t.fee = stack.back();
stack.pop_back();
auto itemCount = stack.back();
stack.pop_back();
if (stack.size() < itemCount)
throw OperandOutOfRange(0, stack.size(), itemCount);
u256s data;
data.reserve((uint)itemCount);
t.data.reserve((uint)itemCount);
for (auto i = 0; i < itemCount; ++i)
{
data.push_back(stack.back());
t.data.push_back(stack.back());
stack.pop_back();
}
u256 nonce = transactionsFrom(_myAddress);
u256 v = 42; // TODO: turn our address into a v/r/s signature?
u256 r = 42;
u256 s = _myAddress;
// v/r/s are required to make the transaction hash (via the RLP serialisation) and thus are required in the creation of a contract.
RLPStream rlp;
if (nonce)
rlp << nonce;
else
rlp << "";
if (dest)
rlp << toBigEndianString(dest);
else
rlp << "";
rlp << value << fee << data << toBigEndianString(v) << toBigEndianString(r) << toBigEndianString(s);
transact(rlp.out());
t.nonce = transactionsFrom(_myAddress);
execute(t);
break;
}
case Instruction::SUICIDE:
{
require(1);
auto dest = stack.back();
u256 minusVoidFee = m_contractMemory[_myAddress].size() * c_memoryFee;
addBalance(dest, balance(_myAddress) + minusVoidFee - _txFee);
m_balance.erase(_myAddress);
m_contractMemory.erase(_myAddress);
u160 dest = as160(stack.back());
u256 minusVoidFee = m_current[_myAddress].memory().size() * c_memoryFee;
addBalance(dest, balance(_myAddress) + minusVoidFee);
subBalance(dest, _txFee);
m_current.erase(_myAddress);
// ...follow through to...
}
case Instruction::STOP:

170
libethereum/VirtualMachine.h

@ -4,6 +4,7 @@
#include <array>
#include <map>
#include <unordered_map>
#include "Trie.h"
#include "RLP.h"
#include "Common.h"
@ -67,14 +68,144 @@ enum class Instruction: uint8_t
class BadInstruction: public std::exception {};
class StackTooSmall: public std::exception { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
class OperandOutOfRange: public std::exception { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; };
class ExecutionException: public std::exception {};
class NoSuchContract: public std::exception {};
class InvalidTransactionFormat: public std::exception {};
class InvalidBlockFormat: public std::exception {};
class InvalidUnclesHash: public std::exception {};
class InvalidTransactionsHash: public std::exception {};
class InvalidTransaction: public std::exception {};
class InvalidDifficulty: public std::exception {};
class InvalidTimestamp: public std::exception {};
class InvalidNonce: public std::exception {};
struct BlockInfo
{
public:
u256 hash;
u256 coinbase;
u256 parentHash;
u256 sha256Uncles;
u256 coinbaseAddress;
u256 sha256Transactions;
u256 difficulty;
u256 timestamp;
u256 nonce;
u256 number;
u256 difficulty;
void populateAndVerify(bytesConstRef _block, u256 _number)
{
number = _number;
RLP root(_block);
try
{
RLP header = root[0];
hash = eth::sha256(_block);
parentHash = header[0].toFatInt();
sha256Uncles = header[1].toFatInt();
coinbaseAddress = header[2].toFatInt();
sha256Transactions = header[3].toFatInt();
difficulty = header[4].toFatInt();
timestamp = header[5].toFatInt();
nonce = header[6].toFatInt();
}
catch (RLP::BadCast)
{
throw InvalidBlockFormat();
}
if (sha256Transactions != sha256(root[1].data()))
throw InvalidTransactionsHash();
if (sha256Uncles != sha256(root[2].data()))
throw InvalidUnclesHash();
// TODO: check timestamp.
// TODO: check difficulty against timestamp.
// TODO: check proof of work.
// TODO: check each transaction.
}
};
enum class AddressType
{
Normal,
Contract
};
class AddressState
{
public:
AddressState(AddressType _type = AddressType::Normal): m_type(_type), m_balance(0), m_nonce(0) {}
AddressType type() const { return m_type; }
u256& balance() { return m_balance; }
u256 const& balance() const { return m_balance; }
u256& nonce() { return m_nonce; }
u256 const& nonce() const { return m_nonce; }
std::map<u256, u256>& memory() { assert(m_type == AddressType::Contract); return m_memory; }
std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract); return m_memory; }
u256 memoryHash() const
{
return hash256(m_memory);
}
std::string toString() const
{
if (m_type == AddressType::Normal)
return rlpList(m_balance, toCompactBigEndianString(m_nonce));
if (m_type == AddressType::Contract)
return rlpList(m_balance, toCompactBigEndianString(m_nonce), toCompactBigEndianString(memoryHash()));
return "";
}
private:
AddressType m_type;
u256 m_balance;
u256 m_nonce;
u256Map m_memory;
};
template <class _T>
inline u160 low160(_T const& _t)
{
return (u160)(_t & ((((_T)1) << 160) - 1));
}
template <class _T>
inline u160 as160(_T const& _t)
{
return (u160)(_t & ((((_T)1) << 160) - 1));
}
struct Signature
{
u256 v;
u256 r;
u256 s;
u160 address() const { return as160(s); } // TODO!
};
// [ nonce, receiving_address, value, fee, [ data item 0, data item 1 ... data item n ], v, r, s ]
struct Transaction
{
Transaction() {}
Transaction(bytes const& _rlp);
u256 nonce;
u160 receiveAddress;
u256 value;
u256 fee;
u256s data;
Signature vrs;
bytes rlp() const;
u256 sha256() const { return eth::sha256(rlp()); }
};
class State
@ -82,38 +213,41 @@ class State
public:
explicit State(u256 _minerAddress): m_minerAddress(_minerAddress) {}
bool transact(bytes const& _rlp);
bool verify(bytes const& _block);
bool execute(bytes const& _rlp) { try { Transaction t(_rlp); return execute(t); } catch (...) { return false; } }
private:
bool isContractAddress(u256 _address) const { return m_contractMemory.count(_address); }
bool execute(Transaction const& _t);
bool execute(Transaction const& _t, u160 _sender);
bool isNormalAddress(u160 _address) const { auto it = m_current.find(_address); return it != m_current.end() && it->second.type() == AddressType::Normal; }
bool isContractAddress(u160 _address) const { auto it = m_current.find(_address); return it != m_current.end() && it->second.type() == AddressType::Contract; }
u256 balance(u256 _id) const { auto it = m_balance.find(_id); return it == m_balance.end() ? 0 : it->second; }
void addBalance(u256 _id, u256 _amount) { auto it = m_balance.find(_id); if (it == m_balance.end()) it->second = _amount; else it->second += _amount; }
u256 balance(u160 _id) const { auto it = m_current.find(_id); return it == m_current.end() ? 0 : it->second.balance(); }
void addBalance(u160 _id, u256 _amount) { auto it = m_current.find(_id); if (it == m_current.end()) it->second.balance() = _amount; else it->second.balance() += _amount; }
// bigint as we don't want any accidental problems with -ve numbers.
bool subBalance(u256 _id, bigint _amount) { auto it = m_balance.find(_id); if (it == m_balance.end() || (bigint)it->second < _amount) return false; it->second = (u256)((bigint)it->second - _amount); return true; }
bool subBalance(u160 _id, bigint _amount) { auto it = m_current.find(_id); if (it == m_current.end() || (bigint)it->second.balance() < _amount) return false; it->second.balance() = (u256)((bigint)it->second.balance() - _amount); return true; }
u256 memory(u256 _contract, u256 _memory) const
u256 contractMemory(u160 _contract, u256 _memory) const
{
auto m = m_contractMemory.find(_contract);
if (m == m_contractMemory.end())
auto m = m_current.find(_contract);
if (m == m_current.end())
return 0;
auto i = m->second.find(_memory);
return i == m->second.end() ? 0 : i->second;
auto i = m->second.memory().find(_memory);
return i == m->second.memory().end() ? 0 : i->second;
}
u256 transactionsFrom(u256 _address) { return 0; } // TODO
u256 transactionsFrom(u160 _address) { auto it = m_current.find(_address); return it == m_current.end() ? 0 : it->second.nonce(); }
void execute(u256 _myAddress, u256 _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* _totalFee);
void execute(u160 _myAddress, u160 _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* o_totalFee);
std::map<u256, u256>& ensureMemory(u256 _contract) { return m_contractMemory[_contract]; }
std::map<u160, AddressState> m_current;
std::map<u256, std::map<u256, u256>> m_contractMemory;
std::map<u256, u256> m_balance; // for now - might end up using Trie?
BlockInfo m_previousBlock;
BlockInfo m_currentBlock;
u256 m_minerAddress;
u160 m_minerAddress;
static const u256 c_stepFee;
static const u256 c_dataFee;

51
libethereum/foreign.h

@ -1,51 +0,0 @@
#pragma once
#include <cassert>
#include <vector>
#include <string>
namespace eth
{
template <class _T>
class foreign
{
public:
typedef _T value_type;
typedef _T element_type;
foreign(): m_data(nullptr), m_count(0) {}
foreign(std::vector<typename std::remove_const<_T>::type>* _data): m_data(_data->data()), m_count(_data->size()) {}
foreign(_T* _data, unsigned _count): m_data(_data), m_count(_count) {}
explicit operator bool() const { return m_data && m_count; }
std::vector<_T> toVector() const { return std::vector<_T>(m_data, m_data + m_count); }
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count); }
template <class _T2> operator foreign<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return foreign<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); }
_T* data() const { return m_data; }
unsigned count() const { return m_count; }
unsigned size() const { return m_count; }
unsigned empty() const { return !m_count; }
foreign<_T> next() const { return foreign<_T>(m_data + m_count, m_count); }
foreign<_T> cropped(unsigned _begin, int _count = -1) const { if (m_data && _begin + std::max(0, _count) <= m_count) return foreign<_T>(m_data + _begin, _count < 0 ? m_count - _begin : _count); else return foreign<_T>(); }
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(); }
_T* begin() { return m_data; }
_T* end() { return m_data + m_count; }
_T const* begin() const { return m_data; }
_T const* end() const { return m_data + m_count; }
_T& operator[](unsigned _i) { assert(m_data); assert(_i < m_count); return m_data[_i]; }
_T const& operator[](unsigned _i) const { assert(m_data); assert(_i < m_count); return m_data[_i]; }
void reset() { m_data = nullptr; m_count = 0; }
private:
_T* m_data;
unsigned m_count;
};
}

14
libethereum/sha256.cpp

@ -194,3 +194,17 @@ u256 eth::sha256(bytes const& _input)
ret = (ret << 8) | buf[i];
return ret;
}
u256 eth::sha256(bytesConstRef _input)
{
u256 ret = 0;
SHA256 ctx = SHA256();
ctx.init();
ctx.update(_input.data(), _input.size());
uint8_t buf[SHA256::DIGEST_SIZE];
ctx.final(buf);
for (unsigned i = 0; i < 32; ++i)
ret = (ret << 8) | buf[i];
return ret;
}

1
libethereum/sha256.h

@ -27,6 +27,7 @@ protected:
std::string sha256(std::string const& input, bool _hex);
u256 sha256(bytes const& input);
u256 sha256(bytesConstRef input);
#define SHA2_SHFR(x, n) (x >> n)
#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))

Loading…
Cancel
Save