Skip to content

Commit

Permalink
Merge pull request #10 from ParsiCoin/development
Browse files Browse the repository at this point in the history
v3.0.1
  • Loading branch information
ParsiCoin committed Apr 17, 2019
2 parents f40e99f + b3fdefb commit 56d0394
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 6 deletions.
3 changes: 3 additions & 0 deletions src/CryptoNoteConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ const std::initializer_list<CheckpointData> CHECKPOINTS = {
{3, "90e8374d29bc23be19ee69cf5b97dc9551a5d5d8385de6a6443e196c102937d2" },
{10, "15d2d574f2b037bce7dfb0e995ade99f2e618399c42a7acf7326b511377db1e4" },
{100, "2b8cf73215920ce9e8ac6f0fe0106ccb39451e9423da055216e97fd6781003f8" },
{1000, "8975877f6ab04ba985ef73fba5045cade3d6d437e29a6771b1da10f57b4b2aca" },
{10000, "48fd53db9bb4885fd530072528e582f7ae652b1cd62e66c57c47ac79d5ec738c" },
{20000, "0a9908210b03805da6b60c456692b5c8a42382fbef2e2fa8eea317d0bb0aad6c" },
};

} // CryptoNote
Expand Down
12 changes: 12 additions & 0 deletions src/CryptoNoteCore/Account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ Crypto::SecretKey AccountBase::generate_key(const Crypto::SecretKey& recovery_ke
return first;
}

void AccountBase::generateViewFromSpend(Crypto::SecretKey &spend, Crypto::SecretKey &viewSecret, Crypto::PublicKey &viewPublic) {
Crypto::SecretKey viewKeySeed;
keccak((uint8_t *)&spend, sizeof(spend), (uint8_t *)&viewKeySeed, sizeof(viewKeySeed));

Crypto::generate_deterministic_keys(viewPublic, viewSecret, viewKeySeed);
}

void AccountBase::generateViewFromSpend(Crypto::SecretKey &spend, Crypto::SecretKey &viewSecret) {
/* If we don't need the pub key */
Crypto::PublicKey unused_dummy_variable;
generateViewFromSpend(spend, viewSecret, unused_dummy_variable);
}

