[GUI] Implement transaction broadcasting
Still need to set expiration, so none of the transactions I broadcast work yet... :( Sadly there is no testnet so I can't finish this. Oh well. I'm sure it'll be much easier on Monday.
This commit is contained in:
parent
02682e761c
commit
99d6450473
9 changed files with 68 additions and 18 deletions
|
|
@ -564,7 +564,7 @@ namespace graphene { namespace app {
|
|||
_app.p2p_node()->broadcast_transaction(trx);
|
||||
}
|
||||
|
||||
void network_broadcast_api::broadcast_transaction_with_callback( confirmation_callback cb, const signed_transaction& trx)
|
||||
void network_broadcast_api::broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction& trx)
|
||||
{
|
||||
trx.validate();
|
||||
_callbacks[trx.id()] = cb;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ public:
|
|||
m_account.name = name.toStdString();
|
||||
}
|
||||
void setAccountObject(const account_object& obj);
|
||||
const account_object& accountObject()const {
|
||||
return m_account;
|
||||
}
|
||||
|
||||
QString name()const { return QString::fromStdString(m_account.name); }
|
||||
QString memoKey()const;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "ChainDataModel.hpp"
|
||||
#include "Balance.hpp"
|
||||
#include "Operations.hpp"
|
||||
#include "Transaction.hpp"
|
||||
|
||||
#include <graphene/app/api.hpp>
|
||||
#include <graphene/chain/protocol/protocol.hpp>
|
||||
|
|
@ -26,11 +27,35 @@ void ChainDataModel::setDatabaseAPI(fc::api<database_api> dbapi) {
|
|||
m_db_api = dbapi;
|
||||
m_rpc_thread->async([this] {
|
||||
m_global_properties = m_db_api->get_global_properties();
|
||||
m_db_api->subscribe_to_objects([this](const variant& v) { m_global_properties = v.as<global_property_object>(); },
|
||||
{m_global_properties.id});
|
||||
m_db_api->subscribe_to_objects([this](const variant& v) {
|
||||
m_global_properties = v.as<global_property_object>();
|
||||
}, {m_global_properties.id});
|
||||
|
||||
m_dynamic_global_properties = m_db_api->get_dynamic_global_properties();
|
||||
m_db_api->subscribe_to_objects([this](const variant& d) {
|
||||
m_dynamic_global_properties = d.as<dynamic_global_property_object>();
|
||||
}, {m_dynamic_global_properties.id});
|
||||
});
|
||||
}
|
||||
|
||||
void ChainDataModel::setNetworkAPI(fc::api<network_broadcast_api> napi)
|
||||
{
|
||||
m_net_api = napi;
|
||||
}
|
||||
|
||||
void ChainDataModel::broadcast(Transaction* transaction)
|
||||
{
|
||||
try {
|
||||
m_net_api->broadcast_transaction_with_callback([transaction](const fc::variant&) {
|
||||
transaction->setStatus(Transaction::Complete);
|
||||
}, transaction->internalTransaction());
|
||||
transaction->setStatus(Transaction::Pending);
|
||||
} catch (const fc::exception& e) {
|
||||
transaction->setStatus(Transaction::Failed);
|
||||
Q_EMIT exceptionThrown(QString::fromStdString(e.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
Asset* ChainDataModel::getAsset(ObjectId id)
|
||||
{
|
||||
auto& by_id_idx = m_assets.get<by_id>();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ typedef multi_index_container<
|
|||
>
|
||||
> account_multi_index_type;
|
||||
|
||||
class Transaction;
|
||||
class ChainDataModel : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
|
@ -52,8 +53,13 @@ public:
|
|||
ChainDataModel(fc::thread& t, QObject* parent = nullptr);
|
||||
|
||||
void setDatabaseAPI(fc::api<graphene::app::database_api> dbapi);
|
||||
void setNetworkAPI(fc::api<graphene::app::network_broadcast_api> napi);
|
||||
|
||||
const graphene::chain::global_property_object& global_properties() const { return m_global_properties; }
|
||||
const graphene::chain::dynamic_global_property_object& dynamic_global_properties() const { return m_dynamic_global_properties; }
|
||||
|
||||
public Q_SLOTS:
|
||||
void broadcast(Transaction* transaction);
|
||||
|
||||
Q_SIGNALS:
|
||||
void queueExecute(const std::function<void()>&);
|
||||
|
|
@ -63,8 +69,10 @@ private:
|
|||
fc::thread* m_rpc_thread = nullptr;
|
||||
std::string m_api_url;
|
||||
fc::api<graphene::app::database_api> m_db_api;
|
||||
fc::api<graphene::app::network_broadcast_api> m_net_api;
|
||||
|
||||
graphene::chain::global_property_object m_global_properties;
|
||||
graphene::chain::dynamic_global_property_object m_dynamic_global_properties;
|
||||
|
||||
ObjectId m_account_query_num = -1;
|
||||
account_multi_index_type m_accounts;
|
||||
|
|
|
|||
|
|
@ -64,10 +64,12 @@ void GrapheneApplication::start(QString apiurl, QString user, QString pass)
|
|||
Q_EMIT loginFailed();
|
||||
return;
|
||||
}
|
||||
auto net_api = remote_api->network_broadcast();
|
||||
|
||||
ilog("connecting...");
|
||||
queueExecute([=](){
|
||||
m_model->setDatabaseAPI(db_api);
|
||||
m_model->setNetworkAPI(net_api);
|
||||
});
|
||||
|
||||
queueExecute([=](){ setIsConnected(true); });
|
||||
|
|
@ -87,6 +89,26 @@ Transaction* GrapheneApplication::createTransaction() const
|
|||
return new Transaction;
|
||||
}
|
||||
|
||||
void GrapheneApplication::signTransaction(Transaction* transaction) const
|
||||
{
|
||||
if (transaction == nullptr) return;
|
||||
|
||||
auto getActiveAuth = [this](graphene::chain::account_id_type id) {
|
||||
return &model()->getAccount(id.instance.value)->accountObject().active;
|
||||
};
|
||||
auto getOwnerAuth = [this](graphene::chain::account_id_type id) {
|
||||
return &model()->getAccount(id.instance.value)->accountObject().owner;
|
||||
};
|
||||
|
||||
auto& trx = transaction->internalTransaction();
|
||||
trx.set_reference_block(model()->dynamic_global_properties().head_block_id);
|
||||
flat_set<public_key_type> pubKeys = wallet()->getAvailablePrivateKeys();
|
||||
auto requiredKeys = trx.get_required_signatures(pubKeys, getActiveAuth, getOwnerAuth);
|
||||
trx.signatures = wallet()->signDigest(trx.digest(), requiredKeys);
|
||||
idump((trx));
|
||||
}
|
||||
|
||||
|
||||
Q_SLOT void GrapheneApplication::execute(const std::function<void()>& func)const
|
||||
{
|
||||
func();
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public:
|
|||
|
||||
/// Convenience method to get a Transaction in QML. Caller takes ownership of the new Transaction.
|
||||
Q_INVOKABLE Transaction* createTransaction() const;
|
||||
Q_INVOKABLE void signTransaction(Transaction* transaction) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void exceptionThrown(QString message);
|
||||
|
|
|
|||
|
|
@ -352,16 +352,6 @@ QList<QPair<QString,QString>> Wallet::getAllPublicKeys(bool only_if_private)cons
|
|||
return result;
|
||||
}
|
||||
|
||||
void Wallet::sign(Transaction* transaction) const
|
||||
{
|
||||
if (transaction == nullptr) return;
|
||||
|
||||
auto& trx = transaction->internalTransaction();
|
||||
flat_set<public_key_type> pubKeys = getAvailablePrivateKeys();
|
||||
trx.signatures = signDigest(trx.digest(), set<public_key_type>(pubKeys.begin(), pubKeys.end()));
|
||||
idump((trx));
|
||||
}
|
||||
|
||||
QString Wallet::getPublicKey(QString label)
|
||||
{
|
||||
if( !isOpen() ) return QString::null;
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ class Wallet : public QObject
|
|||
/**
|
||||
* @pre !isLocked()
|
||||
*/
|
||||
Q_INVOKABLE void sign(Transaction* transaction) const;
|
||||
vector<signature_type> signDigest(const digest_type& d,
|
||||
const set<public_key_type>& keys)const;
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ FormBase {
|
|||
UnlockingFinishButtons {
|
||||
app: base.app
|
||||
Layout.fillWidth: true
|
||||
rightButtonText: qsTr("Commit")
|
||||
onLeftButtonClicked: {
|
||||
canceled({})
|
||||
trx = null
|
||||
|
|
@ -73,7 +74,8 @@ FormBase {
|
|||
if (app.wallet.isLocked)
|
||||
app.wallet.unlock(passwordField.text)
|
||||
else {
|
||||
app.wallet.sign(trx)
|
||||
app.signTransaction(trx)
|
||||
app.model.broadcast(trx)
|
||||
completed(trx)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue