Browse Source

More on JS API types. CODECOPY & CODESIZE. Fixed && operator.

cl-refactor
Gav Wood 11 years ago
parent
commit
fc5e1e4839
  1. 12
      libethcore/CommonData.h
  2. 6
      libethereum/Instruction.cpp
  3. 2
      libethereum/Instruction.h
  4. 25
      libethereum/VM.h
  5. 81
      libqethereum/QEthereum.cpp
  6. 31
      libqethereum/QEthereum.h

12
libethcore/CommonData.h

@ -105,6 +105,18 @@ inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toB
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
/// Convenience function for toBigEndian.
/// @returns a byte array just big enough to represent @a _val.
template <class _T>
inline bytes toCompactBigEndian(_T _val)
{
int i = 0;
for (_T v = _val; v; ++i, v >>= 8) {}
bytes ret(i, 0);
toBigEndian(_val, ret);
return ret;
}
/// Convenience function for toBigEndian. /// Convenience function for toBigEndian.
/// @returns a string just big enough to represent @a _val. /// @returns a string just big enough to represent @a _val.
template <class _T> template <class _T>

6
libethereum/Instruction.cpp

@ -57,6 +57,8 @@ const std::map<std::string, Instruction> eth::c_instructions =
{ "CALLDATALOAD", Instruction::CALLDATALOAD }, { "CALLDATALOAD", Instruction::CALLDATALOAD },
{ "CALLDATASIZE", Instruction::CALLDATASIZE }, { "CALLDATASIZE", Instruction::CALLDATASIZE },
{ "CALLDATACOPY", Instruction::CALLDATACOPY }, { "CALLDATACOPY", Instruction::CALLDATACOPY },
{ "CODESIZE", Instruction::CODESIZE },
{ "CODECOPY", Instruction::CODECOPY },
{ "GASPRICE", Instruction::GASPRICE }, { "GASPRICE", Instruction::GASPRICE },
{ "PREVHASH", Instruction::PREVHASH }, { "PREVHASH", Instruction::PREVHASH },
{ "COINBASE", Instruction::COINBASE }, { "COINBASE", Instruction::COINBASE },
@ -144,6 +146,8 @@ const std::map<Instruction, InstructionInfo> eth::c_instructionInfo =
{ Instruction::CALLDATALOAD, { "CALLDATALOAD", 0, 1, 1 } }, { Instruction::CALLDATALOAD, { "CALLDATALOAD", 0, 1, 1 } },
{ Instruction::CALLDATASIZE, { "CALLDATASIZE", 0, 0, 1 } }, { Instruction::CALLDATASIZE, { "CALLDATASIZE", 0, 0, 1 } },
{ Instruction::CALLDATACOPY, { "CALLDATACOPY", 0, 3, 0 } }, { Instruction::CALLDATACOPY, { "CALLDATACOPY", 0, 3, 0 } },
{ Instruction::CODESIZE, { "CODESIZE", 0, 0, 1 } },
{ Instruction::CODECOPY, { "CODECOPY", 0, 3, 0 } },
{ Instruction::GASPRICE, { "GASPRICE", 0, 0, 1 } }, { Instruction::GASPRICE, { "GASPRICE", 0, 0, 1 } },
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1 } }, { Instruction::PREVHASH, { "PREVHASH", 0, 0, 1 } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1 } }, { Instruction::COINBASE, { "COINBASE", 0, 0, 1 } },
@ -783,6 +787,7 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, bytes
{ {
// Check if true - predicate // Check if true - predicate
appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]); appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]);
o_code.push_back((byte)Instruction::NOT);
// Push the false location. // Push the false location.
ends.push_back((unsigned)o_code.size()); ends.push_back((unsigned)o_code.size());
@ -790,7 +795,6 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, bytes
pushLocation(o_code, 0); pushLocation(o_code, 0);
// Jump to end... // Jump to end...
o_code.push_back((byte)Instruction::NOT);
o_code.push_back((byte)Instruction::JUMPI); o_code.push_back((byte)Instruction::JUMPI);
} }
o_code.push_back((byte)Instruction::POP); o_code.push_back((byte)Instruction::POP);

2
libethereum/Instruction.h

@ -61,6 +61,8 @@ enum class Instruction: uint8_t
CALLDATALOAD, CALLDATALOAD,
CALLDATASIZE, CALLDATASIZE,
CALLDATACOPY, CALLDATACOPY,
CODESIZE,
CODECOPY,
GASPRICE, GASPRICE,
PREVHASH = 0x40, PREVHASH = 0x40,