//-----------------------------------------------------------------
const AccountKeys &AccountBase::getAccountKeys() const {
Expand Down
3 changes: 3 additions & 0 deletions src/CryptoNoteCore/Account.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ namespace CryptoNote {
void generate();
void generateDeterministic();
Crypto::SecretKey generate_key(const Crypto::SecretKey& recovery_key = Crypto::SecretKey(), bool recover = false, bool two_random = false);

static void generateViewFromSpend(Crypto::SecretKey&, Crypto::SecretKey&, Crypto::PublicKey&);
static void generateViewFromSpend(Crypto::SecretKey&, Crypto::SecretKey&);

const AccountKeys& getAccountKeys() const;
void setAccountKeys(const AccountKeys& keys);
Expand Down
10 changes: 10 additions & 0 deletions src/PaymentGate/PaymentServiceJsonRpcMessages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ void GetViewKey::Response::serialize(CryptoNote::ISerializer& serializer) {
serializer(viewSecretKey, "viewSecretKey");
}

void GetMnemonicSeed::Request::serialize(CryptoNote::ISerializer& serializer) {
if (!serializer(address, "address")) {
throw RequestSerializationError();
}
}

void GetMnemonicSeed::Response::serialize(CryptoNote::ISerializer& serializer) {
serializer(mnemonicSeed, "mnemonicSeed");
}

void GetStatus::Request::serialize(CryptoNote::ISerializer& serializer) {
}

Expand Down
14 changes: 14 additions & 0 deletions src/PaymentGate/PaymentServiceJsonRpcMessages.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ struct GetViewKey {
};
};

struct GetMnemonicSeed {
struct Request {
std::string address;

void serialize(CryptoNote::ISerializer& serializer);
};

struct Response {
std::string mnemonicSeed;

void serialize(CryptoNote::ISerializer& serializer);
};
};

struct GetStatus {
struct Request {
void serialize(CryptoNote::ISerializer& serializer);
Expand Down
5 changes: 5 additions & 0 deletions src/PaymentGate/PaymentServiceJsonRpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ PaymentServiceJsonRpcServer::PaymentServiceJsonRpcServer(System::Dispatcher& sys
handlers.emplace("deleteDelayedTransaction", jsonHandler<DeleteDelayedTransaction::Request, DeleteDelayedTransaction::Response>(std::bind(&PaymentServiceJsonRpcServer::handleDeleteDelayedTransaction, this, std::placeholders::_1, std::placeholders::_2)));
handlers.emplace("sendDelayedTransaction", jsonHandler<SendDelayedTransaction::Request, SendDelayedTransaction::Response>(std::bind(&PaymentServiceJsonRpcServer::handleSendDelayedTransaction, this, std::placeholders::_1, std::placeholders::_2)));
handlers.emplace("getViewKey", jsonHandler<GetViewKey::Request, GetViewKey::Response>(std::bind(&PaymentServiceJsonRpcServer::handleGetViewKey, this, std::placeholders::_1, std::placeholders::_2)));
handlers.emplace("getMnemonicSeed", jsonHandler<GetMnemonicSeed::Request, GetMnemonicSeed::Response>(std::bind(&PaymentServiceJsonRpcServer::handleGetMnemonicSeed, this, std::placeholders::_1, std::placeholders::_2)));
handlers.emplace("getStatus", jsonHandler<GetStatus::Request, GetStatus::Response>(std::bind(&PaymentServiceJsonRpcServer::handleGetStatus, this, std::placeholders::_1, std::placeholders::_2)));
handlers.emplace("getAddresses", jsonHandler<GetAddresses::Request, GetAddresses::Response>(std::bind(&PaymentServiceJsonRpcServer::handleGetAddresses, this, std::placeholders::_1, std::placeholders::_2)));
handlers.emplace("sendFusionTransaction", jsonHandler<SendFusionTransaction::Request, SendFusionTransaction::Response>(std::bind(&PaymentServiceJsonRpcServer::handleSendFusionTransaction, this, std::placeholders::_1, std::placeholders::_2)));
Expand Down Expand Up @@ -199,6 +200,10 @@ std::error_code PaymentServiceJsonRpcServer::handleGetViewKey(const GetViewKey::
return service.getViewKey(response.viewSecretKey);
}

std::error_code PaymentServiceJsonRpcServer::handleGetMnemonicSeed(const GetMnemonicSeed::Request& request, GetMnemonicSeed::Response& response) {
return service.getMnemonicSeed(request.address, response.mnemonicSeed);
}

std::error_code PaymentServiceJsonRpcServer::handleGetStatus(const GetStatus::Request& request, GetStatus::Response& response) {
response.version = PROJECT_VERSION_LONG;
return service.getStatus(response.blockCount, response.knownBlockCount, response.localDaemonBlockCount, response.lastBlockHash, response.peerCount, response.minimalFee);
Expand Down
1 change: 1 addition & 0 deletions src/PaymentGate/PaymentServiceJsonRpcServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class PaymentServiceJsonRpcServer : public CryptoNote::JsonRpcServer {
std::error_code handleDeleteDelayedTransaction(const DeleteDelayedTransaction::Request& request, DeleteDelayedTransaction::Response& response);
std::error_code handleSendDelayedTransaction(const SendDelayedTransaction::Request& request, SendDelayedTransaction::Response& response);
std::error_code handleGetViewKey(const GetViewKey::Request& request, GetViewKey::Response& response);
std::error_code handleGetMnemonicSeed(const GetMnemonicSeed::Request& request, GetMnemonicSeed::Response& response);
std::error_code handleGetStatus(const GetStatus::Request& request, GetStatus::Response& response);
std::error_code handleGetAddresses(const GetAddresses::Request& request, GetAddresses::Response& response);
std::error_code handleValidateAddress(const ValidateAddress::Request& request, ValidateAddress::Response& response);
Expand Down
100 changes: 97 additions & 3 deletions src/PaymentGate/WalletService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "CryptoNoteCore/CryptoNoteFormatUtils.h"
#include "CryptoNoteCore/CryptoNoteBasicImpl.h"
#include "CryptoNoteCore/TransactionExtra.h"
#include "CryptoNoteCore/Account.h"

#include <System/EventLock.h>

Expand All @@ -48,6 +49,7 @@
#include "Wallet/WalletUtils.h"
#include "WalletServiceErrorCategory.h"
#include "ITransfersContainer.h"
#include "mnemonics/electrum-words.cpp"

using namespace CryptoNote;

Expand Down Expand Up @@ -331,12 +333,75 @@ void generateNewWallet(const CryptoNote::Currency& currency, const WalletConfigu
CryptoNote::IWallet* wallet = new CryptoNote::WalletGreen(dispatcher, currency, *nodeStub, logger);
std::unique_ptr<CryptoNote::IWallet> walletGuard(wallet);

log(Logging::INFO, Logging::BRIGHT_WHITE) << "Generating new wallet";
std::string address;

if (conf.secretSpendKey.empty() && conf.secretViewKey.empty() && conf.mnemonicSeed.empty())
{
if (conf.generateDeterministic) {
log(Logging::INFO, Logging::BRIGHT_WHITE) << "Generating new deterministic wallet";

Crypto::SecretKey private_view_key;
CryptoNote::KeyPair spendKey;

Crypto::generate_keys(spendKey.publicKey, spendKey.secretKey);
CryptoNote::AccountBase::generateViewFromSpend(spendKey.secretKey, private_view_key);

wallet->initializeWithViewKey(conf.walletFile, conf.walletPassword, private_view_key);
address = wallet->createAddress(spendKey.secretKey);

log(Logging::INFO, Logging::BRIGHT_WHITE) << "New deterministic wallet is generated. Address: " << address;
}
else {
log(Logging::INFO, Logging::BRIGHT_WHITE) << "Generating new non-deterministic wallet";
wallet->initialize(conf.walletFile, conf.walletPassword);
auto address = wallet->createAddress();
address = wallet->createAddress();
log(Logging::INFO, Logging::BRIGHT_WHITE) << "New non-deterministic wallet is generated. Address: " << address;
}
}
else if (!conf.mnemonicSeed.empty()) {
log(Logging::INFO, Logging::BRIGHT_WHITE) << "Importing wallet from mnemonic seed";

Crypto::SecretKey private_spend_key;
Crypto::SecretKey private_view_key;

std::string languageName;
if (!Crypto::ElectrumWords::words_to_bytes(conf.mnemonicSeed, private_spend_key, languageName))
{
log(Logging::ERROR, Logging::BRIGHT_RED) << "Electrum-style word list failed verification.";
return;
}

log(Logging::INFO, Logging::BRIGHT_WHITE) << "New wallet is generated. Address: " << address;
CryptoNote::AccountBase::generateViewFromSpend(private_spend_key, private_view_key);
wallet->initializeWithViewKey(conf.walletFile, conf.walletPassword, private_view_key);
address = wallet->createAddress(private_spend_key);
log(Logging::INFO, Logging::BRIGHT_WHITE) << "Imported wallet successfully.";
}
else {
if (conf.secretSpendKey.empty() || conf.secretViewKey.empty())
{
log(Logging::ERROR, Logging::BRIGHT_RED) << "Need both secret spend key and secret view key.";
return;
} else {
log(Logging::INFO, Logging::BRIGHT_WHITE) << "Importing wallet from keys";
Crypto::Hash private_spend_key_hash;
Crypto::Hash private_view_key_hash;
size_t size;
if (!Common::fromHex(conf.secretSpendKey, &private_spend_key_hash, sizeof(private_spend_key_hash), size) || size != sizeof(private_spend_key_hash)) {
log(Logging::ERROR, Logging::BRIGHT_RED) << "Invalid spend key";
return;
}
if (!Common::fromHex(conf.secretViewKey, &private_view_key_hash, sizeof(private_view_key_hash), size) || size != sizeof(private_spend_key_hash)) {
log(Logging::ERROR, Logging::BRIGHT_RED) << "Invalid view key";
return;
}
Crypto::SecretKey private_spend_key = *(struct Crypto::SecretKey *) &private_spend_key_hash;
Crypto::SecretKey private_view_key = *(struct Crypto::SecretKey *) &private_view_key_hash;

wallet->initializeWithViewKey(conf.walletFile, conf.walletPassword, private_view_key);
address = wallet->createAddress(private_spend_key);
log(Logging::INFO, Logging::BRIGHT_WHITE) << "Wallet imported successfully.";
}
}

wallet->save(CryptoNote::WalletSaveLevel::SAVE_KEYS_ONLY);
log(Logging::INFO, Logging::BRIGHT_WHITE) << "Wallet is saved";
Expand Down Expand Up @@ -688,6 +753,35 @@ std::error_code WalletService::getViewKey(std::string& viewSecretKey) {
return std::error_code();
}

std::error_code WalletService::getMnemonicSeed(const std::string& address, std::string& mnemonicSeed) {
try {
System::EventLock lk(readyEvent);
CryptoNote::KeyPair key = wallet.getAddressSpendKey(address);
CryptoNote::KeyPair viewKey = wallet.getViewKey();

Crypto::SecretKey deterministic_private_view_key;

CryptoNote::AccountBase::generateViewFromSpend(key.secretKey, deterministic_private_view_key);

bool deterministic_private_keys = deterministic_private_view_key == viewKey.secretKey;

if (deterministic_private_keys) {
Crypto::ElectrumWords::bytes_to_words(key.secretKey, mnemonicSeed, "English");
} else {
/* Have to be able to derive view key from spend key to create a mnemonic
seed, due to being able to generate multiple addresses we can't do
this in walletd as the default */
logger(Logging::WARNING, Logging::BRIGHT_YELLOW) << "Your private keys are not deterministic and so a mnemonic seed cannot be generated!";
return make_error_code(CryptoNote::error::WalletServiceErrorCode::KEYS_NOT_DETERMINISTIC);
}
} catch (std::system_error& x) {
logger(Logging::WARNING, Logging::BRIGHT_YELLOW) << "Error while getting mnemonic seed: " << x.what();
return x.code();
}

return std::error_code();
}

std::error_code WalletService::getTransactionHashes(const std::vector<std::string>& addresses, const std::string& blockHashString,
uint32_t blockCount, const std::string& paymentId, std::vector<TransactionHashesInBlockRpcInfo>& transactionHashes) {
try {
Expand Down
5 changes: 5 additions & 0 deletions src/PaymentGate/WalletService.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ namespace PaymentService {
struct WalletConfiguration {
std::string walletFile;
std::string walletPassword;
std::string secretViewKey;
std::string secretSpendKey;
std::string mnemonicSeed;
bool generateDeterministic;
};

void generateNewWallet(const CryptoNote::Currency& currency, const WalletConfiguration& conf, Logging::ILogger& logger, System::Dispatcher& dispatcher);
Expand Down Expand Up @@ -73,6 +77,7 @@ class WalletService {
std::error_code getBalance(uint64_t& availableBalance, uint64_t& lockedAmount);
std::error_code getBlockHashes(uint32_t firstBlockIndex, uint32_t blockCount, std::vector<std::string>& blockHashes);
std::error_code getViewKey(std::string& viewSecretKey);
std::error_code getMnemonicSeed(const std::string& address, std::string& mnemonicSeed);
std::error_code getTransactionHashes(const std::vector<std::string>& addresses, const std::string& blockHash,
uint32_t blockCount, const std::string& paymentId, std::vector<TransactionHashesInBlockRpcInfo>& transactionHashes);
std::error_code getTransactionHashes(const std::vector<std::string>& addresses, uint32_t firstBlockIndex,
Expand Down
4 changes: 3 additions & 1 deletion src/PaymentGate/WalletServiceErrorCategory.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ enum class WalletServiceErrorCode {
WRONG_PAYMENT_ID_FORMAT,
WRONG_HASH_FORMAT,
OBJECT_NOT_FOUND,
DUPLICATE_KEY
DUPLICATE_KEY,
KEYS_NOT_DETERMINISTIC
};

// custom category:
Expand All @@ -55,6 +56,7 @@ class WalletServiceErrorCategory : public std::error_category {
case WalletServiceErrorCode::WRONG_HASH_FORMAT: return "Wrong block id format";
case WalletServiceErrorCode::OBJECT_NOT_FOUND: return "Requested object not found";
case WalletServiceErrorCode::DUPLICATE_KEY: return "Duplicate key";
case WalletServiceErrorCode::KEYS_NOT_DETERMINISTIC: return "Keys are non-deterministic";
default: return "Unknown error";
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/PaymentGateService/PaymentGateService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,11 @@ bool PaymentGateService::init(int argc, char** argv) {
WalletConfiguration PaymentGateService::getWalletConfig() const {
return WalletConfiguration{
config.gateConfiguration.containerFile,
config.gateConfiguration.containerPassword
config.gateConfiguration.containerPassword,
config.gateConfiguration.secretViewKey,
config.gateConfiguration.secretSpendKey,
config.gateConfiguration.mnemonicSeed,
config.gateConfiguration.generateDeterministic
};
}

Expand Down
36 changes: 36 additions & 0 deletions src/PaymentGateService/PaymentServiceConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace PaymentService {

Configuration::Configuration() {
generateNewContainer = false;
generateDeterministic = false;
daemonize = false;
registerService = false;
unregisterService = false;
Expand All @@ -44,6 +45,9 @@ Configuration::Configuration() {
bindPort = 0;
m_rpcUser = "";
m_rpcPassword = "";
secretViewKey = "";
secretSpendKey = "";
mnemonicSeed = "";
}

void Configuration::initOptions(boost::program_options::options_description& desc) {
Expand All @@ -55,6 +59,10 @@ void Configuration::initOptions(boost::program_options::options_description& des
("container-file,w", po::value<std::string>(), "container file")
("container-password,p", po::value<std::string>(), "container password")
("generate-container,g", "generate new container file with one wallet and exit")
("view-key", po::value<std::string>(), "generate a container with this secret key view")
("spend-key", po::value<std::string>(), "generate a container with this secret spend key")
("mnemonic-seed", po::value<std::string>(), "generate a container with this mnemonic seed")
("deterministic", "generate a container with deterministic keys. View key is generated from spend key of the first address")
("daemon,d", "run as daemon in Unix or as service in Windows")
#ifdef _WIN32
("register-service", "register service and exit (Windows only)")
Expand Down Expand Up @@ -133,6 +141,34 @@ void Configuration::init(const boost::program_options::variables_map& options) {
generateNewContainer = true;
}

if (options.count("deterministic") != 0) {
generateDeterministic = true;
}

if (options.count("view-key") != 0) {
if (!generateNewContainer) {
throw ConfigurationError("generate-container parameter is required");
}
secretViewKey = options["view-key"].as<std::string>();
}

if (options.count("spend-key") != 0) {
if (!generateNewContainer) {
throw ConfigurationError("generate-container parameter is required");
}
secretSpendKey = options["spend-key"].as<std::string>();
}

if (options.count("mnemonic-seed") != 0) {
if (!generateNewContainer) {
throw ConfigurationError("generate-container parameter is required");
}
else if (options.count("spend-key") != 0 || options.count("view-key") != 0) {
throw ConfigurationError("Cannot specify import via both mnemonic seed and private keys");
}
mnemonicSeed = options["mnemonic-seed"].as<std::string>();
}

if (options.count("address") != 0) {
printAddresses = true;
}
Expand Down
4 changes: 4 additions & 0 deletions src/PaymentGateService/PaymentServiceConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ struct Configuration {
std::string containerPassword;
std::string logFile;
std::string serverRoot;
std::string secretViewKey;
std::string secretSpendKey;
std::string mnemonicSeed;

bool generateNewContainer;
bool generateDeterministic;
bool daemonize;
bool registerService;
bool unregisterService;
Expand Down
1 change: 1 addition & 0 deletions src/Rpc/RpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,7 @@ bool RpcServer::f_on_block_json(const F_COMMAND_RPC_GET_BLOCK_DETAILS::request&
res.block.nonce = block_header.nonce;
res.block.hash = block_header.hash;
res.block.depth = block_header.depth;
res.block.orphan_status = block_header.orphan_status;
m_core.getBlockDifficulty(static_cast<uint32_t>(res.block.height), res.block.difficulty);
m_core.getBlockCumulativeDifficulty(static_cast<uint32_t>(res.block.height), res.block.cumulativeDifficulty);

Expand Down
2 changes: 1 addition & 1 deletion src/version.h.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#define BUILD_COMMIT_ID "Stable"
#define PROJECT_VERSION "3.0"
#define PROJECT_VERSION_BUILD_NO "0"
#define PROJECT_VERSION_BUILD_NO "1"
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO " (" BUILD_COMMIT_ID ")"

0 comments on commit 56d0394

Please sign in to comment.