Browse Source

Merge pull request #1091 from chriseth/accountProxyQueues

Account proxy queues
cl-refactor
Gav Wood 10 years ago
parent
commit
a88c32a3e7
  1. 25
      alethzero/OurWebThreeStubServer.cpp
  2. 8
      alethzero/OurWebThreeStubServer.h
  3. 2
      libdevcrypto/Common.cpp
  4. 3
      libdevcrypto/Common.h
  5. 108
      libweb3jsonrpc/AccountHolder.cpp
  6. 74
      libweb3jsonrpc/AccountHolder.h
  7. 94
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  8. 12
      libweb3jsonrpc/WebThreeStubServerBase.h
  9. 18
      libweb3jsonrpc/abstractwebthreestubserver.h
  10. 4
      libweb3jsonrpc/spec.json
  11. 74
      test/AccountHolder.cpp
  12. 30
      test/webthreestubclient.h

25
alethzero/OurWebThreeStubServer.cpp

@ -51,22 +51,24 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string
return button == QMessageBox::Ok;
}
bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t) const
bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) const
{
return showAuthenticationPopup("Contract Creation Transaction", "ÐApp is attemping to create a contract; to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is <b>" + formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>.");
return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is <b>" + formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>.");
}
bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t) const
bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) const
{
return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is <b>" + formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>.");
return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") +
", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is <b>" + formatBalance(_t.value + _t.gas * _t.gasPrice) + "</b>.");
}
bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) const
bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) const
{
return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!",
"ÐApp is attempting to call into an unknown contract at address " +
m_main->pretty(_t.to).toStdString() +
".\n\nCall involves sending " +
m_main->pretty(_t.to).toStdString() + ".\n\n" +
(_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") +
"Call involves sending " +
formatBalance(_t.value) + " to the recipient, with additional network fees of up to " +
formatBalance(_t.gas * _t.gasPrice) +
"However, this also does other stuff which we don't understand, and does so in your name.\n\n" +
@ -76,25 +78,25 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t)
"REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!");
}
bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy)
{
if (_t.creation)
{
// recipient has no code - nothing special about this transaction, show basic value transfer info
return showCreationNotice(_t);
return showCreationNotice(_t, _toProxy);
}
h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to);
if (contractCodeHash == EmptySHA3)
{
// recipient has no code - nothing special about this transaction, show basic value transfer info
return showSendNotice(_t);
return showSendNotice(_t, _toProxy);
}
string userNotice = m_main->natSpec()->getUserNotice(contractCodeHash, _t.data);
if (userNotice.empty())
return showUnknownCallNotice(_t);
return showUnknownCallNotice(_t, _toProxy);
NatspecExpressionEvaluator evaluator;
userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString();
@ -104,6 +106,7 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
"ÐApp attempting to conduct contract interaction with " +
m_main->pretty(_t.to).toStdString() +
": <b>" + userNotice + "</b>.\n\n" +
(_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") +
(_t.value > 0 ?
"In addition, ÐApp is attempting to send " +
formatBalance(_t.value) + " to said recipient, with additional network fees of up to " +

8
alethzero/OurWebThreeStubServer.h

@ -35,16 +35,16 @@ public:
std::vector<dev::KeyPair> const& _accounts, Main* main);
virtual std::string shh_newIdentity() override;
virtual bool authenticate(dev::eth::TransactionSkeleton const& _t);
virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
signals:
void onNewId(QString _s);
private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const;
bool showCreationNotice(dev::eth::TransactionSkeleton const& _t) const;
bool showSendNotice(dev::eth::TransactionSkeleton const& _t) const;
bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t) const;
bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const;
bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const;
bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const;
dev::WebThreeDirect* m_web3;
Main* m_main;

2
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;

3
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;

108
libweb3jsonrpc/AccountHolder.cpp

