diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 47beb94a3..673973fbd 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -333,6 +333,28 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ m_tq.attemptImport(t.rlp()); } +bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +{ + State temp; + Transaction t; +// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + { + ReadGuard l(x_stateDB); + temp = m_postMine; + t.nonce = temp.transactionsFrom(toAddress(_secret)); + } + t.value = _value; + t.gasPrice = _gasPrice; + t.gas = _gas; + t.receiveAddress = _dest; + t.data = _data; + t.sign(_secret); + bytes out; + u256 gasUsed = temp.execute(t.data, &out, false); + (void)gasUsed; // TODO: do something with gasused which it returns. + return out; +} + Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { ensureWorking(); diff --git a/libethereum/Client.h b/libethereum/Client.h index e9b10b538..c761e3d0f 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -180,14 +180,14 @@ public: /// @returns the new contract's address (assuming it all goes through). Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo); - /// Blocks until all pending transactions have been processed. - void flushTransactions(); - /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. void inject(bytesConstRef _rlp); - /// Makes the given call. Nothing is recorded into the state. TODO -// bytes call(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes()); + /// Blocks until all pending transactions have been processed. + void flushTransactions(); + + /// Makes the given call. Nothing is recorded into the state. + bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); // Informational stuff diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index f6b114b6f..1ae2fef21 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -131,6 +131,11 @@ QString QEthereum::sha3(QString _s) const return toQJS(eth::sha3(asBytes(_s))); } +QString QEthereum::offset(QString _s, int _i) const +{ + return toQJS(toU256(_s) + _i); +} + QString QEthereum::coinbase() const { return m_client ? toQJS(client()->address()) : ""; @@ -277,6 +282,45 @@ static eth::MessageFilter toMessageFilter(QString _json) return filter; } +struct TransactionSkeleton +{ + Secret from; + Address to; + u256 value; + bytes data; + u256 gas; + u256 gasPrice; +}; + +static TransactionSkeleton toTransaction(QString _json) +{ + TransactionSkeleton ret; + + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); + if (f.contains("from")) + ret.from = toSecret(f["from"].toString()); + if (f.contains("to")) + ret.to = toAddress(f["to"].toString()); + if (f.contains("value")) + ret.value = toU256(f["value"].toString()); + if (f.contains("gas")) + ret.gas = toU256(f["gas"].toString()); + if (f.contains("gasPrice")) + ret.gasPrice = toU256(f["gasPrice"].toString()); + if (f.contains("data")) + { + if (f["data"].isString()) + ret.data = toBytes(f["data"].toString()); + else if (f["data"].isArray()) + for (auto i: f["data"].toArray()) + eth::operator +=(ret.data, toBytes(padded(i.toString(), 32))); + else if (f["dataclose"].isArray()) + for (auto i: f["dataclose"].toArray()) + eth::operator +=(ret.data, toBytes(toBinary(i.toString()))); + } + return ret; +} + static QString toJson(eth::PastMessages const& _pms) { QJsonArray jsonArray; @@ -359,6 +403,41 @@ void QEthereum::doTransact(QString _secret, QString _amount, QString _dest, QStr client()->flushTransactions(); } +void QEthereum::doTransact(QString _json) +{ + if (!m_client) + return; + TransactionSkeleton t = toTransaction(_json); + if (!t.from && m_accounts.size()) + t.from = m_accounts[0].secret(); + if (!t.gasPrice) + t.gasPrice = 10 * eth::szabo; + if (!t.gas) + t.gas = client()->balanceAt(KeyPair(t.from).address()) / t.gasPrice; + if (t.to) + client()->transact(t.from, t.value, t.to, t.data, t.gas, t.gasPrice); + else + client()->transact(t.from, t.value, t.data, t.gas, t.gasPrice); + client()->flushTransactions(); +} + +QString QEthereum::doCall(QString _json) +{ + if (!m_client) + return QString(); + TransactionSkeleton t = toTransaction(_json); + if (!t.to) + return QString(); + if (!t.from && m_accounts.size()) + t.from = m_accounts[0].secret(); + if (!t.gasPrice) + t.gasPrice = 10 * eth::szabo; + if (!t.gas) + t.gas = client()->balanceAt(KeyPair(t.from).address()) / t.gasPrice; + bytes out = client()->call(t.from, t.value, t.to, t.data, t.gas, t.gasPrice); + return asQString(out); +} + unsigned QEthereum::newWatch(QString _json) { if (!m_client) diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index e5476613e..b702f09a4 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -72,6 +72,11 @@ inline QString toDecimal(QString const& _s) return QString::fromStdString(eth::toString(toU256(_s))); } +inline double toFixed(QString const& _s) +{ + return (double)toU256(_s) / (double)(eth::u256(1) << 128); +} + inline QString fromBinary(eth::bytes const& _s) { return QString::fromStdString("0x" + eth::toHex(_s)); @@ -105,12 +110,14 @@ public: Q_INVOKABLE QString lll(QString _s) const; Q_INVOKABLE QString sha3(QString _s) const; + Q_INVOKABLE QString offset(QString _s, int _offset) const; 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 unpad(QString _s) const { return unpadded(_s); } Q_INVOKABLE QString toBinary(QString _s) const { return ::toBinary(_s); } Q_INVOKABLE QString fromBinary(QString _s) const { return ::fromBinary(_s); } Q_INVOKABLE QString toDecimal(QString _s) const { return ::toDecimal(_s); } + Q_INVOKABLE double toFixed(QString _s) const { return ::toFixed(_s); } // [NEW API] - Use this instead. Q_INVOKABLE QString/*eth::u256*/ balanceAt(QString/*eth::Address*/ _a, int _block) const; @@ -127,6 +134,8 @@ public: Q_INVOKABLE QString doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice); Q_INVOKABLE void doTransact(QString _secret, QString _amount, QString _dest, QString _data, QString _gas, QString _gasPrice); + Q_INVOKABLE void doTransact(QString _json); + Q_INVOKABLE QString doCall(QString _json); Q_INVOKABLE unsigned newWatch(QString _json); Q_INVOKABLE QString watchMessages(unsigned _w); @@ -192,6 +201,8 @@ private: frame->evaluateJavaScript("eth.watchPending = function() { return eth.makeWatch('pendingChanged') }"); \ frame->evaluateJavaScript("eth.create = function(s, v, c, g, p, f) { var v = eth.doCreate(s, v, c, g, p); if (f) f(v) }"); \ frame->evaluateJavaScript("eth.transact = function(s, v, t, d, g, p, f) { eth.doTransact(s, v, t, d, g, p); if (f) f() }"); \ + frame->evaluateJavaScript("eth.transact = function(a, f) { eth.doTransactJson(JSON.stringify(a)); if (f) f() }"); \ + frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \ frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ frame->evaluateJavaScript("eth.transactions = function(a) { env.warn('THIS CALL IS DEPRECATED. USE eth.messages INSTEAD.'); return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \ frame->evaluateJavaScript("String.prototype.pad = function(l, r) { return eth.pad(this, l, r) }"); \ @@ -199,6 +210,7 @@ private: frame->evaluateJavaScript("String.prototype.unbin = function(l) { return eth.fromBinary(this) }"); \ frame->evaluateJavaScript("String.prototype.unpad = function(l) { return eth.unpad(this) }"); \ frame->evaluateJavaScript("String.prototype.dec = function() { return eth.toDecimal(this) }"); \ + frame->evaluateJavaScript("String.prototype.fix = function() { return eth.toFixed(this) }"); \ frame->evaluateJavaScript("String.prototype.sha3 = function() { return eth.sha3(this) }"); \ }