25
libethereum/VM.h

@ -137,6 +137,10 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
require(3); require(3);
newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 3]; newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 3];
break; break;
case Instruction::CODECOPY:
require(3);
newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 3];
break;
case Instruction::BALANCE: case Instruction::BALANCE:
runGas = c_balanceGas; runGas = c_balanceGas;
@ -328,7 +332,26 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
m_stack.pop_back(); m_stack.pop_back();
unsigned l = (unsigned)m_stack.back(); unsigned l = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
memcpy(m_temp.data() + mf, _ext.data.data() + cf, l); unsigned el = cf + l > _ext.data.size() ? _ext.data.size() - cf : l;
memcpy(m_temp.data() + mf, _ext.data.data() + cf, el);
memset(m_temp.data() + mf + el, 0, l - el);
break;
}
case Instruction::CODESIZE:
m_stack.push_back(_ext.code.size());
break;
case Instruction::CODECOPY:
{
require(3);
unsigned mf = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned cf = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned l = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned el = cf + l > _ext.code.size() ? _ext.code.size() - cf : l;
memcpy(m_temp.data() + mf, _ext.code.data() + cf, el);
memset(m_temp.data() + mf + el, 0, l - el);
break; break;
} }
case Instruction::GASPRICE: case Instruction::GASPRICE:

81
libqethereum/QEthereum.cpp