@ -0,0 +1,108 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AccountHolder.cpp
* @authors:
* Christian R <c@ethdev.com>
* Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#include "AccountHolder.h"
#include <random>
#include <ctime>
#include <libdevcore/Guards.h>
#include <libethereum/Client.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
vector<TransactionSkeleton> g_emptyQueue;
static std::mt19937 g_randomNumberGenerator(time(0));
static Mutex x_rngMutex;
void AccountHolder::setAccounts(vector<KeyPair> const& _accounts)
{
m_accounts.clear();
for (auto const& keyPair: _accounts)
{
m_accounts.push_back(keyPair.address());
m_keyPairs[keyPair.address()] = keyPair;
}
}
vector<Address> AccountHolder::getAllAccounts() const
{
vector<Address> accounts = m_accounts;
for (auto const& pair: m_proxyAccounts)
if (!isRealAccount(pair.first))
accounts.push_back(pair.first);
return accounts;
}
Address const& AccountHolder::getDefaultTransactAccount() 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;
}
int AccountHolder::addProxyAccount(const Address& _account)
{
Guard g(x_rngMutex);
int id = std::uniform_int_distribution<int>(1)(g_randomNumberGenerator);
id = int(u256(FixedHash<32>(sha3(bytesConstRef((byte*)(&id), sizeof(int) / sizeof(byte))))));
if (isProxyAccount(_account) || id == 0 || m_transactionQueues.count(id))
return 0;
m_proxyAccounts.insert(make_pair(_account, id));
m_transactionQueues[id].first = _account;
return id;
}
bool AccountHolder::removeProxyAccount(unsigned _id)
{
if (!m_transactionQueues.count(_id))
return false;
m_proxyAccounts.erase(m_transactionQueues[_id].first);
m_transactionQueues.erase(_id);
return true;
}
void AccountHolder::queueTransaction(TransactionSkeleton const& _transaction)
{
if (!m_proxyAccounts.count(_transaction.from))
return;
int id = m_proxyAccounts[_transaction.from];
m_transactionQueues[id].second.push_back(_transaction);
}
vector<TransactionSkeleton> const& AccountHolder::getQueuedTransactions(int _id) const
{
if (!m_transactionQueues.count(_id))
return g_emptyQueue;
return m_transactionQueues.at(_id).second;
}
void AccountHolder::clearQueue(int _id)
{
if (m_transactionQueues.count(_id))
m_transactionQueues.at(_id).second.clear();
}

74
libweb3jsonrpc/AccountHolder.h

