Merge branch 'master' of github.com:cryptonomex/graphene

This commit is contained in:
Daniel Larimer 2015-07-24 17:04:00 -04:00
commit 0b5b31ab74
12 changed files with 134 additions and 63 deletions

View file

@ -27,19 +27,19 @@ class Account : public GrapheneObject {
public: public:
Account(ObjectId id = -1, QString name = QString(), QObject* parent = nullptr) Account(ObjectId id = -1, QString name = QString(), QObject* parent = nullptr)
: GrapheneObject(id, parent) : GrapheneObject(id, parent)
{ {
m_account.name = name.toStdString(); m_account.name = name.toStdString();
} }
void setAccountObject( const account_object& obj ) void setAccountObject(const account_object& obj)
{ {
auto old_name = m_account.name; auto old_name = m_account.name;
m_account = obj; m_account = obj;
if( old_name != m_account.name ) if (old_name != m_account.name)
Q_EMIT nameChanged(); Q_EMIT nameChanged();
} }
QString name()const { return toQString(m_account.name); } QString name()const { return QString::fromStdString(m_account.name); }
QQmlListProperty<Balance> balances(); QQmlListProperty<Balance> balances();
void setBalances(QList<Balance*> balances) { void setBalances(QList<Balance*> balances) {
@ -52,11 +52,11 @@ public:
void update(const account_balance_object& balance); void update(const account_balance_object& balance);
/** /**
* Anything greater than 1.0 means full authority. * Anything greater than 1.0 means full authority.
* Anything between (0 and 1.0) means partial authority * Anything between (0 and 1.0) means partial authority
* 0 means no authority. * 0 means no authority.
* *
* @return the percent of direct control the wallet has over the account. * @return the percent of direct control the wallet has over the account.
*/ */
Q_INVOKABLE double getOwnerControl( Wallet* w )const; Q_INVOKABLE double getOwnerControl( Wallet* w )const;

View file

@ -195,7 +195,7 @@ void ChainDataModel::getAccountImpl(QString accountIdentifier, Account* const *
} else { } else {
m_accounts.modify(itr, [this,&accountPackage](Account* a){ m_accounts.modify(itr, [this,&accountPackage](Account* a){
a->setProperty("id", ObjectId(accountPackage->account.id.instance())); a->setProperty("id", ObjectId(accountPackage->account.id.instance()));
a->setAccountObject( accountPackage->account ); a->setAccountObject(accountPackage->account);
// Set balances // Set balances
QList<Balance*> balances; QList<Balance*> balances;

View file

@ -5,8 +5,6 @@
#include <functional> #include <functional>
QString toQString( const std::string& s );
using ObjectId = qint64; using ObjectId = qint64;
Q_DECLARE_METATYPE(ObjectId) Q_DECLARE_METATYPE(ObjectId)

View file

@ -43,6 +43,7 @@ OperationBase* Transaction::operationAt(int index) const {
void Transaction::appendOperation(OperationBase* op) void Transaction::appendOperation(OperationBase* op)
{ {
op->setParent(this);
m_transaction.operations.push_back(op->genericOperation()); m_transaction.operations.push_back(op->genericOperation());
Q_EMIT operationsChanged(); Q_EMIT operationsChanged();
} }

View file

@ -18,14 +18,9 @@ public:
QQmlListProperty<OperationBase> operations(); QQmlListProperty<OperationBase> operations();
OperationBase* operationAt(int index) const; OperationBase* operationAt(int index) const;
void appendOperation(OperationBase* op);
int operationCount() const { int operationCount() const {
return m_transaction.operations.size(); return m_transaction.operations.size();
} }
void clearOperations() {
m_transaction.operations.clear();
Q_EMIT operationsChanged();
}
public slots: public slots:
void setStatus(Status status) void setStatus(Status status)
@ -37,6 +32,16 @@ public slots:
emit statusChanged(status); emit statusChanged(status);
} }
/**
* @brief Append the operation to the transaction
* @param op The operation to append. This Transaction will take ownership of the operation.
*/
void appendOperation(OperationBase* op);
void clearOperations() {
m_transaction.operations.clear();
Q_EMIT operationsChanged();
}
signals: signals:
void statusChanged(Status status); void statusChanged(Status status);
void operationsChanged(); void operationsChanged();

View file

@ -3,10 +3,9 @@
#include <fc/crypto/aes.hpp> #include <fc/crypto/aes.hpp>
#include <fc/io/json.hpp> #include <fc/io/json.hpp>
QString toQString( const std::string& s ) { QString result; result.fromStdString( s ); return result; } QString toQString(public_key_type k) { return QString::fromStdString(fc::variant(k).as_string()); }
QString toQString( public_key_type k ) { return toQString( fc::variant(k).as_string() ); }
Wallet::Wallet( QObject* parent ) Wallet::Wallet(QObject* parent)
:QObject(parent) :QObject(parent)
{ {
} }
@ -16,10 +15,10 @@ Wallet::~Wallet()
close(); close();
} }
bool Wallet::open( QString file_path ) bool Wallet::open(QString file_path)
{ {
fc::path p( file_path.toStdString() ); fc::path p(file_path.toStdString());
if( !fc::exists( p ) ) if( !fc::exists(p) )
{ {
ilog( "Unable to open wallet file '${f}', it does not exist", ("f",p) ); ilog( "Unable to open wallet file '${f}', it does not exist", ("f",p) );
return false; return false;
@ -30,7 +29,7 @@ bool Wallet::open( QString file_path )
for( const auto& key : _data.encrypted_private_keys ) for( const auto& key : _data.encrypted_private_keys )
{ {
if( key.second.label != string() ) if( key.second.label != string() )
_label_to_key[toQString(key.second.label)] = toQString( key.first ); _label_to_key[QString::fromStdString(key.second.label)] = toQString(key.first);
if( key.second.encrypted_private_key.size() ) if( key.second.encrypted_private_key.size() )
_available_private_keys.insert( key.first ); _available_private_keys.insert( key.first );
} }
@ -194,7 +193,7 @@ bool Wallet::hasPrivateKey( QString pubkey, bool include_with_brain_key )
auto itr = _data.encrypted_private_keys.find(pub); auto itr = _data.encrypted_private_keys.find(pub);
if( itr == _data.encrypted_private_keys.end() ) if( itr == _data.encrypted_private_keys.end() )
return false; return false;
if( itr->second.encrypted_private_key.size() ) if( itr->second.encrypted_private_key.size() )
return true; return true;
if( include_with_brain_key && itr->second.brain_sequence >= 0 ) if( include_with_brain_key && itr->second.brain_sequence >= 0 )
{ {
@ -217,7 +216,7 @@ QString Wallet::getPrivateKey( QString pubkey )
if( itr->second.encrypted_private_key.size() == 0 ) if( itr->second.encrypted_private_key.size() == 0 )
return QString(); return QString();
auto plain = fc::aes_decrypt( _decrypted_master_key, itr->second.encrypted_private_key ); auto plain = fc::aes_decrypt( _decrypted_master_key, itr->second.encrypted_private_key );
return toQString( fc::raw::unpack<std::string>(plain) ); return QString::fromStdString( fc::raw::unpack<std::string>(plain) );
} }
QString Wallet::getPublicKey( QString wif_private_key )const QString Wallet::getPublicKey( QString wif_private_key )const
@ -227,7 +226,7 @@ QString Wallet::getPublicKey( QString wif_private_key )const
auto pub = public_key_type(priv->get_public_key()); auto pub = public_key_type(priv->get_public_key());
return toQString( fc::variant( pub ).as_string() ); return QString::fromStdString( fc::variant( pub ).as_string() );
} }
QString Wallet::getActivePrivateKey( QString owner_pub_key, uint32_t seq ) QString Wallet::getActivePrivateKey( QString owner_pub_key, uint32_t seq )
@ -251,7 +250,7 @@ QString Wallet::getActivePrivateKey( QString owner_pub_key, uint32_t seq )
_data.encrypted_private_keys[active_pub_key].brain_sequence = seq; _data.encrypted_private_keys[active_pub_key].brain_sequence = seq;
_available_private_keys.insert( active_pub_key ); _available_private_keys.insert( active_pub_key );
return toQString(wif); return QString::fromStdString(wif);
} }
QString Wallet::getOwnerPrivateKey( uint32_t seq ) QString Wallet::getOwnerPrivateKey( uint32_t seq )
@ -273,7 +272,7 @@ QString Wallet::getOwnerPrivateKey( uint32_t seq )
_data.encrypted_private_keys[owner_pub_key].brain_sequence = seq; _data.encrypted_private_keys[owner_pub_key].brain_sequence = seq;
_available_private_keys.insert( owner_pub_key ); _available_private_keys.insert( owner_pub_key );
return toQString( wif ); return QString::fromStdString( wif );
} }
QString Wallet::getActivePublicKey( QString active_pub, uint32_t seq ) QString Wallet::getActivePublicKey( QString active_pub, uint32_t seq )
@ -294,11 +293,11 @@ QString Wallet::getKeyLabel( QString pubkey )
auto itr = _data.encrypted_private_keys.find( key ); auto itr = _data.encrypted_private_keys.find( key );
if( itr == _data.encrypted_private_keys.end() ) if( itr == _data.encrypted_private_keys.end() )
return QString(); return QString();
return toQString( itr->second.label ); return QString::fromStdString( itr->second.label );
} }
/** /**
* The same label may not be assigned to more than one key, this method will * The same label may not be assigned to more than one key, this method will
* fail if a key with the same label already exists. * fail if a key with the same label already exists.
* *
* @return true if the label was set * @return true if the label was set
*/ */
@ -310,7 +309,7 @@ bool Wallet::setKeyLabel( QString pubkey, QString label )
auto old_label = _data.encrypted_private_keys[pub].label; auto old_label = _data.encrypted_private_keys[pub].label;
_data.encrypted_private_keys[pub].label = string(); _data.encrypted_private_keys[pub].label = string();
if( old_label.size() ) if( old_label.size() )
_label_to_key.erase( toQString( old_label ) ); _label_to_key.erase( QString::fromStdString( old_label ) );
return true; return true;
} }
@ -336,7 +335,7 @@ QList<QPair<QString,QString> > Wallet::getAllPublicKeys( bool only_if_private )c
for( const auto& item : _data.encrypted_private_keys ) for( const auto& item : _data.encrypted_private_keys )
{ {
if( only_if_private && !item.second.encrypted_private_key.size() ) continue; if( only_if_private && !item.second.encrypted_private_key.size() ) continue;
result.push_back( qMakePair( toQString( item.first ), toQString( item.second.label ) ) ); result.push_back( qMakePair( toQString( item.first ), QString::fromStdString( item.second.label ) ) );
} }
return result; return result;
@ -359,9 +358,9 @@ bool Wallet::importPublicKey( QString pubkey, QString label )
return setKeyLabel( pubkey, label ); return setKeyLabel( pubkey, label );
} }
/** /**
* @param wifkey a private key in (WIF) Wallet Import Format * @param wifkey a private key in (WIF) Wallet Import Format
* @pre !isLocked() * @pre !isLocked()
**/ **/
bool Wallet::importPrivateKey( QString wifkey, QString label ) bool Wallet::importPrivateKey( QString wifkey, QString label )
{ {
@ -390,14 +389,14 @@ bool Wallet::removePublicKey( QString pubkey )
auto itr = _data.encrypted_private_keys.find(pub); auto itr = _data.encrypted_private_keys.find(pub);
if( itr != _data.encrypted_private_keys.end() ) if( itr != _data.encrypted_private_keys.end() )
{ {
_label_to_key.erase( toQString(itr->second.label) ); _label_to_key.erase( QString::fromStdString(itr->second.label) );
_data.encrypted_private_keys.erase(itr); _data.encrypted_private_keys.erase(itr);
return true; return true;
} }
return false; return false;
} }
/** removes only the private key, keeping the public key and label /** removes only the private key, keeping the public key and label
* *
* @pre isOpen() && !isLocked() * @pre isOpen() && !isLocked()
**/ **/
@ -416,7 +415,7 @@ bool Wallet::removePrivateKey( QString pubkey )
/** /**
* @pre !isLocked() * @pre !isLocked()
*/ */
vector<signature_type> Wallet::signDigest( const digest_type& d, vector<signature_type> Wallet::signDigest( const digest_type& d,
const set<public_key_type>& keys )const const set<public_key_type>& keys )const
{ {
vector<signature_type> result; vector<signature_type> result;

View file

@ -16,7 +16,6 @@ using graphene::chain::digest_type;
using graphene::chain::signature_type; using graphene::chain::signature_type;
using fc::optional; using fc::optional;
QString toQString( const std::string& s );
QString toQString( public_key_type k ); QString toQString( public_key_type k );
struct key_data struct key_data
@ -38,12 +37,12 @@ struct wallet_file
map<public_key_type, key_data> encrypted_private_keys; map<public_key_type, key_data> encrypted_private_keys;
}; };
FC_REFLECT( wallet_file, FC_REFLECT( wallet_file,
(encrypted_brain_key) (encrypted_brain_key)
(brain_key_digest) (brain_key_digest)
(encrypted_master_key) (encrypted_master_key)
(master_key_digest) (master_key_digest)
(encrypted_private_keys) (encrypted_private_keys)
); );
@ -57,6 +56,8 @@ FC_REFLECT( wallet_file,
class Wallet : public QObject class Wallet : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool isOpen READ isOpen NOTIFY isOpenChanged)
Q_PROPERTY(bool isLocked READ isLocked NOTIFY isLockedChanged)
public: public:
Wallet( QObject* parent = nullptr ); Wallet( QObject* parent = nullptr );
~Wallet(); ~Wallet();
@ -86,7 +87,7 @@ class Wallet : public QObject
/** /**
* @pre !isLocked(); * @pre !isLocked();
* @post save() * @post save()
* @return WIF private key * @return WIF private key
*/ */
Q_INVOKABLE QString getActivePrivateKey( QString owner_public_key, uint32_t sequence ); Q_INVOKABLE QString getActivePrivateKey( QString owner_public_key, uint32_t sequence );
Q_INVOKABLE QString getActivePublicKey( QString owner_public_key, uint32_t sequence ); Q_INVOKABLE QString getActivePublicKey( QString owner_public_key, uint32_t sequence );
@ -95,7 +96,7 @@ class Wallet : public QObject
* @pre !isLocked(); * @pre !isLocked();
* @pre hasBrainKey(); * @pre hasBrainKey();
* @post save() * @post save()
* @return WIF private key * @return WIF private key
*/ */
Q_INVOKABLE QString getOwnerPrivateKey( uint32_t sequence ); Q_INVOKABLE QString getOwnerPrivateKey( uint32_t sequence );
Q_INVOKABLE QString getOwnerPublicKey( uint32_t sequence ); Q_INVOKABLE QString getOwnerPublicKey( uint32_t sequence );
@ -110,9 +111,9 @@ class Wallet : public QObject
/** imports a public key and assigns it a label */ /** imports a public key and assigns it a label */
Q_INVOKABLE bool importPublicKey( QString pubkey, QString label = QString() ); Q_INVOKABLE bool importPublicKey( QString pubkey, QString label = QString() );
/** /**
* @param wifkey a private key in (WIF) Wallet Import Format * @param wifkey a private key in (WIF) Wallet Import Format
* @pre !isLocked() * @pre !isLocked()
**/ **/
Q_INVOKABLE bool importPrivateKey( QString wifkey, QString label = QString() ); Q_INVOKABLE bool importPrivateKey( QString wifkey, QString label = QString() );
@ -131,7 +132,7 @@ class Wallet : public QObject
/** /**
* @pre !isLocked() * @pre !isLocked()
*/ */
vector<signature_type> signDigest( const digest_type& d, vector<signature_type> signDigest( const digest_type& d,
const set<public_key_type>& keys )const; const set<public_key_type>& keys )const;
const flat_set<public_key_type>& getAvailablePrivateKeys()const; const flat_set<public_key_type>& getAvailablePrivateKeys()const;
@ -149,5 +150,3 @@ class Wallet : public QObject
map<QString,QString> _label_to_key; map<QString,QString> _label_to_key;
QString _brain_key; QString _brain_key;
}; };

