diff --git a/README.md b/README.md index 313b393..8692a35 100644 --- a/README.md +++ b/README.md @@ -16,52 +16,58 @@ Windows 10 with Visual Studio 2019 for build environment and vcpkg for library m ## Quick start -- Run a miner instance +- Run a miner node ``` - $ tiny-sandbox.exe --port 9901 --wallet miner.dat --mine + $ tiny-sandbox.exe --port 9901 --node_type miner --wallet miner.dat - [ 03:04:45 ] [ tc ] Generating new wallet miner.dat - [ 03:04:45 ] [ tc ] Your address is 172eJPtmt5wMq71bnT1fS55FYLHw1syhWB - [ 03:04:47 ] [ tc ] Load chain failed, starting from genesis + [ 17:17:23 ] [ tc ] Generating new wallet miner.dat + [ 17:17:25 ] [ tc ] Your address is 172eJPtmt5wMq71bnT1fS55FYLHw1syhWB + [ 17:17:26 ] [ tc ] Load chain failed, starting from genesis ``` - Wait for a few blocks to go by ``` - [ 03:04:47 ] [ tc ] Block found => 1 s, 726 KH/s, 0000001ec4d7580bf8b0459af362857d148112c8a38e5b039ca423558bf28ca3, 13835058055282350115 - [ 03:04:47 ] [ tc ] Connecting block 0000001ec4d7580bf8b0459af362857d148112c8a38e5b039ca423558bf28ca3 to chain 0 - [ 03:04:47 ] [ tc ] Adding TxOutPoint f353379e1dce17f3964bd1e673eb268faabaf8e6a24cc866f46389f54d920b25 to UTXO map - [ 03:04:47 ] [ tc ] Block accepted with height 1 and txs 1 - [ 03:04:47 ] [ tc ] Saving chain with 2 blocks + [ 17:17:27 ] [ tc ] Block found => 2 s, 835 KH/s, 000000fe05062373c95152a779915f25d75cfc519395a120d3bba466b88b9bc5, 422750 + [ 17:17:27 ] [ tc ] Connecting block 000000fe05062373c95152a779915f25d75cfc519395a120d3bba466b88b9bc5 to chain 0 + [ 17:17:27 ] [ tc ] Adding TxOutPoint f353379e1dce17f3964bd1e673eb268faabaf8e6a24cc866f46389f54d920b25 to UTXO map + [ 17:17:27 ] [ tc ] Block accepted with height 1 and txs 1 + [ 17:17:27 ] [ tc ] Saving chain with 2 blocks ... ``` -- Generate an empty wallet +- Run a wallet node ``` - $ tiny-sandbox.exe --port 9902 --wallet receiver.dat --balance + $ tiny-sandbox.exe --port 9902 --node_type wallet --wallet miner.dat - [ 03:04:53 ] [ tc ] Generating new wallet receiver.dat - [ 03:04:53 ] [ tc ] Your address is 16KHYopvjuY3mVLtEPHDLTzemWbPV6agoi - [ 03:04:55 ] [ tc ] Address 16KHYopvjuY3mVLtEPHDLTzemWbPV6agoi holds 0 coins + [ 17:17:31 ] [ tc ] Your address is 172eJPtmt5wMq71bnT1fS55FYLHw1syhWB + ``` +- Generate an empty wallet + ``` + $ address receiver.dat + + [ 17:21:06 ] [ tc ] receiver.dat belongs to address is 16KHYopvjuY3mVLtEPHDLTzemWbPV6agoi ``` - Send coins from miner wallet to empty wallet ``` - $ tiny-sandbox.exe --port 9902 --wallet miner.dat --send_address 16KHYopvjuY3mVLtEPHDLTzemWbPV6agoi --send_value 50 + $ send 16KHYopvjuY3mVLtEPHDLTzemWbPV6agoi 50 - [ 03:05:27 ] [ tc ] Built transaction bc74ea19c1eb5fd5d5571d2926f7f247e8c54844085aeb4902dddd3c587d934b, broadcasting + [ 17:21:52 ] [ tc ] Built transaction df02039631785fe23eb047bf8222f6cb89e767c6ee9e56c2e06d14ac0624c843, broadcasting ``` - Wait for transaction to get mined in a block ``` - [ 03:05:33 ] [ tc ] Added transaction bc74ea19c1eb5fd5d5571d2926f7f247e8c54844085aeb4902dddd3c587d934b to block 3d202ec5dda4e5bad64c52d29cb03d9342c9eac9062503613665fb606da15e51 - [ 03:05:50 ] [ tc ] Block found => 17 s, 1177 KH/s, 00000079f33dc7c0b50d51a425b8eae0c3bf406f71094b33a016aee05fdf26c7, 13835058055287314157 - [ 03:05:50 ] [ tc ] Connecting block 00000079f33dc7c0b50d51a425b8eae0c3bf406f71094b33a016aee05fdf26c7 to chain 0 - [ 03:05:50 ] [ tc ] Adding TxOutPoint e08baa6462a7a406879248f914cf8bb5a1758a73129f07f82aea7209769a754e to UTXO map - [ 03:05:50 ] [ tc ] Adding TxOutPoint bc74ea19c1eb5fd5d5571d2926f7f247e8c54844085aeb4902dddd3c587d934b to UTXO map - [ 03:05:50 ] [ tc ] Block accepted with height 8 and txs 2 - [ 03:05:50 ] [ tc ] Saving chain with 9 blocks + ... + [ 17:22:03 ] [ tc ] Added transaction df02039631785fe23eb047bf8222f6cb89e767c6ee9e56c2e06d14ac0624c843 to block 02f30dcb19d2fdda6a2e2dd556aacb22197f0d66170c37d5bc3bc479a7cd583f + [ 17:22:28 ] [ tc ] Block found => 25 s, 1146 KH/s, 0000009d480d7d6fb74541c35553a4e030461d3ee890312c152d209f12fa9dfd, 9223372036861901087 + [ 17:22:28 ] [ tc ] Connecting block 0000009d480d7d6fb74541c35553a4e030461d3ee890312c152d209f12fa9dfd to chain 0 + [ 17:22:28 ] [ tc ] Adding TxOutPoint 1972eeeea6949504e763fd0c22de36091ffddb734b546db3336c78d169c1a294 to UTXO map + [ 17:22:28 ] [ tc ] Adding TxOutPoint df02039631785fe23eb047bf8222f6cb89e767c6ee9e56c2e06d14ac0624c843 to UTXO map + [ 17:22:28 ] [ tc ] Block accepted with height 23 and txs 2 + [ 17:22:28 ] [ tc ] Saving chain with 24 blocks + ... ``` -- Check balance of reciever wallet +- Check balance of receiver wallet ``` - $ tiny-sandbox.exe --port 9902 --wallet receiver.dat --balance - - [ 03:05:54 ] [ tc ] Address 16KHYopvjuY3mVLtEPHDLTzemWbPV6agoi holds 50 coins + $ balance 16KHYopvjuY3mVLtEPHDLTzemWbPV6agoi + + [ 17:23:41 ] [ tc ] Address 16KHYopvjuY3mVLtEPHDLTzemWbPV6agoi holds 50 coins ``` ## TODO @@ -71,4 +77,5 @@ Windows 10 with Visual Studio 2019 for build environment and vcpkg for library m - Mempool sorting by fee - Orphan blocks - Chainwork -- Peer discovery \ No newline at end of file +- Peer discovery +- Full node \ No newline at end of file diff --git a/tiny-lib/Connection.hpp b/tiny-lib/Connection.hpp index ef0c9d0..2e79ff8 100644 --- a/tiny-lib/Connection.hpp +++ b/tiny-lib/Connection.hpp @@ -14,5 +14,5 @@ class Connection std::mutex WriteMutex; - NodeType NodeType = Unspecified; + NodeType NodeType = NodeType::Unspecified; }; diff --git a/tiny-lib/Enums.hpp b/tiny-lib/Enums.hpp index d68c503..e3aa13d 100644 --- a/tiny-lib/Enums.hpp +++ b/tiny-lib/Enums.hpp @@ -9,12 +9,12 @@ enum class TxStatus : uint8_t NotFound }; -enum NodeType : uint8_t +enum class NodeType : uint8_t { Unspecified = 0, Miner = 1, Wallet = 2, - Full = Miner | Wallet //TODO: implement full node + Full = Miner | Wallet }; using NodeTypeType = std::underlying_type::type; @@ -23,3 +23,13 @@ inline NodeType operator|(NodeType a, NodeType b) { return static_cast(static_cast(a) | static_cast(b)); } + +inline NodeType& operator|=(NodeType& a, NodeType b) +{ + return reinterpret_cast(reinterpret_cast(a) |= static_cast(b)); +} + +inline bool operator&(NodeType a, NodeType b) +{ + return static_cast(a) & static_cast(b); +} diff --git a/tiny-lib/NetClient.cpp b/tiny-lib/NetClient.cpp index 3cb5d39..176ce93 100644 --- a/tiny-lib/NetClient.cpp +++ b/tiny-lib/NetClient.cpp @@ -58,7 +58,8 @@ void NetClient::Stop() ConnectionsMutex.unlock(); IO_Service.stop(); - IO_Thread.join(); + if (IO_Thread.joinable()) + IO_Thread.join(); ConnectionsMutex.lock(); MinerConnections.clear(); @@ -361,7 +362,7 @@ void NetClient::RemoveConnection(std::shared_ptr& con) soc.shutdown(boost::asio::socket_base::shutdown_both); soc.close(); } - if (con->NodeType & Miner) + if (con->NodeType & NodeType::Miner) { const auto vec_it2 = std::ranges::find_if(MinerConnections, [&con](const std::shared_ptr& o) diff --git a/tiny-lib/NodeConfig.cpp b/tiny-lib/NodeConfig.cpp index e0f6cdd..fdff113 100644 --- a/tiny-lib/NodeConfig.cpp +++ b/tiny-lib/NodeConfig.cpp @@ -1,4 +1,4 @@ #include "pch.hpp" #include "NodeConfig.hpp" -NodeType NodeConfig::Type = Unspecified; +NodeType NodeConfig::Type = NodeType::Unspecified; diff --git a/tiny-lib/PeerHelloMsg.cpp b/tiny-lib/PeerHelloMsg.cpp index f6dcd5a..1b5ef4f 100644 --- a/tiny-lib/PeerHelloMsg.cpp +++ b/tiny-lib/PeerHelloMsg.cpp @@ -9,7 +9,7 @@ void PeerHelloMsg::Handle(std::shared_ptr& con) { con->NodeType = NodeType; - if (con->NodeType & Miner) + if (con->NodeType & NodeType::Miner) { std::lock_guard lock(NetClient::ConnectionsMutex); diff --git a/tiny-lib/Wallet.cpp b/tiny-lib/Wallet.cpp index 78a580a..d4223dd 100644 --- a/tiny-lib/Wallet.cpp +++ b/tiny-lib/Wallet.cpp @@ -48,10 +48,8 @@ std::string Wallet::PubKeyToAddress(const std::vector& pubKey) return PubKeyHashVersion + Base58::Encode(ripe); } -std::tuple, std::vector, std::string> Wallet::InitWallet(const std::string& walletPath) +std::tuple, std::vector, std::string> Wallet::GetWallet(const std::string& walletPath) { - WalletPath = walletPath; - std::vector privKey; std::vector pubKey; std::string address; @@ -77,6 +75,22 @@ std::tuple, std::vector, std::string> Wallet::Init wallet_out.close(); } + return {privKey, pubKey, address}; +} + +void Wallet::PrintWalletAddress(const std::string& walletPath) +{ + const auto [privKey, pubKey, address] = GetWallet(walletPath); + + LOG_INFO("{} belongs to address is {}", walletPath, address); +} + +std::tuple, std::vector, std::string> Wallet::InitWallet(const std::string& walletPath) +{ + WalletPath = walletPath; + + const auto [privKey, pubKey, address] = GetWallet(WalletPath); + static bool printedAddress = false; if (!printedAddress) { diff --git a/tiny-lib/Wallet.hpp b/tiny-lib/Wallet.hpp index a64da1d..a8715b4 100644 --- a/tiny-lib/Wallet.hpp +++ b/tiny-lib/Wallet.hpp @@ -21,6 +21,8 @@ class Wallet public: static std::string PubKeyToAddress(const std::vector& pubKey); + static std::tuple, std::vector, std::string> GetWallet(const std::string& walletPath); + static void PrintWalletAddress(const std::string& walletPath); static std::tuple, std::vector, std::string> InitWallet(const std::string& walletPath); static std::tuple, std::vector, std::string> InitWallet(); diff --git a/tiny-sandbox/main.cpp b/tiny-sandbox/main.cpp index 1d87423..f0809a5 100644 --- a/tiny-sandbox/main.cpp +++ b/tiny-sandbox/main.cpp @@ -1,15 +1,17 @@ #include #include #include +#include #include #include #include +#include #include "../tiny-lib/Log.hpp" #include "../tiny-lib/NetClient.hpp" +#include "../tiny-lib/NodeConfig.hpp" #include "../tiny-lib/PoW.hpp" #include "../tiny-lib/Wallet.hpp" -#include "../tiny-lib/NodeConfig.hpp" namespace po = boost::program_options; @@ -18,7 +20,7 @@ void atexit_handler() Log::StopLog(); } -int main(int ac, char** av) +int main(int argc, char** argv) { Log::StartLog(); if (std::atexit(atexit_handler) != 0) @@ -26,34 +28,45 @@ int main(int ac, char** av) po::options_description desc("allowed options"); desc.add_options() - ("wallet", po::value(), "path to wallet") - ("mine", "sets up a mining node") + ("node_type", po::value(), "specify node type") ("port", po::value(), "port to listen on network connections") - ("balance", "shows balance for this wallet") - ("send_address", po::value(), "sends coins to address") - ("send_value", po::value(), "sends coins to address") - ("tx_status", po::value(), "shows status for transaction"); + ("wallet", po::value(), "path to wallet"); po::variables_map vm; - po::store(po::parse_command_line(ac, av, desc), vm); + po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if (!vm.contains("port")) { LOG_ERROR("A port for network connection must be specified"); - Log::StopLog(); + return EXIT_FAILURE; + } + + if (!vm.contains("node_type")) + { + LOG_ERROR("Node type must be specified"); return EXIT_FAILURE; } - if (vm.contains("mine")) + if (vm["node_type"].as() == "miner") + { + NodeConfig::Type = NodeType::Miner; + } + else if (vm["node_type"].as() == "wallet") { - NodeConfig::Type = NodeConfig::Type | Miner; + NodeConfig::Type = NodeType::Wallet; + } + else if (vm["node_type"].as() == "full") + { + NodeConfig::Type = NodeType::Full; //TODO: implement full node } else { - NodeConfig::Type = NodeConfig::Type | Wallet; + LOG_ERROR("Invalid node type"); + + return EXIT_FAILURE; } const auto [privKey, pubKey, address] = vm.contains("wallet") @@ -76,23 +89,65 @@ int main(int ac, char** av) for (const auto& pendingConnection : pendingConnections) pendingConnection.wait(); - if (NodeConfig::Type & Miner) + if (NodeConfig::Type == NodeType::Miner) { PoW::MineForever(); } else { - if (vm.contains("balance")) - { - Wallet::PrintBalance(address); - } - else if (vm.contains("tx_status")) - { - Wallet::PrintTxStatus(vm["tx_status"].as()); - } - else if (vm.contains("send_address") && vm.contains("send_value")) + std::string wallet_address = "address "; + std::string balance_address = "balance "; + std::string balance_own = "balance"; + std::string send = "send "; + std::string tx_status = "tx_status "; + while (true) { - Wallet::SendValue(vm["send_value"].as(), vm["send_address"].as(), privKey); + std::string command; + std::getline(std::cin, command); + + if (command == "exit" || command == "quit") + { + break; + } + + if (command.starts_with(wallet_address)) + { + command.erase(0, wallet_address.length()); + Wallet::PrintWalletAddress(command); + } + else if (command.starts_with(balance_address)) + { + command.erase(0, balance_address.length()); + Wallet::PrintBalance(command); + } + else if (command.starts_with(balance_own)) + { + Wallet::PrintBalance(address); + } + else if (command.starts_with(send)) + { + command.erase(0, send.length()); + std::vector send_args; + boost::split(send_args, command, boost::is_any_of(" ")); + if (send_args.size() != 2) + { + LOG_ERROR("Send command requires 2 arguments, receiver address and send value"); + + continue; + } + const auto& send_address = send_args[0]; + const auto& send_value = send_args[1]; + Wallet::SendValue(std::stoull(send_value), send_address, privKey); + } + else if (command.starts_with(tx_status)) + { + command.erase(0, tx_status.length()); + Wallet::PrintTxStatus(command); + } + else + { + LOG_ERROR("Unknown command"); + } } }