@ -0,0 +1,74 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AccountHolder.h
* @authors:
* Christian R <c@ethdev.com>
* Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#pragma once
#include <functional>
#include <vector>
#include <map>
#include <libdevcrypto/Common.h>
#include <libethcore/CommonJS.h>
namespace dev
{
namespace eth
{
class Interface;
}
/**
* 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<eth::Interface*()> const& _client): m_client(_client) {}
/// Sets or resets the list of real accounts.
void setAccounts(std::vector<KeyPair> const& _accounts);
std::vector<Address> const& getRealAccounts() const { return m_accounts; }
bool isRealAccount(Address const& _account) const { return m_keyPairs.count(_account) > 0; }
bool isProxyAccount(Address const& _account) const { return m_proxyAccounts.count(_account) > 0; }
Secret const& secretKey(Address const& _account) const { return m_keyPairs.at(_account).secret(); }
std::vector<Address> getAllAccounts() const;
Address const& getDefaultTransactAccount() const;
int addProxyAccount(Address const& _account);
bool removeProxyAccount(unsigned _id);
void queueTransaction(eth::TransactionSkeleton const& _transaction);
std::vector<eth::TransactionSkeleton> const& getQueuedTransactions(int _id) const;
void clearQueue(int _id);
private:
using TransactionQueue = std::vector<eth::TransactionSkeleton>;
std::map<Address, KeyPair> m_keyPairs;
std::vector<Address> m_accounts;
std::map<Address, int> m_proxyAccounts;
std::map<int, std::pair<Address, TransactionQueue>> m_transactionQueues;
std::function<eth::Interface*()> m_client;
};
}

94
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -35,11 +35,13 @@
#include <libserpent/funcs.h>
#endif
#include "WebThreeStubServerBase.h"
#include "AccountHolder.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
static Json::Value toJson(dev::eth::BlockInfo const& _bi)
{
Json::Value res;
@ -72,6 +74,18 @@ static Json::Value toJson(dev::eth::Transaction const& _t)
return res;
}
static Json::Value toJson(dev::eth::TransactionSkeleton const& _t)
{
Json::Value res;
res["to"] = toJS(_t.to);
res["from"] = toJS(_t.from);
res["gas"] = toJS(_t.gas);
res["gasPrice"] = toJS(_t.gasPrice);
res["value"] = toJS(_t.value);
res["data"] = jsFromBinary(_t.data);
return res;
}
static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e)
{
Json::Value res;
@ -212,19 +226,9 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message
}
WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts):
AbstractWebThreeStubServer(_conn)
{
setAccounts(_accounts);
}
void WebThreeStubServerBase::setAccounts(std::vector<dev::KeyPair> const& _accounts)
AbstractWebThreeStubServer(_conn), m_accounts(make_shared<AccountHolder>(std::bind(&WebThreeStubServerBase::client, this)))
{
m_accounts.clear();
for (auto const& i: _accounts)
{
m_accounts.push_back(i.address());
m_accountsLookup[i.address()] = i;
}
m_accounts->setAccounts(_accounts);
}
void WebThreeStubServerBase::setIdentities(std::vector<dev::KeyPair> const& _ids)
@ -242,7 +246,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 +330,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->getDefaultTransactAccount();
if (!m_accounts->isRealAccount(t.from))
return ret;
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = min<u256>(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;
}
@ -464,6 +462,25 @@ bool WebThreeStubServerBase::eth_submitWork(std::string const& _nonce)
return client()->submitNonce(jsToFixed<32>(_nonce));
}
int WebThreeStubServerBase::eth_register(std::string const& _address)
{
return m_accounts->addProxyAccount(jsToAddress(_address));
}
bool WebThreeStubServerBase::eth_unregister(int _id)
{
return m_accounts->removeProxyAccount(_id);
}
Json::Value WebThreeStubServerBase::eth_queuedTransactions(int _id)
{
Json::Value ret(Json::arrayValue);
for (TransactionSkeleton const& t: m_accounts->getQueuedTransactions(_id))
ret.append(toJson(t));
m_accounts->clearQueue(_id);
return ret;
}
std::string WebThreeStubServerBase::shh_newGroup(std::string const& _id, std::string const& _who)
{
(void)_id;
@ -684,33 +701,32 @@ std::string WebThreeStubServerBase::eth_transact(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))
return ret;
if (!t.from)
t.from = m_accounts->getDefaultTransactAccount();
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);
if (authenticate(t))
if (!m_accounts->isRealAccount(t.from))
{
if (m_accounts->isProxyAccount(t.from))
if (authenticate(t, true))
m_accounts->queueTransaction(t);
return ret;
}
if (authenticate(t, false))
{
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;
}
bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t)
bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool)
{
cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here.";
return true;
@ -742,3 +758,7 @@ bool WebThreeStubServerBase::eth_uninstallFilter(int _id)
return true;
}
void WebThreeStubServerBase::setAccounts(const std::vector<KeyPair>& _accounts)
{
m_accounts->setAccounts(_accounts);
}

12
libweb3jsonrpc/WebThreeStubServerBase.h

@ -23,6 +23,7 @@
#pragma once
#include <memory>
#include <iostream>
#include <jsonrpccpp/server.h>
#include <libdevcrypto/Common.h>
@ -35,6 +36,7 @@
namespace dev
{
class WebThreeNetworkFace;
class AccountHolder;
class KeyPair;
namespace eth
{
@ -110,6 +112,10 @@ public:
virtual Json::Value eth_getWork();
virtual bool eth_submitWork(std::string const& _nonce);
virtual int eth_register(std::string const& _address);
virtual bool eth_unregister(int _id);
virtual Json::Value eth_queuedTransactions(int _id);
virtual std::string db_get(std::string const& _name, std::string const& _key);
virtual std::string db_getString(std::string const& _name, std::string const& _key);
virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value);
@ -130,7 +136,7 @@ public:
std::map<dev::Public, dev::Secret> const& ids() const { return m_ids; }
protected:
virtual bool authenticate(dev::eth::TransactionSkeleton const& _t);
virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy);
protected:
virtual dev::eth::Interface* client() = 0;
@ -138,11 +144,9 @@ protected:
virtual dev::WebThreeNetworkFace* network() = 0;
virtual dev::WebThreeStubDatabaseFace* db() = 0;
std::map<dev::Address, dev::KeyPair> m_accountsLookup;
std::vector<dev::Address> m_accounts;
std::map<dev::Public, dev::Secret> m_ids;
std::map<unsigned, dev::Public> m_shhWatches;
std::shared_ptr<dev::AccountHolder> m_accounts;
};
} //namespace dev

18
libweb3jsonrpc/abstractwebthreestubserver.h

@ -55,6 +55,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_register", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_registerI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_unregister", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_unregisterI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_queuedTransactions", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_queuedTransactionsI);
this->bindAndAddMethod(jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI);
this->bindAndAddMethod(jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI);
this->bindAndAddMethod(jsonrpc::Procedure("db_putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putStringI);
@ -253,6 +256,18 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
{
response = this->eth_submitWork(request[0u].asString());
}
inline virtual void eth_registerI(const Json::Value &request, Json::Value &response)
{
response = this->eth_register(request[0u].asString());
}
inline virtual void eth_unregisterI(const Json::Value &request, Json::Value &response)
{
response = this->eth_unregister(request[0u].asInt());
}
inline virtual void eth_queuedTransactionsI(const Json::Value &request, Json::Value &response)
{
response = this->eth_queuedTransactions(request[0u].asInt());
}
inline virtual void db_putI(const Json::Value &request, Json::Value &response)
{
response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString());
@ -349,6 +364,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual Json::Value eth_logs(const Json::Value& param1) = 0;
virtual Json::Value eth_getWork() = 0;
virtual bool eth_submitWork(const std::string& param1) = 0;
virtual int eth_register(const std::string& param1) = 0;
virtual bool eth_unregister(int param1) = 0;
virtual Json::Value eth_queuedTransactions(int param1) = 0;
virtual bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual std::string db_get(const std::string& param1, const std::string& param2) = 0;
virtual bool db_putString(const std::string& param1, const std::string& param2, const std::string& param3) = 0;

4
libweb3jsonrpc/spec.json

@ -50,6 +50,10 @@
{ "name": "eth_getWork", "params": [], "order": [], "returns": []},
{ "name": "eth_submitWork", "params": [""], "order": [], "returns": true},
{ "name": "eth_register", "params": [""], "order": [], "returns": 0},
{ "name": "eth_unregister", "params": [0], "order": [], "returns": true},
{ "name": "eth_queuedTransactions", "params": [0], "order": [], "returns": []},
{ "name": "db_put", "params": ["", "", ""], "order": [], "returns": true},
{ "name": "db_get", "params": ["", ""], "order": [], "returns": ""},
{ "name": "db_putString", "params": ["", "", ""], "order": [], "returns": true},

74
test/AccountHolder.cpp

@ -0,0 +1,74 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian R <c@ethdev.com>
* @date 2015
* Unit tests for the account holder used by the WebThreeStubServer.
*/
#include <boost/test/unit_test.hpp>
#include <libweb3jsonrpc/AccountHolder.h>
namespace dev
{
namespace test
{
BOOST_AUTO_TEST_SUITE(AccountHolderTest)
BOOST_AUTO_TEST_CASE(ProxyAccountUseCase)
{
AccountHolder h = AccountHolder(std::function<eth::Interface*()>());
BOOST_CHECK(h.getAllAccounts().empty());
BOOST_CHECK(h.getRealAccounts().empty());
Address addr("abababababababababababababababababababab");
Address addr2("abababababababababababababababababababab");
int id = h.addProxyAccount(addr);
BOOST_CHECK(h.getQueuedTransactions(id).empty());
// register it again
int secondID = h.addProxyAccount(addr);
BOOST_CHECK(h.getQueuedTransactions(secondID).empty());
eth::TransactionSkeleton t1;
eth::TransactionSkeleton t2;
t1.from = addr;
t1.data = fromHex("12345678");
t2.from = addr;
t2.data = fromHex("abcdef");
BOOST_CHECK(h.getQueuedTransactions(id).empty());
h.queueTransaction(t1);
BOOST_CHECK_EQUAL(1, h.getQueuedTransactions(id).size());
h.queueTransaction(t2);
BOOST_REQUIRE_EQUAL(2, h.getQueuedTransactions(id).size());
// second proxy should not see transactions
BOOST_CHECK(h.getQueuedTransactions(secondID).empty());
BOOST_CHECK(h.getQueuedTransactions(id)[0].data == t1.data);
BOOST_CHECK(h.getQueuedTransactions(id)[1].data == t2.data);
h.clearQueue(id);
BOOST_CHECK(h.getQueuedTransactions(id).empty());
// removing fails because it never existed
BOOST_CHECK(!h.removeProxyAccount(secondID));
BOOST_CHECK(h.removeProxyAccount(id));
}
BOOST_AUTO_TEST_SUITE_END()
}
}

30
test/webthreestubclient.h

@ -447,6 +447,36 @@ class WebThreeStubClient : public jsonrpc::Client
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
int eth_register(const std::string& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_register",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool eth_unregister(int param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_unregister",p);
if (result.isBool())
return result.asBool();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
Json::Value eth_queuedTransactions(int param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_queuedTransactions",p);
if (result.isArray())
return result;
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException)
{
Json::Value p;

Loading…
Cancel
Save