@ -189,12 +189,8 @@ eth::bytes toBytes(QString const& _s)
// Hex // Hex
return eth::fromHex(_s.mid(2).toStdString()); return eth::fromHex(_s.mid(2).toStdString());
else if (!_s.contains(QRegExp("[^0-9]"))) else if (!_s.contains(QRegExp("[^0-9]")))
{
// Decimal // Decimal
eth::bytes ret; return eth::toCompactBigEndian(eth::bigint(_s.toStdString()));
eth::toBigEndian(eth::bigint(_s.toStdString()), ret);
return ret;
}
else else
// Binary // Binary
return eth::asBytes(_s.toStdString()); return eth::asBytes(_s.toStdString());
@ -207,8 +203,24 @@ QString padded(QString const& _s, unsigned _l, unsigned _r)
b.insert(b.begin(), 0); b.insert(b.begin(), 0);
while (b.size() < _r) while (b.size() < _r)
b.push_back(0); b.push_back(0);
b.resize(_r); return QString::fromStdString(eth::asString(b).substr(b.size() - max(_l, _r)));
return QString::fromStdString(eth::asString(b)); }
QString padded(QString const& _s, unsigned _l)
{
if (_s.startsWith("0x") || !_s.contains(QRegExp("[^0-9]")))
// Numeric: pad to right
return padded(_s, _l, _l);
else
// Text: pad to the left
return padded(_s, 0, _l);
}
QString unpadded(QString _s)
{
while (_s.size() && _s.endsWith(QChar(0)))
_s.chop(1);
return _s;
} }
QEthereum::QEthereum(QObject* _p, Client* _c, QList<eth::KeyPair> _accounts): QObject(_p), m_client(_c), m_accounts(_accounts) QEthereum::QEthereum(QObject* _p, Client* _c, QList<eth::KeyPair> _accounts): QObject(_p), m_client(_c), m_accounts(_accounts)
@ -225,9 +237,9 @@ void QEthereum::setup(QWebFrame* _e)
// disconnect // disconnect
disconnect(SIGNAL(changed())); disconnect(SIGNAL(changed()));
_e->addToJavaScriptWindowObject("eth", this, QWebFrame::ScriptOwnership); _e->addToJavaScriptWindowObject("eth", this, QWebFrame::ScriptOwnership);
_e->addToJavaScriptWindowObject("u256", new U256Helper, QWebFrame::ScriptOwnership); /* _e->addToJavaScriptWindowObject("u256", new U256Helper, QWebFrame::ScriptOwnership);
_e->addToJavaScriptWindowObject("key", new KeyHelper, QWebFrame::ScriptOwnership); _e->addToJavaScriptWindowObject("key", new KeyHelper, QWebFrame::ScriptOwnership);
_e->addToJavaScriptWindowObject("bytes", new BytesHelper, QWebFrame::ScriptOwnership); _e->addToJavaScriptWindowObject("bytes", new BytesHelper, QWebFrame::ScriptOwnership);*/
_e->evaluateJavaScript("eth.newBlock = function(f) { eth.changed.connect(f) }"); _e->evaluateJavaScript("eth.newBlock = function(f) { eth.changed.connect(f) }");
_e->evaluateJavaScript("eth.watch = function(a, s, f) { eth.changed.connect(f ? f : s) }"); _e->evaluateJavaScript("eth.watch = function(a, s, f) { eth.changed.connect(f ? f : s) }");
_e->evaluateJavaScript("eth.create = function(s, v, c, g, p, f) { eth.doCreate(s, v, c, g, p); if (f) f() }"); _e->evaluateJavaScript("eth.create = function(s, v, c, g, p, f) { eth.doCreate(s, v, c, g, p); if (f) f() }");
@ -235,6 +247,7 @@ void QEthereum::setup(QWebFrame* _e)
_e->evaluateJavaScript("String.prototype.pad = function(l, r) { return eth.pad(this, l, r) }"); _e->evaluateJavaScript("String.prototype.pad = function(l, r) { return eth.pad(this, l, r) }");
_e->evaluateJavaScript("String.prototype.bin = function(l) { return eth.toBinary(this) }"); _e->evaluateJavaScript("String.prototype.bin = function(l) { return eth.toBinary(this) }");
_e->evaluateJavaScript("String.prototype.unbin = function(l) { return eth.fromBinary(this) }"); _e->evaluateJavaScript("String.prototype.unbin = function(l) { return eth.fromBinary(this) }");
_e->evaluateJavaScript("String.prototype.unpad = function(l) { return eth.unpad(this) }");
} }
void QEthereum::teardown(QWebFrame*) void QEthereum::teardown(QWebFrame*)
@ -246,58 +259,58 @@ Client* QEthereum::client() const
return m_client; return m_client;
} }
QVariant QEthereum::coinbase() const QString QEthereum::coinbase() const
{ {
return toQJS(client()->address()); return toQJS(client()->address());
} }
QVariant QEthereum::account() const QString QEthereum::account() const
{ {
if (m_accounts.empty()) if (m_accounts.empty())
return toQJS(Address()); return toQJS(Address());
return toQJS(m_accounts[0].address()); return toQJS(m_accounts[0].address());
} }
QList<QVariant> QEthereum::accounts() const QStringList QEthereum::accounts() const
{ {
QList<QVariant> ret; QStringList ret;
for (auto i: m_accounts) for (auto i: m_accounts)
ret.push_back(toQJS(i.address())); ret.push_back(toQJS(i.address()));
return ret; return ret;
} }
QVariant QEthereum::key() const QString QEthereum::key() const
{ {
if (m_accounts.empty()) if (m_accounts.empty())
return toQJS(KeyPair()); return toQJS(KeyPair().sec());
return toQJS(m_accounts[0]); return toQJS(m_accounts[0].sec());
} }
QList<QVariant> QEthereum::keys() const QStringList QEthereum::keys() const
{ {
QList<QVariant> ret; QStringList ret;
for (auto i: m_accounts) for (auto i: m_accounts)
ret.push_back(toQJS(i)); ret.push_back(toQJS(i.sec()));
return ret; return ret;
} }
void QEthereum::setCoinbase(QVariant _a) void QEthereum::setCoinbase(QString _a)
{ {
if (client()->address() != to<Address>(_a)) if (client()->address() != toAddress(_a))
{ {
client()->setAddress(to<Address>(_a)); client()->setAddress(toAddress(_a));
changed(); changed();
} }
} }
QVariant QEthereum::balanceAt(QVariant _a) const QString QEthereum::balanceAt(QString _a) const
{ {
return toQJS(client()->postState().balance(to<Address>(_a))); return toQJS(client()->postState().balance(toAddress(_a)));
} }
QVariant QEthereum::storageAt(QVariant _a, QVariant _p) const QString QEthereum::storageAt(QString _a, QString _p) const
{ {
return toQJS(client()->postState().storage(to<Address>(_a), to<u256>(_p))); return toQJS(client()->postState().storage(toAddress(_a), toU256(_p)));
} }
u256 QEthereum::balanceAt(Address _a) const u256 QEthereum::balanceAt(Address _a) const
@ -305,9 +318,9 @@ u256 QEthereum::balanceAt(Address _a) const
return client()->postState().balance(_a); return client()->postState().balance(_a);
} }
bool QEthereum::isContractAt(QVariant _a) const bool QEthereum::isContractAt(QString _a) const
{ {
return client()->postState().addressHasCode(to<Address>(_a)); return client()->postState().addressHasCode(toAddress(_a));
} }
bool QEthereum::isContractAt(Address _a) const bool QEthereum::isContractAt(Address _a) const
@ -341,9 +354,9 @@ void QEthereum::setListening(bool _l)
client()->stopNetwork(); client()->stopNetwork();
} }
double QEthereum::txCountAt(QVariant _a) const double QEthereum::txCountAt(QString _a) const
{ {
return (double)client()->postState().transactionsFrom(to<Address>(_a)); return (double)client()->postState().transactionsFrom(toAddress(_a));
} }
double QEthereum::txCountAt(Address _a) const double QEthereum::txCountAt(Address _a) const
@ -356,14 +369,14 @@ unsigned QEthereum::peerCount() const
return (unsigned)client()->peerCount(); return (unsigned)client()->peerCount();
} }
QVariant QEthereum::doCreate(QVariant _secret, QVariant _amount, QByteArray _init, QVariant _gas, QVariant _gasPrice) QString QEthereum::doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice)
{ {
return toQJS(client()->transact(to<Secret>(_secret), to<u256>(_amount), bytes(_init.data(), _init.data() + _init.size()), to<u256>(_gas), to<u256>(_gasPrice))); return toQJS(client()->transact(toSecret(_secret), toU256(_amount), toBytes(_init), toU256(_gas), toU256(_gasPrice)));
} }
void QEthereum::doTransact(QVariant _secret, QVariant _amount, QVariant _dest, QByteArray _data, QVariant _gas, QVariant _gasPrice) void QEthereum::doTransact(QString _secret, QString _amount, QString _dest, QString _data, QString _gas, QString _gasPrice)
{ {
client()->transact(to<Secret>(_secret), to<u256>(_amount), to<Address>(_dest), bytes(_data.data(), _data.data() + _data.size()), to<u256>(_gas), to<u256>(_gasPrice)); client()->transact(toSecret(_secret), toU256(_amount), toAddress(_dest), toBytes(_data), toU256(_gas), toU256(_gasPrice));
} }
// extra bits needed to link on VS // extra bits needed to link on VS

