From 1d16e1556fc4ffe0c57c1781fc77aa3ac236f64a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 4 Nov 2014 18:11:06 +0000 Subject: [PATCH 1/3] Ready for move to log entries in JS API. --- libdevcore/FixedHash.h | 5 ++ libdevcrypto/Common.h | 3 + libdevcrypto/SHA3.h | 3 + libethereum/MessageFilter.cpp | 55 ++++++++++++++++ libethereum/MessageFilter.h | 34 ++++++++++ libethereum/State.cpp | 3 +- libevm/ExtVMFace.h | 20 ++++-- libweb3jsonrpc/WebThreeStubServer.cpp | 71 ++++++++++++++++++--- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libweb3jsonrpc/abstractwebthreestubserver.h | 7 -- libweb3jsonrpc/spec.json | 1 - 11 files changed, 181 insertions(+), 25 deletions(-) diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 02d199f62..2353a100c 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -163,6 +163,11 @@ public: return (*this |= _h.template nbloom()); } + template inline bool containsBloom(FixedHash const& _h) + { + return contains(_h.template nbloom()); + } + template inline FixedHash nbloom() const { static const unsigned c_bloomBits = M * 8; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7f2a8192e..4b4d34d87 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -50,6 +50,9 @@ using Address = h160; /// A vector of Ethereum addresses. using Addresses = h160s; +/// A vector of Ethereum addresses. +using AddressSet = std::set; + /// A vector of secrets. using Secrets = h256s; diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index 1575ab29c..7aa4db246 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -56,6 +56,9 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } +/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. +template inline h256 sha3(FixedHash const& _input) { return sha3(_input.ref()); } + extern h256 EmptySHA3; extern h256 EmptyListSHA3; diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index fc6af1308..88f1a24f9 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -149,3 +149,58 @@ bool MessageFilter::matches(Manifest const& _m, vector _p, Address _o, return ret; } + + + +void LogFilter::streamRLP(RLPStream& _s) const +{ + _s.appendList(6) << m_addresses << m_topics << m_earliest << m_latest << m_max << m_skip; +} + +h256 LogFilter::sha3() const +{ + RLPStream s; + streamRLP(s); + return dev::sha3(s.out()); +} + +bool LogFilter::matches(LogBloom _bloom) const +{ + if (m_addresses.size()) + { + for (auto i: m_addresses) + if (_bloom.containsBloom<3>(dev::sha3(i))) + goto OK1; + return false; + } + OK1: + if (m_topics.size()) + { + for (auto i: m_topics) + if (_bloom.containsBloom<3>(dev::sha3(i))) + goto OK2; + return false; + } + OK2: + return true; +} + +bool LogFilter::matches(State const& _s, unsigned _i) const +{ + return matches(_s.receipt(_i)).size() > 0; +} + +LogEntries LogFilter::matches(TransactionReceipt const& _m) const +{ + LogEntries ret; + for (LogEntry const& e: _m.log()) + { + if (!m_addresses.empty() && !m_addresses.count(e.address)) + continue; + for (auto const& t: m_topics) + if (!e.topics.count(t)) + continue; + ret.push_back(e); + } + return ret; +} diff --git a/libethereum/MessageFilter.h b/libethereum/MessageFilter.h index 83cbb7237..5602d7a17 100644 --- a/libethereum/MessageFilter.h +++ b/libethereum/MessageFilter.h @@ -25,6 +25,7 @@ #include #include #include "PastMessage.h" +#include "TransactionReceipt.h" namespace dev { @@ -72,5 +73,38 @@ private: unsigned m_skip; }; +class LogFilter +{ +public: + LogFilter(int _earliest = 0, int _latest = -1, unsigned _max = 10, unsigned _skip = 0): m_earliest(_earliest), m_latest(_latest), m_max(_max), m_skip(_skip) {} + + void streamRLP(RLPStream& _s) const; + h256 sha3() const; + + int earliest() const { return m_earliest; } + int latest() const { return m_latest; } + unsigned max() const { return m_max; } + unsigned skip() const { return m_skip; } + bool matches(LogBloom _bloom) const; + bool matches(State const& _s, unsigned _i) const; + LogEntries matches(TransactionReceipt const& _r) const; + + LogFilter address(Address _a) { m_addresses.insert(_a); return *this; } + LogFilter from(Address _a) { return topic(u256((u160)_a) + 1); } + LogFilter topic(h256 const& _t) { m_topics.insert(_t); return *this; } + LogFilter withMax(unsigned _m) { m_max = _m; return *this; } + LogFilter withSkip(unsigned _m) { m_skip = _m; return *this; } + LogFilter withEarliest(int _e) { m_earliest = _e; return *this; } + LogFilter withLatest(int _e) { m_latest = _e; return *this; } + +private: + AddressSet m_addresses; + h256Set m_topics; + int m_earliest = 0; + int m_latest = -1; + unsigned m_max; + unsigned m_skip; +}; + } } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 51f5901c5..cd1a7f541 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -791,7 +791,8 @@ h256 State::oldBloom() const LogBloom State::logBloom() const { LogBloom ret; - ret.shiftBloom<3>(sha3(m_currentBlock.coinbaseAddress.ref())); + auto sa = sha3(m_currentBlock.coinbaseAddress.ref()); + ret.shiftBloom<3>(sa); for (TransactionReceipt const& i: m_receipts) ret |= i.bloom(); return ret; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 1b1ae7455..9f662087c 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -36,27 +36,35 @@ namespace dev namespace eth { +template inline std::set toSet(std::vector const& _ts) +{ + std::set ret; + for (auto const& t: _ts) + ret.insert(t); + return ret; +} + using LogBloom = h512; struct LogEntry { LogEntry() {} - LogEntry(RLP const& _r) { from = (Address)_r[0]; topics = (h256s)_r[1]; data = (bytes)_r[2]; } - LogEntry(Address const& _f, h256s&& _ts, bytes&& _d): from(_f), topics(std::move(_ts)), data(std::move(_d)) {} + LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = (bytes)_r[2]; } + LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_ts)), data(std::move(_d)) {} - void streamRLP(RLPStream& _s) const { _s.appendList(3) << from << topics << data; } + void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; } LogBloom bloom() const { LogBloom ret; - ret.shiftBloom<3, 32>(sha3(from.ref())); + ret.shiftBloom<3, 32>(sha3(address.ref())); for (auto t: topics) ret.shiftBloom<3, 32>(sha3(t.ref())); return ret; } - Address from; - h256s topics; + Address address; + h256Set topics; bytes data; }; diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index e7eb62e04..4ac048ee9 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -97,6 +97,24 @@ static Json::Value toJson(dev::eth::Transaction const& _t) return res; } +static Json::Value toJson(dev::eth::LogEntry const& _e) +{ + Json::Value res; + res["data"] = jsFromBinary(_e.data); + res["address"] = toJS(_e.address); + for (auto const& t: _e.topics) + res["topics"].append(toJS(t)); + return res; +} + +static Json::Value toJson(dev::eth::LogEntries const& _es) +{ + Json::Value res; + for (dev::eth::LogEntry const& e: _es) + res.append(toJson(e)); + return res; +} + static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) { dev::eth::MessageFilter filter; @@ -123,9 +141,9 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) { if (_json["to"].isArray()) for (auto i : _json["to"]) - filter.from(jsToAddress(i.asString())); + filter.to(jsToAddress(i.asString())); else - filter.from(jsToAddress(_json["to"].asString())); + filter.to(jsToAddress(_json["to"].asString())); } if (!_json["altered"].empty()) { @@ -143,6 +161,48 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) return filter; } +static dev::eth::LogFilter toLogFilter(Json::Value const& _json) +{ + dev::eth::LogFilter filter; + if (!_json.isObject() || _json.empty()) + return filter; + + if (!_json["earliest"].empty()) + filter.withEarliest(_json["earliest"].asInt()); + if (!_json["latest"].empty()) + filter.withLatest(_json["lastest"].asInt()); + if (!_json["max"].empty()) + filter.withMax(_json["max"].asInt()); + if (!_json["skip"].empty()) + filter.withSkip(_json["skip"].asInt()); + if (!_json["from"].empty()) + { + if (_json["from"].isArray()) + for (auto i : _json["from"]) + filter.from(jsToAddress(i.asString())); + else + filter.from(jsToAddress(_json["from"].asString())); + } + if (!_json["address"].empty()) + { + if (_json["address"].isArray()) + for (auto i : _json["address"]) + filter.address(jsToAddress(i.asString())); + else + filter.from(jsToAddress(_json["address"].asString())); + } + if (!_json["topics"].empty()) + { + if (_json["topics"].isArray()) + for (auto i: _json["topics"]) + if (i.isString()) + filter.topic(jsToU256(i.asString())); + else if(_json["topics"].isString()) + filter.topic(jsToU256(_json["topics"].asString())); + } + return filter; +} + static shh::Message toMessage(Json::Value const& _json) { shh::Message ret; @@ -252,13 +312,6 @@ std::shared_ptr WebThreeStubServer::face() const return m_web3.whisper(); } -std::string WebThreeStubServer::account() -{ - if (!m_accounts.empty()) - return toJS(m_accounts.begin()->first); - return ""; -} - Json::Value WebThreeStubServer::accounts() { Json::Value ret(Json::arrayValue); diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index b18faf95a..33163b75e 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -56,13 +56,14 @@ class Interface; * @brief JSON-RPC api implementation * @todo filters should work on unsigned instead of int * unsigned are not supported in json-rpc-cpp and there are bugs with double in json-rpc-cpp version 0.2.1 + * @todo split these up according to subprotocol (eth, shh, db, p2p, web3) and make it /very/ clear about how to add other subprotocols. + * @todo modularise everything so additional subprotocols don't need to change this file. */ class WebThreeStubServer: public AbstractWebThreeStubServer { public: WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); - virtual std::string account(); virtual Json::Value accounts(); virtual std::string addToGroup(std::string const& _group, std::string const& _who); virtual std::string balanceAt(std::string const& _address); @@ -109,6 +110,7 @@ public: void setAccounts(std::vector const& _accounts); void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } + private: dev::eth::Interface* client() const; std::shared_ptr face() const; diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index ac6893933..66b9ff77d 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -13,7 +13,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer(conn) { - this->bindAndAddMethod(new jsonrpc::Procedure("account", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::accountI); this->bindAndAddMethod(new jsonrpc::Procedure("accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::accountsI); this->bindAndAddMethod(new jsonrpc::Procedure("addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::addToGroupI); this->bindAndAddMethod(new jsonrpc::Procedure("balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::balanceAtI); @@ -59,11 +58,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServeraccount(); - } - inline virtual void accountsI(const Json::Value& request, Json::Value& response) { response = this->accounts(); @@ -275,7 +269,6 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer Date: Wed, 5 Nov 2014 13:45:19 +0000 Subject: [PATCH 2/3] Classify Transaction. --- alethzero/MainWin.cpp | 91 +++++++++++++-------------- libethereum/Client.cpp | 42 ++++--------- libethereum/Executive.cpp | 42 ++++++------- libethereum/MessageFilter.cpp | 2 +- libethereum/State.cpp | 6 +- libethereum/Transaction.cpp | 30 ++++----- libethereum/Transaction.h | 53 +++++++++------- libweb3jsonrpc/WebThreeStubServer.cpp | 16 ++--- neth/main.cpp | 32 +++++----- test/crypto.cpp | 14 +---- test/state.cpp | 7 +-- test/vm.cpp | 38 ++++------- 12 files changed, 167 insertions(+), 206 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index f413532b7..18270ff8c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -868,18 +868,18 @@ void Main::refreshPending() ui->transactionQueue->clear(); for (Transaction const& t: ethereum()->pending()) { - QString s = t.receiveAddress ? + QString s = t.receiveAddress() ? QString("%2 %5> %3: %1 [%4]") - .arg(formatBalance(t.value).c_str()) + .arg(formatBalance(t.value()).c_str()) .arg(render(t.safeSender())) - .arg(render(t.receiveAddress)) - .arg((unsigned)t.nonce) - .arg(ethereum()->codeAt(t.receiveAddress).size() ? '*' : '-') : + .arg(render(t.receiveAddress())) + .arg((unsigned)t.nonce()) + .arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') : QString("%2 +> %3: %1 [%4]") - .arg(formatBalance(t.value).c_str()) + .arg(formatBalance(t.value()).c_str()) .arg(render(t.safeSender())) - .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce))))) - .arg((unsigned)t.nonce); + .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce()))))) + .arg((unsigned)t.nonce()); ui->transactionQueue->addItem(s); } } @@ -946,7 +946,7 @@ static bool blockMatch(string const& _f, dev::eth::BlockDetails const& _b, h256 static bool transactionMatch(string const& _f, Transaction const& _t) { - string info = toHex(_t.receiveAddress.ref()) + " " + toHex(_t.sha3(true).ref()) + " " + toHex(_t.sha3(false).ref()) + " " + toHex(_t.sender().ref()); + string info = toHex(_t.receiveAddress().ref()) + " " + toHex(_t.sha3(true).ref()) + " " + toHex(_t.sha3(false).ref()) + " " + toHex(_t.sender().ref()); if (info.find(_f) != string::npos) return true; return false; @@ -986,18 +986,18 @@ void Main::refreshBlockChain() Transaction t(i.data()); if (bm || transactionMatch(filter, t)) { - QString s = t.receiveAddress ? + QString s = t.receiveAddress() ? QString(" %2 %5> %3: %1 [%4]") - .arg(formatBalance(t.value).c_str()) + .arg(formatBalance(t.value()).c_str()) .arg(render(t.safeSender())) - .arg(render(t.receiveAddress)) - .arg((unsigned)t.nonce) - .arg(ethereum()->codeAt(t.receiveAddress).size() ? '*' : '-') : + .arg(render(t.receiveAddress())) + .arg((unsigned)t.nonce()) + .arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') : QString(" %2 +> %3: %1 [%4]") - .arg(formatBalance(t.value).c_str()) + .arg(formatBalance(t.value()).c_str()) .arg(render(t.safeSender())) - .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce))))) - .arg((unsigned)t.nonce); + .arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce()))))) + .arg((unsigned)t.nonce()); QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks); auto hba = QByteArray((char const*)h.data(), h.size); txItem->setData(Qt::UserRole, hba); @@ -1144,26 +1144,26 @@ void Main::on_transactionQueue_currentItemChanged() { Transaction tx(ethereum()->pending()[i]); auto ss = tx.safeSender(); - h256 th = sha3(rlpList(ss, tx.nonce)); + h256 th = sha3(rlpList(ss, tx.nonce())); s << "

" << th << "

"; s << "From: " << pretty(ss).toStdString() << " " << ss; if (tx.isCreation()) s << "
Creates: " << pretty(right160(th)).toStdString() << " " << right160(th); else - s << "
To: " << pretty(tx.receiveAddress).toStdString() << " " << tx.receiveAddress; - s << "
Value: " << formatBalance(tx.value) << ""; - s << "   #" << tx.nonce << ""; - s << "
Gas price: " << formatBalance(tx.gasPrice) << ""; - s << "
Gas: " << tx.gas << ""; + s << "
To: " << pretty(tx.receiveAddress()).toStdString() << " " << tx.receiveAddress(); + s << "
Value: " << formatBalance(tx.value()) << ""; + s << "   #" << tx.nonce() << ""; + s << "
Gas price: " << formatBalance(tx.gasPrice()) << ""; + s << "
Gas: " << tx.gas() << ""; if (tx.isCreation()) { - if (tx.data.size()) - s << "

Code

" << disassemble(tx.data); + if (tx.data().size()) + s << "

Code

" << disassemble(tx.data()); } else { - if (tx.data.size()) - s << dev::memDump(tx.data, 16, true); + if (tx.data().size()) + s << dev::memDump(tx.data(), 16, true); } s << "
"; @@ -1251,31 +1251,31 @@ void Main::on_blocks_currentItemChanged() unsigned txi = item->data(Qt::UserRole + 1).toInt(); Transaction tx(block[1][txi].data()); auto ss = tx.safeSender(); - h256 th = sha3(rlpList(ss, tx.nonce)); + h256 th = sha3(rlpList(ss, tx.nonce())); s << "

" << th << "

"; s << "

" << h << "[" << txi << "]

"; s << "
From: " << pretty(ss).toHtmlEscaped().toStdString() << " " << ss; if (tx.isCreation()) s << "
Creates: " << pretty(right160(th)).toHtmlEscaped().toStdString() << " " << right160(th); else - s << "
To: " << pretty(tx.receiveAddress).toHtmlEscaped().toStdString() << " " << tx.receiveAddress; - s << "
Value: " << formatBalance(tx.value) << ""; - s << "   #" << tx.nonce << ""; - s << "
Gas price: " << formatBalance(tx.gasPrice) << ""; - s << "
Gas: " << tx.gas << ""; - s << "
V: " << hex << nouppercase << (int)tx.vrs.v << ""; - s << "
R: " << hex << nouppercase << tx.vrs.r << ""; - s << "
S: " << hex << nouppercase << tx.vrs.s << ""; + s << "
To: " << pretty(tx.receiveAddress()).toHtmlEscaped().toStdString() << " " << tx.receiveAddress(); + s << "
Value: " << formatBalance(tx.value()) << ""; + s << "   #" << tx.nonce() << ""; + s << "
Gas price: " << formatBalance(tx.gasPrice()) << ""; + s << "
Gas: " << tx.gas() << ""; + s << "
V: " << hex << nouppercase << (int)tx.signature().v << ""; + s << "
R: " << hex << nouppercase << tx.signature().r << ""; + s << "
S: " << hex << nouppercase << tx.signature().s << ""; s << "
Msg: " << tx.sha3(false) << ""; if (tx.isCreation()) { - if (tx.data.size()) - s << "

Code

" << disassemble(tx.data); + if (tx.data().size()) + s << "

Code

" << disassemble(tx.data()); } else { - if (tx.data.size()) - s << dev::memDump(tx.data, 16, true); + if (tx.data().size()) + s << dev::memDump(tx.data(), 16, true); } s << renderDiff(ethereum()->diff(txi, h)); ui->debugCurrent->setEnabled(true); @@ -1786,14 +1786,9 @@ void Main::on_debug_clicked() Secret s = i.secret(); m_executiveState = ethereum()->postState(); m_currentExecution = unique_ptr(new Executive(m_executiveState)); - Transaction t; - t.nonce = m_executiveState.transactionsFrom(dev::toAddress(s)); - t.value = value(); - t.gasPrice = gasPrice(); - t.gas = ui->gas->value(); - t.data = m_data; - t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); - t.sign(s); + Transaction t = isCreation() ? + Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) : + Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s); auto r = t.rlp(); populateDebugger(&r); m_currentExecution.reset(); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 63e093b17..d87e9c33e 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -316,19 +316,13 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ { startWorking(); - Transaction t; -// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + u256 n; { ReadGuard l(x_stateDB); - t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); + n = m_postMine.transactionsFrom(toAddress(_secret)); } - t.value = _value; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::MessageCall; - t.receiveAddress = _dest; - t.data = _data; - t.sign(_secret); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); +// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); cnote << "New transaction " << t; m_tq.attemptImport(t.rlp()); } @@ -338,22 +332,16 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat bytes out; try { + u256 n; 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)); + n = temp.transactionsFrom(toAddress(_secret)); } - t.value = _value; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::ContractCreation; - t.receiveAddress = _dest; - t.data = _data; - t.sign(_secret); - u256 gasUsed = temp.execute(t.data, &out, false); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + u256 gasUsed = temp.execute(t.data(), &out, false); (void)gasUsed; // TODO: do something with gasused which it returns. } catch (...) @@ -367,21 +355,15 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2 { startWorking(); - Transaction t; + u256 n; { ReadGuard l(x_stateDB); - t.nonce = m_postMine.transactionsFrom(toAddress(_secret)); + n = m_postMine.transactionsFrom(toAddress(_secret)); } - t.value = _endowment; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.type = Transaction::ContractCreation; - t.receiveAddress = Address(); - t.data = _init; - t.sign(_secret); + Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); cnote << "New transaction " << t; m_tq.attemptImport(t.rlp()); - return right160(sha3(rlpList(t.sender(), t.nonce))); + return right160(sha3(rlpList(t.sender(), t.nonce()))); } void Client::inject(bytesConstRef _rlp) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 885ab5535..e14401972 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -40,7 +40,7 @@ Executive::~Executive() u256 Executive::gasUsed() const { - return m_t.gas - m_endGas; + return m_t.gas() - m_endGas; } bool Executive::setup(bytesConstRef _rlp) @@ -52,29 +52,29 @@ bool Executive::setup(bytesConstRef _rlp) // Avoid invalid transactions. auto nonceReq = m_s.transactionsFrom(m_sender); - if (m_t.nonce != nonceReq) + if (m_t.nonce() != nonceReq) { - clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce; - BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce)); + clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); + BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce())); } // Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going. - if (m_t.gasPrice < m_s.m_currentBlock.minGasPrice) + if (m_t.gasPrice() < m_s.m_currentBlock.minGasPrice) { - clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice; + clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice(); BOOST_THROW_EXCEPTION(GasPriceTooLow()); } // Check gas cost is enough. - u256 gasCost = m_t.data.size() * c_txDataGas + c_txGas; + u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas; - if (m_t.gas < gasCost) + if (m_t.gas() < gasCost) { - clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas; + clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas(); BOOST_THROW_EXCEPTION(OutOfGas()); } - u256 cost = m_t.value + m_t.gas * m_t.gasPrice; + u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice(); // Avoid unaffordable transactions. if (m_s.balance(m_sender) < cost) @@ -84,9 +84,9 @@ bool Executive::setup(bytesConstRef _rlp) } u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + m_t.gas > m_s.m_currentBlock.gasLimit) + if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit) { - clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas; + clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); BOOST_THROW_EXCEPTION(BlockGasLimitReached()); } @@ -94,21 +94,21 @@ bool Executive::setup(bytesConstRef _rlp) m_s.noteSending(m_sender); // Pay... - clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas << "gas at" << formatBalance(m_t.gasPrice) << ")"; + clog(StateDetail) << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas() << "gas at" << formatBalance(m_t.gasPrice()) << ")"; m_s.subBalance(m_sender, cost); if (m_ms) { m_ms->from = m_sender; - m_ms->to = m_t.receiveAddress; - m_ms->value = m_t.value; - m_ms->input = m_t.data; + m_ms->to = m_t.receiveAddress(); + m_ms->value = m_t.value(); + m_ms->input = m_t.data(); } if (m_t.isCreation()) - return create(m_sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, m_sender); + return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - gasCost, &m_t.data(), m_sender); else - return call(m_t.receiveAddress, m_sender, m_t.value, m_t.gasPrice, bytesConstRef(&m_t.data), m_t.gas - gasCost, m_sender); + return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - gasCost, m_sender); } bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) @@ -177,7 +177,7 @@ bool Executive::go(OnOpFunc const& _onOp) { m_out = m_vm->go(*m_ext, _onOp); if (m_ext) - m_endGas += min((m_t.gas - m_endGas) / 2, m_ext->sub.refunds); + m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds); m_endGas = m_vm->gas(); } catch (StepsDone const&) @@ -234,9 +234,9 @@ void Executive::finalize(OnOpFunc const&) m_s.m_cache[m_newAddress].setCode(m_out); // cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")"; - m_s.addBalance(m_sender, m_endGas * m_t.gasPrice); + m_s.addBalance(m_sender, m_endGas * m_t.gasPrice()); - u256 feesEarned = (m_t.gas - m_endGas) * m_t.gasPrice; + u256 feesEarned = (m_t.gas() - m_endGas) * m_t.gasPrice(); // cnote << "Transferring" << formatBalance(gasSpent) << "to miner."; m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); diff --git a/libethereum/MessageFilter.cpp b/libethereum/MessageFilter.cpp index 88f1a24f9..b04d213f9 100644 --- a/libethereum/MessageFilter.cpp +++ b/libethereum/MessageFilter.cpp @@ -79,7 +79,7 @@ bool MessageFilter::matches(State const& _s, unsigned _i) const return false; Transaction t = _s.pending()[_i]; - if (!m_to.empty() && !m_to.count(t.receiveAddress)) + if (!m_to.empty() && !m_to.count(t.receiveAddress())) return false; if (!m_from.empty() && !m_from.count(t.sender())) return false; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index cd1a7f541..c059922d5 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -520,7 +520,7 @@ bool State::cull(TransactionQueue& _tq) const try { Transaction t(i.second); - if (t.nonce <= transactionsFrom(t.sender())) + if (t.nonce() <= transactionsFrom(t.sender())) { _tq.drop(i.first); ret = true; @@ -1154,10 +1154,10 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) paranoia("after execution commit.", true); - if (e.t().receiveAddress) + if (e.t().receiveAddress()) { EnforceRefs r(m_db, true); - if (storageRoot(e.t().receiveAddress) && m_db.lookup(storageRoot(e.t().receiveAddress)).empty()) + if (storageRoot(e.t().receiveAddress()) && m_db.lookup(storageRoot(e.t().receiveAddress())).empty()) { cwarn << "TRIE immediately after execution; no node for receiveAddress"; BOOST_THROW_EXCEPTION(InvalidTrie()); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index bdc8bf34d..c65421e04 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -36,14 +36,14 @@ Transaction::Transaction(bytesConstRef _rlpData, bool _checkSender) RLP rlp(_rlpData); try { - nonce = rlp[field = 0].toInt(); - gasPrice = rlp[field = 1].toInt(); - gas = rlp[field = 2].toInt(); - type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; - receiveAddress = rlp[field = 3].toHash
(); - value = rlp[field = 4].toInt(); - data = rlp[field = 5].toBytes(); - vrs = SignatureStruct{ rlp[field = 7].toInt(), rlp[field = 8].toInt(), byte(rlp[field = 6].toInt() - 27) }; + m_nonce = rlp[field = 0].toInt(); + m_gasPrice = rlp[field = 1].toInt(); + m_gas = rlp[field = 2].toInt(); + m_type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; + m_receiveAddress = rlp[field = 3].toHash
(); + m_value = rlp[field = 4].toInt(); + m_data = rlp[field = 5].toBytes(); + m_vrs = SignatureStruct{ rlp[field = 7].toInt(), rlp[field = 8].toInt(), byte(rlp[field = 6].toInt() - 27) }; if (_checkSender) m_sender = sender(); } @@ -71,7 +71,7 @@ Address Transaction::sender() const { if (!m_sender) { - auto p = recover(*(Signature const*)&vrs, sha3(false)); + auto p = recover(*(Signature const*)&m_vrs, sha3(false)); if (!p) BOOST_THROW_EXCEPTION(InvalidSignature()); m_sender = right160(dev::sha3(bytesConstRef(p.data(), sizeof(p)))); @@ -82,18 +82,18 @@ Address Transaction::sender() const void Transaction::sign(Secret _priv) { auto sig = dev::sign(_priv, sha3(false)); - vrs = *(SignatureStruct const*)&sig; + m_vrs = *(SignatureStruct const*)&sig; } void Transaction::streamRLP(RLPStream& _s, bool _sig) const { _s.appendList((_sig ? 3 : 0) + 6); - _s << nonce << gasPrice << gas; - if (type == MessageCall) - _s << receiveAddress; + _s << m_nonce << m_gasPrice << m_gas; + if (m_type == MessageCall) + _s << m_receiveAddress; else _s << ""; - _s << value << data; + _s << m_value << m_data; if (_sig) - _s << (vrs.v + 27) << (u256)vrs.r << (u256)vrs.s; + _s << (m_vrs.v + 27) << (u256)m_vrs.r << (u256)m_vrs.s; } diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 2492e32bc..bb04bcab7 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -30,47 +30,59 @@ namespace dev namespace eth { -struct Transaction +class Transaction { +public: enum Type { + NullTransaction, ContractCreation, MessageCall }; Transaction() {} + Transaction(u256 _value, u256 _gasPrice, u256 _gas, Address const& _dest, bytes const& _data, u256 _nonce, Secret const& _secret): m_type(MessageCall), m_nonce(_nonce), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); } + Transaction(u256 _value, u256 _gasPrice, u256 _gas, bytes const& _data, u256 _nonce, Secret const& _secret): m_type(ContractCreation), m_nonce(_nonce), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) { sign(_secret); } + Transaction(u256 _value, u256 _gasPrice, u256 _gas, Address const& _dest, bytes const& _data): m_type(MessageCall), m_value(_value), m_receiveAddress(_dest), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} + Transaction(u256 _value, u256 _gasPrice, u256 _gas, bytes const& _data): m_type(ContractCreation), m_value(_value), m_gasPrice(_gasPrice), m_gas(_gas), m_data(_data) {} Transaction(bytesConstRef _rlp, bool _checkSender = false); Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} - bool operator==(Transaction const& _c) const { return type == _c.type && (type == ContractCreation || receiveAddress == _c.receiveAddress) && value == _c.value && data == _c.data; } + bool operator==(Transaction const& _c) const { return m_type == _c.m_type && (m_type == ContractCreation || m_receiveAddress == _c.m_receiveAddress) && m_value == _c.m_value && m_data == _c.m_data; } bool operator!=(Transaction const& _c) const { return !operator==(_c); } - Type type; ///< True if this is a contract-creation transaction. F - u256 nonce; ///< The transaction-count of the sender. - u256 value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. - Address receiveAddress; ///< The receiving address of the transaction. - u256 gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. - u256 gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. - - bytes data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. - - SignatureStruct vrs; ///< The signature of the transaction. Encodes the sender. - Address safeSender() const noexcept; ///< Like sender() but will never throw. Address sender() const; ///< Determine the sender of the transaction from the signature (and hash). void sign(Secret _priv); ///< Sign the transaction. - bool isCreation() const { return !receiveAddress; } - - static h256 kFromMessage(h256 _msg, h256 _priv); + bool isCreation() const { return !m_receiveAddress; } void streamRLP(RLPStream& _s, bool _sig = true) const; + bytes rlp(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return s.out(); } std::string rlpString(bool _sig = true) const { return asString(rlp(_sig)); } h256 sha3(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return dev::sha3(s.out()); } bytes sha3Bytes(bool _sig = true) const { RLPStream s; streamRLP(s, _sig); return dev::sha3Bytes(s.out()); } + Type type() const { return m_type; } + u256 nonce() const { return m_nonce; } + u256 value() const { return m_value; } + Address receiveAddress() const { return m_receiveAddress; } + u256 gasPrice() const { return m_gasPrice; } + u256 gas() const { return m_gas; } + bytes const& data() const { return m_data; } + SignatureStruct const& signature() const { return m_vrs; } + private: + Type m_type = NullTransaction; ///< True if this is a contract-creation transaction. F + u256 m_nonce; ///< The transaction-count of the sender. + u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. + Address m_receiveAddress; ///< The receiving address of the transaction. + u256 m_gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. + u256 m_gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. + bytes m_data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. + SignatureStruct m_vrs; ///< The signature of the transaction. Encodes the sender. + mutable Address m_sender; }; @@ -79,19 +91,18 @@ using Transactions = std::vector; inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) { _out << "{"; - if (_t.receiveAddress) - _out << _t.receiveAddress.abridged(); + if (_t.receiveAddress()) + _out << _t.receiveAddress().abridged(); else _out << "[CREATE]"; - _out << "/" << _t.nonce << "$" << _t.value << "+" << _t.gas << "@" << _t.gasPrice; - Address s; + _out << "/" << _t.nonce() << "$" << _t.value() << "+" << _t.gas() << "@" << _t.gasPrice(); try { _out << "<-" << _t.sender().abridged(); } catch (...) {} - _out << " #" << _t.data.size() << "}"; + _out << " #" << _t.data().size() << "}"; return _out; } diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 4ac048ee9..89d45f4e0 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -87,13 +87,13 @@ static Json::Value toJson(dev::eth::Transaction const& _t) { Json::Value res; res["hash"] = toJS(_t.sha3()); - res["input"] = jsFromBinary(_t.data); - res["to"] = toJS(_t.receiveAddress); + res["input"] = jsFromBinary(_t.data()); + res["to"] = toJS(_t.receiveAddress()); res["from"] = toJS(_t.sender()); - res["gas"] = (int)_t.gas; - res["gasPrice"] = toJS(_t.gasPrice); - res["nonce"] = toJS(_t.nonce); - res["value"] = toJS(_t.value); + res["gas"] = (int)_t.gas(); + res["gasPrice"] = toJS(_t.gasPrice()); + res["nonce"] = toJS(_t.nonce()); + res["value"] = toJS(_t.value()); return res; } @@ -107,7 +107,7 @@ static Json::Value toJson(dev::eth::LogEntry const& _e) return res; } -static Json::Value toJson(dev::eth::LogEntries const& _es) +/*static*/ Json::Value toJson(dev::eth::LogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7. { Json::Value res; for (dev::eth::LogEntry const& e: _es) @@ -161,7 +161,7 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json) return filter; } -static dev::eth::LogFilter toLogFilter(Json::Value const& _json) +/*static*/ dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to avoid warning. Uncomment once in use @ PoC-7. { dev::eth::LogFilter filter; if (!_json.isObject() || _json.empty()) diff --git a/neth/main.cpp b/neth/main.cpp index 4e3a0f40a..06e22f963 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -843,18 +843,18 @@ int main(int argc, char** argv) for (auto const& i: RLP(b)[1]) { Transaction t(i[0].data()); - auto s = t.receiveAddress ? + auto s = t.receiveAddress() ? boost::format(" %1% %2%> %3%: %4% [%5%]") % toString(t.safeSender()) % - (c.codeAt(t.receiveAddress, 0).size() ? '*' : '-') % - toString(t.receiveAddress) % - toString(formatBalance(t.value)) % - toString((unsigned)t.nonce) : + (c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % + toString(t.receiveAddress()) % + toString(formatBalance(t.value())) % + toString((unsigned)t.nonce()) : boost::format(" %1% +> %2%: %3% [%4%]") % toString(t.safeSender()) % - toString(right160(sha3(rlpList(t.safeSender(), t.nonce)))) % - toString(formatBalance(t.value)) % - toString((unsigned)t.nonce); + toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) % + toString(formatBalance(t.value())) % + toString((unsigned)t.nonce()); mvwaddnstr(blockswin, y++, x, s.str().c_str(), qwidth - 2); if (y > qheight - 2) break; @@ -868,18 +868,18 @@ int main(int argc, char** argv) y = 1; for (Transaction const& t: c.pending()) { - auto s = t.receiveAddress ? + auto s = t.receiveAddress() ? boost::format("%1% %2%> %3%: %4% [%5%]") % toString(t.safeSender()) % - (c.codeAt(t.receiveAddress, 0).size() ? '*' : '-') % - toString(t.receiveAddress) % - toString(formatBalance(t.value)) % - toString((unsigned)t.nonce) : + (c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % + toString(t.receiveAddress()) % + toString(formatBalance(t.value())) % + toString((unsigned)t.nonce()) : boost::format("%1% +> %2%: %3% [%4%]") % toString(t.safeSender()) % - toString(right160(sha3(rlpList(t.safeSender(), t.nonce)))) % - toString(formatBalance(t.value)) % - toString((unsigned)t.nonce); + toString(right160(sha3(rlpList(t.safeSender(), t.nonce())))) % + toString(formatBalance(t.value())) % + toString((unsigned)t.nonce()); mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth); if (y > height * 1 / 5 - 4) break; diff --git a/test/crypto.cpp b/test/crypto.cpp index 67286bfca..2f5314421 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -339,16 +339,11 @@ BOOST_AUTO_TEST_CASE(eth_keypairs) BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); { - eth::Transaction t; - t.nonce = 0; - t.type = eth::Transaction::MessageCall; - t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); - t.value = 1000; + eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); auto rlp = t.rlp(false); cnote << RLP(rlp); cnote << toHex(rlp); cnote << t.sha3(false); - t.sign(p.secret()); rlp = t.rlp(true); cnote << RLP(rlp); cnote << toHex(rlp); @@ -368,16 +363,11 @@ int cryptoTest() assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); { - eth::Transaction t; - t.nonce = 0; - t.type = eth::Transaction::MessageCall; - t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); - t.value = 1000; + eth::Transaction t(1000, 0, 0, h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")), bytes(), 0, p.secret()); auto rlp = t.rlp(false); cnote << RLP(rlp); cnote << toHex(rlp); cnote << t.sha3(false); - t.sign(p.secret()); rlp = t.rlp(true); cnote << RLP(rlp); cnote << toHex(rlp); diff --git a/test/state.cpp b/test/state.cpp index b0f279bac..921be5f95 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -65,12 +65,7 @@ int stateTest() // Inject a transaction to transfer funds from miner to me. bytes tx; { - Transaction t; - t.nonce = s.transactionsFrom(myMiner.address()); - t.value = 1000; // 1e3 wei. - t.type = eth::Transaction::MessageCall; - t.receiveAddress = me.address(); - t.sign(myMiner.secret()); + Transaction t(1000, 0, 0, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); tx = t.rlp(); } diff --git a/test/vm.cpp b/test/vm.cpp index 617cb95c7..8344c0c5f 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -36,11 +36,7 @@ FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&) { - Transaction t; - t.value = _endowment; - t.gasPrice = gasPrice; - t.gas = *_gas; - t.data = _init.toBytes(); + Transaction t(_endowment, gasPrice, *_gas, _init.toBytes()); m_s.noteSending(myAddress); m_ms.internal.resize(m_ms.internal.size() + 1); @@ -55,7 +51,6 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun get<3>(addresses[ret]) = m_s.code(ret); } - t.type = eth::Transaction::ContractCreation; callcreates.push_back(t); return ret; } @@ -64,13 +59,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, { u256 contractgas = 0xffff; - Transaction t; - t.value = _value; - t.gasPrice = gasPrice; - t.gas = *_gas; - t.data = _data.toVector(); - t.type = eth::Transaction::MessageCall; - t.receiveAddress = _receiveAddress; + Transaction t(_value, gasPrice, *_gas, _receiveAddress, _data.toVector()); callcreates.push_back(t); string codeOf_CodeAddress = _codeAddressOverride ? toHex(get<3>(addresses[_codeAddressOverride])) : toHex(get<3>(addresses[_receiveAddress]) ); @@ -386,10 +375,10 @@ mArray FakeExtVM::exportCallCreates() for (Transaction const& tx: callcreates) { mObject o; - o["destination"] = tx.type == Transaction::ContractCreation ? "" : toString(tx.receiveAddress); - push(o, "gasLimit", tx.gas); - push(o, "value", tx.value); - o["data"] = "0x" + toHex(tx.data); + o["destination"] = tx.type() == Transaction::ContractCreation ? "" : toString(tx.receiveAddress()); + push(o, "gasLimit", tx.gas()); + push(o, "value", tx.value()); + o["data"] = "0x" + toHex(tx.data()); ret.push_back(o); } return ret; @@ -404,19 +393,18 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) BOOST_REQUIRE(tx.count("value") > 0); BOOST_REQUIRE(tx.count("destination") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0); - Transaction t; - t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall; - t.receiveAddress = Address(tx["destination"].get_str()); - t.value = toInt(tx["value"]); - t.gas = toInt(tx["gasLimit"]); + bytes data; if (tx["data"].type() == str_type) if (tx["data"].get_str().find_first_of("0x") == 0) - t.data = fromHex(tx["data"].get_str().substr(2)); + data = fromHex(tx["data"].get_str().substr(2)); else - t.data = fromHex(tx["data"].get_str()); + data = fromHex(tx["data"].get_str()); else for (auto const& j: tx["data"].get_array()) - t.data.push_back(toByte(j)); + data.push_back(toByte(j)); + Transaction t = tx["destination"].get_str().empty() ? + Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), data) : + Transaction(toInt(tx["value"]), 0, toInt(tx["gasLimit"]), Address(tx["destination"].get_str()), data); callcreates.push_back(t); } } From 3b6ffcbe8d091e607c19604e938a5574a870a816 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 5 Nov 2014 14:10:10 +0000 Subject: [PATCH 3/3] Minor fixes to Transaction. --- libethereum/Transaction.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index bb04bcab7..ba79f971c 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -51,11 +51,10 @@ public: bool operator==(Transaction const& _c) const { return m_type == _c.m_type && (m_type == ContractCreation || m_receiveAddress == _c.m_receiveAddress) && m_value == _c.m_value && m_data == _c.m_data; } bool operator!=(Transaction const& _c) const { return !operator==(_c); } - Address safeSender() const noexcept; ///< Like sender() but will never throw. + Address safeSender() const noexcept; ///< Like sender() but will never throw. @returns a null Address if the signature is invalid. Address sender() const; ///< Determine the sender of the transaction from the signature (and hash). - void sign(Secret _priv); ///< Sign the transaction. - bool isCreation() const { return !m_receiveAddress; } + bool isCreation() const { return m_type == ContractCreation; } void streamRLP(RLPStream& _s, bool _sig = true) const; @@ -74,6 +73,8 @@ public: SignatureStruct const& signature() const { return m_vrs; } private: + void sign(Secret _priv); ///< Sign the transaction. + Type m_type = NullTransaction; ///< True if this is a contract-creation transaction. F u256 m_nonce; ///< The transaction-count of the sender. u256 m_value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions.