From 06364f5ff203df7edf6d6f8eadc8f4ddec8274aa Mon Sep 17 00:00:00 2001 From: clemahieu Date: Sat, 29 Nov 2014 17:29:18 -0600 Subject: [PATCH] Initial cut at manually creating blocks. --- rai/core/core.cpp | 5 + rai/core/core.hpp | 1 + rai/core_test/uint256_union.cpp | 7 + rai/core_test/wallet_test.cpp | 2 + rai/qt/qt.cpp | 273 +++++++++++++++++++++++++++++++- rai/qt/qt.hpp | 7 + rai/secure.cpp | 35 ++-- rai/secure.hpp | 1 + 8 files changed, 321 insertions(+), 10 deletions(-) diff --git a/rai/core/core.cpp b/rai/core/core.cpp index dbc06af1..9954f82c 100644 --- a/rai/core/core.cpp +++ b/rai/core/core.cpp @@ -544,6 +544,11 @@ bool rai::wallet::fetch (rai::public_key const & pub, rai::private_key & prv) return result; } +bool rai::wallet::exists (rai::public_key const & pub) +{ + return find (pub) != end (); +} + rai::key_iterator::key_iterator (leveldb::DB * db_a) : iterator (db_a->NewIterator (leveldb::ReadOptions ())) { diff --git a/rai/core/core.hpp b/rai/core/core.hpp index 9a638544..8b0280bc 100644 --- a/rai/core/core.hpp +++ b/rai/core/core.hpp @@ -298,6 +298,7 @@ namespace rai { rai::uint256_union salt (); void insert (rai::private_key const &); bool fetch (rai::public_key const &, rai::private_key &); + bool exists (rai::public_key const &); bool generate_send (rai::ledger &, rai::public_key const &, rai::uint128_t const &, std::vector > &); bool valid_password (); key_iterator find (rai::uint256_union const &); diff --git a/rai/core_test/uint256_union.cpp b/rai/core_test/uint256_union.cpp index 827d5f30..f35eb245 100644 --- a/rai/core_test/uint256_union.cpp +++ b/rai/core_test/uint256_union.cpp @@ -34,6 +34,13 @@ TEST (uint256_union, encryption) ASSERT_EQ (number1, number2); } +TEST (uint256_union, decode_empty) +{ + std::string text; + rai::uint256_union val; + ASSERT_TRUE (val.decode_hex (text)); +} + TEST (uint256_union, parse_zero) { rai::uint256_union input (rai::uint256_t (0)); diff --git a/rai/core_test/wallet_test.cpp b/rai/core_test/wallet_test.cpp index 7387b8b1..86e0e614 100644 --- a/rai/core_test/wallet_test.cpp +++ b/rai/core_test/wallet_test.cpp @@ -228,7 +228,9 @@ TEST (wallet, find_existing) rai::wallet wallet (init, boost::filesystem::unique_path ()); ASSERT_FALSE (init); rai::keypair key1; + ASSERT_FALSE (wallet.exists (key1.pub)); wallet.insert (key1.prv); + ASSERT_TRUE (wallet.exists (key1.pub)); auto existing (wallet.find (key1.pub)); ASSERT_NE (wallet.end (), existing); ++existing; diff --git a/rai/qt/qt.cpp b/rai/qt/qt.cpp index 4354f349..1bd57def 100644 --- a/rai/qt/qt.cpp +++ b/rai/qt/qt.cpp @@ -638,6 +638,9 @@ destination_label (new QLabel ("Destination:")), destination (new QLineEdit), representative_label (new QLabel ("Representative:")), representative (new QLineEdit), +block (new QPlainTextEdit), +status (new QLabel), +create (new QPushButton ("Create")), back (new QPushButton ("Back")), client (client_a) { @@ -645,6 +648,10 @@ client (client_a) group->addButton (receive); group->addButton (change); group->addButton (open); + group->setId (send, 0); + group->setId (receive, 1); + group->setId (change, 2); + group->setId (open, 3); button_layout->addWidget (send); button_layout->addWidget (receive); @@ -662,7 +669,9 @@ client (client_a) layout->addWidget (destination); layout->addWidget (representative_label); layout->addWidget (representative); - layout->addStretch (); + layout->addWidget (block); + layout->addWidget (status); + layout->addWidget (create); layout->addWidget (back); window->setLayout (layout); QObject::connect (send, &QRadioButton::toggled, [this] () @@ -697,6 +706,27 @@ client (client_a) activate_change (); } }); + QObject::connect (create, &QPushButton::released, [this] () + { + switch (group->checkedId ()) + { + case 0: + create_send (); + break; + case 1: + create_receive (); + break; + case 2: + create_change (); + break; + case 3: + create_open (); + break; + default: + assert (false); + break; + } + }); QObject::connect (back, &QPushButton::released, [this] () { client.pop_main_stack (); @@ -748,4 +778,245 @@ void rai_qt::block_creation::activate_change () account->show (); representative_label->show (); representative->show (); +} + +void rai_qt::block_creation::create_send () +{ + rai::account account_l; + auto error (account_l.decode_hex (account->text ().toStdString ())); + if (!error) + { + rai::amount amount_l; + error = account_l.decode_hex (amount->text ().toStdString ()); + if (!error) + { + rai::account destination_l; + error = destination_l.decode_hex (destination->text ().toStdString ()); + if (!error) + { + rai::private_key key; + if (client.client_m.wallet.fetch (account_l, key)) + { + auto balance (client.client_m.ledger.account_balance (account_l)); + if (amount_l.number () <= balance) + { + rai::frontier frontier; + auto error (client.client_m.store.latest_get (account_l, frontier)); + assert (!error); + rai::send_block send; + send.hashables.destination = destination_l; + send.hashables.previous = frontier.hash; + send.hashables.balance = rai::amount (balance - amount_l.number ()); + rai::sign_message (key, account_l, send.hash (), send.signature); + key.clear (); + send.work = client.client_m.ledger.create_work (send); + std::string block_l; + send.serialize_json (block_l); + block->setPlainText (QString (block_l.c_str ())); + status->setStyleSheet ("QLabel { color: black }"); + status->setText ("Created block"); + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Insufficient balance"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Account is not in wallet"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Unable to decode destination"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Unable to decode amount"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Unable to decode account"); + } +} + +void rai_qt::block_creation::create_receive () +{ + rai::block_hash source_l; + auto error (source_l.decode_hex (source->text ().toStdString ())); + if (!error) + { + rai::account source; + rai::amount amount; + rai::account destination; + if (!client.client_m.store.pending_get (source_l, source, amount, destination)) + { + rai::frontier frontier; + auto error (client.client_m.store.latest_get (destination, frontier)); + if (!error) + { + rai::private_key key; + auto error (client.client_m.wallet.fetch (destination, key)); + if (!error) + { + rai::receive_block receive; + receive.hashables.previous = frontier.hash; + receive.hashables.source = source_l; + rai::sign_message (key, destination, receive.hash (), receive.signature); + key.clear (); + receive.work = client.client_m.ledger.create_work (receive); + std::string block_l; + receive.serialize_json (block_l); + block->setPlainText (QString (block_l.c_str ())); + status->setStyleSheet ("QLabel { color: black }"); + status->setText ("Created block"); + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Account is not in wallet"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Account not yet open"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Source block is not pending to receive"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Unable to decode source"); + } +} + +void rai_qt::block_creation::create_change () +{ + rai::account account_l; + auto error (account_l.decode_hex (account->text ().toStdString ())); + if (!error) + { + rai::account representative_l; + error = representative_l.decode_hex (representative->text ().toStdString ()); + if (!error) + { + rai::frontier frontier; + auto error (client.client_m.store.latest_get (account_l, frontier)); + if (!error) + { + rai::private_key key; + auto error (client.client_m.wallet.fetch (account_l, key)); + if (!error) + { + rai::change_block change (representative_l, frontier.hash, key, account_l); + key.clear (); + change.work = client.client_m.ledger.create_work (change); + std::string block_l; + change.serialize_json (block_l); + block->setPlainText (QString (block_l.c_str ())); + status->setStyleSheet ("QLabel { color: black }"); + status->setText ("Created block"); + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Account is not in wallet"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Account not yet open"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Unable to decode representative"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Unable to decode account"); + } +} + +void rai_qt::block_creation::create_open () +{ + rai::block_hash source_l; + auto error (source_l.decode_hex (source->text ().toStdString ())); + if (!error) + { + rai::account representative_l; + error = representative_l.decode_hex (representative->text ().toStdString ()); + if (!error) + { + rai::account source; + rai::amount amount; + rai::account destination; + if (!client.client_m.store.pending_get (source_l, source, amount, destination)) + { + rai::frontier frontier; + auto error (client.client_m.store.latest_get (destination, frontier)); + if (error) + { + rai::private_key key; + auto error (client.client_m.wallet.fetch (destination, key)); + if (!error) + { + rai::open_block open; + open.hashables.source = source_l; + open.hashables.representative = representative_l; + rai::sign_message (key, destination, open.hash (), open.signature); + key.clear (); + open.work = client.client_m.ledger.create_work (open); + std::string block_l; + open.serialize_json (block_l); + block->setPlainText (QString (block_l.c_str ())); + status->setStyleSheet ("QLabel { color: black }"); + status->setText ("Created block"); + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Account is not in wallet"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Account already open"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Source block is not pending to receive"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Unable to decode representative"); + } + } + else + { + status->setStyleSheet ("QLabel { color: red }"); + status->setText ("Unable to decode source"); + } } \ No newline at end of file diff --git a/rai/qt/qt.hpp b/rai/qt/qt.hpp index 52bbacb5..01c66c9c 100644 --- a/rai/qt/qt.hpp +++ b/rai/qt/qt.hpp @@ -103,6 +103,10 @@ namespace rai_qt { void activate_receive (); void activate_change (); void activate_open (); + void create_send (); + void create_receive (); + void create_change (); + void create_open (); QWidget * window; QVBoxLayout * layout; QButtonGroup * group; @@ -121,6 +125,9 @@ namespace rai_qt { QLineEdit * destination; QLabel * representative_label; QLineEdit * representative; + QPlainTextEdit * block; + QLabel * status; + QPushButton * create; QPushButton * back; rai_qt::client & client; }; diff --git a/rai/secure.cpp b/rai/secure.cpp index 3060c74c..cf96b2e7 100644 --- a/rai/secure.cpp +++ b/rai/secure.cpp @@ -623,22 +623,33 @@ void rai::uint256_union::encode_hex (std::string & text) const bool rai::uint256_union::decode_hex (std::string const & text) { - auto result (text.size () > 64); - if (!result) + auto result (false); + if (!text.empty ()) { - std::stringstream stream (text); - stream << std::hex << std::noshowbase; - rai::uint256_t number_l; - try + if (text.size () <= 64) { - stream >> number_l; - *this = number_l; + std::stringstream stream (text); + stream << std::hex << std::noshowbase; + rai::uint256_t number_l; + try + { + stream >> number_l; + *this = number_l; + } + catch (std::runtime_error &) + { + result = true; + } } - catch (std::runtime_error &) + else { result = true; } } + else + { + result = true; + } return result; } @@ -1207,6 +1218,12 @@ work (work_a) rai::sign_message (prv_a, pub_a, hash (), signature); } +rai::change_block::change_block (rai::account const & representative_a, rai::block_hash const & previous_a, rai::private_key const & prv_a, rai::public_key const & pub_a) : +hashables (representative_a, previous_a) +{ + rai::sign_message (prv_a, pub_a, hash (), signature); +} + rai::change_block::change_block (bool & error_a, rai::stream & stream_a) : hashables (error_a, stream_a) { diff --git a/rai/secure.hpp b/rai/secure.hpp index 94b90c5f..b2063df5 100644 --- a/rai/secure.hpp +++ b/rai/secure.hpp @@ -289,6 +289,7 @@ namespace rai { public: change_block (rai::account const &, rai::block_hash const &, uint64_t, rai::private_key const &, rai::public_key const &); + change_block (rai::account const &, rai::block_hash const &, rai::private_key const &, rai::public_key const &); change_block (bool &, rai::stream &); change_block (bool &, boost::property_tree::ptree const &); using rai::block::hash;