diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 0a94662c8..048134de8 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -44,6 +44,8 @@ bool dev::SignatureStruct::isValid() const return true; } +Address dev::ZeroAddress = Address(); + Public dev::toPublic(Secret const& _secret) { Public p; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index e91df2526..ccbd0953b 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -62,6 +62,9 @@ struct SignatureStruct /// @NOTE This is not endian-specific; it's just a bunch of bytes. using Address = h160; +/// The zero address. +extern Address ZeroAddress; + /// A vector of Ethereum addresses. using Addresses = h160s; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 8e0b30366..185d3f6e0 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -211,22 +211,33 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message return res; } -WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): - AbstractWebThreeStubServer(_conn) -{ - setAccounts(_accounts); -} - -void WebThreeStubServerBase::setAccounts(std::vector const& _accounts) +void AccountHolder::setAccounts(std::vector const& _accounts) { m_accounts.clear(); - for (auto const& i: _accounts) + for (auto const& keyPair: _accounts) { - m_accounts.push_back(i.address()); - m_accountsLookup[i.address()] = i; + m_accounts.push_back(keyPair.address()); + m_keyPairs[keyPair.address()] = keyPair; } } +Address const& AccountHolder::getDefaultCallAccount() const +{ + if (m_accounts.empty()) + return ZeroAddress; + Address const* bestMatch = &m_accounts.front(); + for (auto const& account: m_accounts) + if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) + bestMatch = &account; + return *bestMatch; +} + +WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): + AbstractWebThreeStubServer(_conn), m_accounts(std::bind(&WebThreeStubServerBase::client, this)) +{ + m_accounts.setAccounts(_accounts); +} + void WebThreeStubServerBase::setIdentities(std::vector const& _ids) { m_ids.clear(); @@ -242,7 +253,7 @@ std::string WebThreeStubServerBase::web3_sha3(std::string const& _param1) Json::Value WebThreeStubServerBase::eth_accounts() { Json::Value ret(Json::arrayValue); - for (auto const& i: m_accounts) + for (auto const& i: m_accounts.getAllAccounts()) ret.append(toJS(i)); return ret; } @@ -326,21 +337,15 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) - { - auto b = m_accounts.front(); - for (auto const& a: m_accounts) - if (client()->balanceAt(a) > client()->balanceAt(b)) - b = a; - t.from = b; - } - if (!m_accountsLookup.count(t.from)) + if (!t.from) + t.from = m_accounts.getDefaultCallAccount(); + if (!m_accounts.isRealAccount(t.from)) return ret; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - ret = toJS(client()->call(m_accountsLookup[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->call(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice)); return ret; } @@ -684,16 +689,14 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) + if (!t.from) + t.from = m_accounts.getDefaultCallAccount(); + if (!m_accounts.isRealAccount(t.from)) { - auto b = m_accounts.front(); - for (auto const& a: m_accounts) - if (client()->balanceAt(a) > client()->balanceAt(b)) - b = a; - t.from = b; - } - if (!m_accountsLookup.count(t.from)) +// if (m_accounts.isProxyAccount(t.from)) +// m_accounts.storeTransaction(t); return ret; + } if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) @@ -702,9 +705,9 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { if (t.to) // TODO: from qethereum, insert validification hook here. - client()->transact(m_accountsLookup[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); + client()->transact(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); else - ret = toJS(client()->transact(m_accountsLookup[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->transact(m_accounts.secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); client()->flushTransactions(); } return ret; @@ -741,4 +744,3 @@ bool WebThreeStubServerBase::eth_uninstallFilter(int _id) client()->uninstallWatch(_id); return true; } - diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index ec83c9797..988f13b8f 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include #include #pragma GCC diagnostic push @@ -53,6 +54,32 @@ public: virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; }; + +/** + * Manages real accounts (where we know the secret key) and proxy accounts (where transactions + * to be sent from these accounts are forwarded to a proxy on the other side). + */ +class AccountHolder +{ +public: + explicit AccountHolder(std::function const& _client): m_client(_client) {} + + /// Sets or resets the list of real accounts. + void setAccounts(std::vector const& _accounts); + std::vector const& getRealAccounts() const { return m_accounts; } + bool isRealAccount(dev::Address const& _account) const { return m_keyPairs.count(_account) > 0; } + Secret const& secretKey(dev::Address const& _account) const { return m_keyPairs.at(_account).secret(); } + std::vector const& getAllAccounts() const { return m_accounts; /*todo */} + dev::Address const& getDefaultCallAccount() const; + +private: + std::map m_keyPairs; + std::vector m_accounts; + std::function m_client; + +}; + + /** * @brief JSON-RPC api implementation * @todo filters should work on unsigned instead of int @@ -125,7 +152,7 @@ public: virtual bool shh_post(Json::Value const& _json); virtual bool shh_uninstallFilter(int _id); - void setAccounts(std::vector const& _accounts); + void setAccounts(std::vector const& _accounts) { m_accounts.setAccounts(_accounts); } void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } @@ -138,11 +165,9 @@ protected: virtual dev::WebThreeNetworkFace* network() = 0; virtual dev::WebThreeStubDatabaseFace* db() = 0; - std::map m_accountsLookup; - std::vector m_accounts; - std::map m_ids; std::map m_shhWatches; + AccountHolder m_accounts; }; } //namespace dev