View file

@ -29,7 +29,8 @@ Rectangle {
var form = formType.createObject(formContainer, params) var form = formType.createObject(formContainer, params)
formContainer.data = [form] formContainer.data = [form]
form.finished.connect(function(){state = "HIDDEN"}) form.canceled.connect(function(){state = "HIDDEN"; internal.callbackArgs = []})
form.completed.connect(function(){state = "HIDDEN"; internal.callbackArgs = arguments})
if (closedCallback instanceof Function) if (closedCallback instanceof Function)
internal.callback = closedCallback internal.callback = closedCallback
state = "SHOWN" state = "SHOWN"
@ -89,6 +90,7 @@ Rectangle {
if (internal.callback instanceof Function) if (internal.callback instanceof Function)
internal.callback() internal.callback()
internal.callback = undefined internal.callback = undefined
internal.callbackArgs = []
} }
} }
}, },
@ -145,5 +147,6 @@ Rectangle {
QtObject { QtObject {
id: internal id: internal
property var callback property var callback
property var callbackArgs
} }
} }

View file

@ -0,0 +1,51 @@
import QtQuick 2.5
import Graphene.Client 0.1
Flipable {
id: flipable
anchors.fill: parent
property Component frontComponent
property Component backComponent
property GrapheneApplication app
signal canceled
signal completed
property bool flipped: false
Component.onCompleted: {
back = backComponent.createObject(flipable, {app: app, enabled: Qt.binding(function(){return flipped})})
front = frontComponent.createObject(flipable, {app: app, enabled: Qt.binding(function(){return !flipped})})
front.canceled.connect(function() { canceled.apply(this, arguments) })
front.completed.connect(function() {
if (back.hasOwnProperty("arguments"))
back.arguments = arguments
flipped = true
})
back.canceled.connect(function() {
if (front.hasOwnProperty("arguments"))
front.arguments = arguments
flipped = false
})
back.completed.connect(function() { completed.apply(this, arguments) })
}
transform: Rotation {
id: rotation
origin.x: flipable.width/2
origin.y: flipable.height/2
axis.x: 0; axis.y: 1; axis.z: 0 // set axis.y to 1 to rotate around y-axis
angle: 0 // the default angle
}
states: State {
name: "back"
PropertyChanges { target: rotation; angle: 180 }
when: flipable.flipped
}
transitions: Transition {
NumberAnimation { target: rotation; property: "angle"; duration: 500 }
}
}