31
libqethereum/QEthereum.h

@ -159,6 +159,7 @@ private:
Q_PROPERTY(bool mining READ isMining WRITE setMining) Q_PROPERTY(bool mining READ isMining WRITE setMining)
}; };
#if 0
template <class T> T to(QVariant const& _s) { if (_s.type() != QVariant::String) return T(); auto s = _s.toString().toLatin1(); assert(s.size() == sizeof(T)); return *(T*)s.data(); } template <class T> T to(QVariant const& _s) { if (_s.type() != QVariant::String) return T(); auto s = _s.toString().toLatin1(); assert(s.size() == sizeof(T)); return *(T*)s.data(); }
template <class T> QVariant toQJS(T const& _s) { QLatin1String ret((char*)&_s, sizeof(T)); assert(QVariant(QString(ret)).toString().toLatin1().size() == sizeof(T)); assert(*(T*)(QVariant(QString(ret)).toString().toLatin1().data()) == _s); return QVariant(QString(ret)); } template <class T> QVariant toQJS(T const& _s) { QLatin1String ret((char*)&_s, sizeof(T)); assert(QVariant(QString(ret)).toString().toLatin1().size() == sizeof(T)); assert(*(T*)(QVariant(QString(ret)).toString().toLatin1().data()) == _s); return QVariant(QString(ret)); }
@ -282,33 +283,43 @@ public:
return toQJS<eth::u256>(ret); return toQJS<eth::u256>(ret);
} }
}; };
#endif
eth::bytes toBytes(QString const& _s); eth::bytes toBytes(QString const& _s);
QString padded(QString const& _s, unsigned _l, unsigned _r); QString padded(QString const& _s, unsigned _l, unsigned _r);
QString padded(QString const& _s, unsigned _l);
QString unpadded(QString _s);
template <class H> H toFixed(QString const& _s) template <unsigned N> eth::FixedHash<N> toFixed(QString const& _s)
{ {
if (_s.startsWith("0x")) if (_s.startsWith("0x"))
// Hex // Hex
return H(_s.mid(2)); return eth::FixedHash<N>(_s.mid(2).toStdString());
else if (!_s.contains(QRegExp("[^0-9]"))) else if (!_s.contains(QRegExp("[^0-9]")))
// Decimal // Decimal
return (typename H::Arith)(_s); return (typename eth::FixedHash<N>::Arith)(_s.toStdString());
else else
// Binary // Binary
return H(toBytes(_s)); return eth::FixedHash<N>(eth::asBytes(padded(_s, N).toStdString()));
} }
template <class I> I toInt(QString const& _s) template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> toInt(QString const& _s)
{ {
if (_s.startsWith("0x") || !_s.contains(QRegExp("[^0-9]"))) if (_s.startsWith("0x") || !_s.contains(QRegExp("[^0-9]")))
// Hex or Decimal // Hex or Decimal
return (I)eth::bigint(_s); return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s.toStdString());
else else
// Binary // Binary
return eth::fromBigEndian<I>(toBytes(_s)); return eth::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(eth::asBytes(padded(_s, N).toStdString()));
} }
inline eth::Address toAddress(QString const& _s) { return toFixed<20>(_s); }
inline eth::Secret toSecret(QString const& _s) { return toFixed<32>(_s); }
inline eth::u256 toU256(QString const& _s) { return toInt<32>(_s); }
template <unsigned S> QString toQJS(eth::FixedHash<S> const& _h) { return QString::fromStdString("0x" + toHex(_h.ref())); }
template <unsigned N> QString toQJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n) { return QString::fromStdString("0x" + eth::toHex(eth::toCompactBigEndian(_n))); }
inline QString toBinary(QString const& _s) inline QString toBinary(QString const& _s)
{ {
return QString::fromStdString(eth::asString(toBytes(_s))); return QString::fromStdString(eth::asString(toBytes(_s)));
@ -335,7 +346,9 @@ public:
Q_INVOKABLE QString ethTest() const { return "Hello world!"; } Q_INVOKABLE QString ethTest() const { return "Hello world!"; }
Q_INVOKABLE QEthereum* self() { return this; } Q_INVOKABLE QEthereum* self() { return this; }
Q_INVOKABLE QString pad(QString _s, unsigned _l) const { return padded(_s, _l); }
Q_INVOKABLE QString pad(QString _s, unsigned _l, unsigned _r) const { return padded(_s, _l, _r); } Q_INVOKABLE QString pad(QString _s, unsigned _l, unsigned _r) const { return padded(_s, _l, _r); }
Q_INVOKABLE QString unpad(QString _s) const { return unpadded(_s); }
Q_INVOKABLE QString toBinary(QString _s) const { return ::toBinary(_s); } Q_INVOKABLE QString toBinary(QString _s) const { return ::toBinary(_s); }
Q_INVOKABLE QString fromBinary(QString _s) const { return ::fromBinary(_s); } Q_INVOKABLE QString fromBinary(QString _s) const { return ::fromBinary(_s); }
@ -351,7 +364,7 @@ public:
bool isMining() const; bool isMining() const;
QString/*eth::Address*/ coinbase() const; QString/*eth::Address*/ coinbase() const;
QString/*eth::u256*/ gasPrice() const { return toString(10 * eth::szabo); } QString/*eth::u256*/ gasPrice() const { return toQJS(10 * eth::szabo); }
eth::u256 balanceAt(eth::Address _a) const; eth::u256 balanceAt(eth::Address _a) const;
double txCountAt(eth::Address _a) const; double txCountAt(eth::Address _a) const;
@ -380,7 +393,7 @@ private:
Q_PROPERTY(bool mining READ isMining WRITE setMining) Q_PROPERTY(bool mining READ isMining WRITE setMining)
Q_PROPERTY(QString gasPrice READ gasPrice NOTIFY changed) Q_PROPERTY(QString gasPrice READ gasPrice NOTIFY changed)
Q_PROPERTY(QString key READ key NOTIFY changed) Q_PROPERTY(QString key READ key NOTIFY changed)
Q_PROPERTY(QString keys READ keys NOTIFY changed) Q_PROPERTY(QStringList keys READ keys NOTIFY changed)
Q_PROPERTY(unsigned peerCount READ peerCount) Q_PROPERTY(unsigned peerCount READ peerCount)
eth::Client* m_client; eth::Client* m_client;

Loading…
Cancel
Save