View file

@ -15,14 +15,21 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
property GrapheneApplication app property GrapheneApplication app
signal finished signal canceled
signal completed(TransferOperation op)
/// The Account object for the sender /// The Account object for the sender
property alias senderAccount: senderPicker.account property alias senderAccount: senderPicker.account
/// The Account object for the receiver /// The Account object for the receiver
property alias receiverAccount: recipientPicker.account property alias receiverAccount: recipientPicker.account
/// The operation created in this form
property var operation function operation() {
if (!transferButton.enabled) return app.operationBuilder.transfer(0,0,0,0, memoField.text, 0)
return app.operationBuilder.transfer(senderPicker.account.id, recipientPicker.account.id,
amountField.value * amountField.precisionAdjustment,
amountField.maxBalance.type.id, memoField.text, 0)
}
Component.onCompleted: console.log("Made a transfer form") Component.onCompleted: console.log("Made a transfer form")
Component.onDestruction: console.log("Destroyed a transfer form") Component.onDestruction: console.log("Destroyed a transfer form")
@ -77,6 +84,12 @@ Rectangle {
property Balance maxBalance: assetField.enabled && senderPicker.showBalance >= 0? property Balance maxBalance: assetField.enabled && senderPicker.showBalance >= 0?
senderPicker.balances[senderPicker.showBalance] : null senderPicker.balances[senderPicker.showBalance] : null
property int precisionAdjustment: maxBalance? Math.pow(10, maxBalance.type.precision) : 1
// Workaround to preserve value in case form gets disabled then re-enabled
onEnabledChanged: if (!enabled) __valueBackup = value
onMaximumValueChanged: if (enabled && maximumValue > __valueBackup) value = __valueBackup
property real __valueBackup
} }
ComboBox { ComboBox {
id: assetField id: assetField
@ -89,25 +102,21 @@ Rectangle {
Text { Text {
font.pixelSize: assetField.height / 2.5 font.pixelSize: assetField.height / 2.5
text: { text: {
var balance = amountField.maxBalance if (!senderPicker.account)
if (!balance || !balance.type) return "" return ""
var precisionAdjustment = Math.pow(10, balance.type.precision) return qsTr("Fee:<br/>") + operation().fee / amountField.precisionAdjustment + " CORE"
var op = app.operationBuilder.transfer(0, 0, amountField.value * precisionAdjustment,
balance.type.id, memoField.text, 0)
return qsTr("Fee:<br/>") + op.fee / precisionAdjustment + " CORE"
} }
} }
Item { Layout.fillWidth: true } Item { Layout.fillWidth: true }
Button { Button {
text: qsTr("Cancel") text: qsTr("Cancel")
onClicked: finished() onClicked: canceled()
} }
Button { Button {
id: transferButton
text: qsTr("Transfer") text: qsTr("Transfer")
enabled: senderPicker.account && recipientPicker.account && senderPicker.account !== recipientPicker.account && amountField.value enabled: senderPicker.account && recipientPicker.account && senderPicker.account !== recipientPicker.account && amountField.value
onClicked: console.log(amountField.value) onClicked: completed(operation)
} }
} }
} }

View file

@ -60,10 +60,15 @@ ApplicationWindow {
Button { Button {
text: "Transfer" text: "Transfer"
onClicked: formBox.showForm(Qt.createComponent("TransferForm.qml"), {}, onClicked: {
function() { var front = Qt.createComponent("TransferForm.qml")
console.log("Closed form") // TODO: make back into a preview and confirm dialog
}) var back = Qt.createComponent("TransferForm.qml")
formBox.showForm(Qt.createComponent("FormFlipper.qml"), {frontComponent: front, backComponent: back},
function() {
console.log("Closed form")
})
}
} }
TextField { TextField {
id: nameField id: nameField

View file

@ -3,6 +3,7 @@
<file>main.qml</file> <file>main.qml</file>
<file>TransferForm.qml</file> <file>TransferForm.qml</file>
<file>FormBox.qml</file> <file>FormBox.qml</file>
<file>FormFlipper.qml</file>
<file>Scaling.qml</file> <file>Scaling.qml</file>
<file>Identicon.qml</file> <file>Identicon.qml</file>
<file>AccountPicker.qml</file> <file>AccountPicker.qml</file>