version-1.4

This commit is contained in:
aeonix
2014-07-07 07:07:01 +02:00
parent 8addf7d335
commit d0a4015643
19 changed files with 530 additions and 451 deletions
+6
View File
@@ -4,8 +4,14 @@
#pragma once
// FIXME: Why is this ifdef needed? Hopefully making it struct won't break things.
/*
#if defined(_MSC_VER)
#define POD_CLASS struct
#else
#define POD_CLASS class
#endif
*/
#define POD_CLASS struct
-177
View File
@@ -1,177 +0,0 @@
/*
---------------------------------------------------------------------------
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
The redistribution and use of this software (with or without changes)
is allowed without the payment of fees or royalties provided that:
source code distributions include the above copyright notice, this
list of conditions and the following disclaimer;
binary distributions include the above copyright notice, this list
of conditions and the following disclaimer in their documentation.
This software is provided 'as is' with no explicit or implied warranties
in respect of its operation, including, but not limited to, correctness
and fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 20/12/2007
*/
#include <stdint.h>
#if defined(__cplusplus)
extern "C"
{
#endif
#define TABLE_ALIGN 32
#define WPOLY 0x011b
#define N_COLS 4
#define AES_BLOCK_SIZE 16
#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
#if defined(_MSC_VER)
#define ALIGN __declspec(align(TABLE_ALIGN))
#elif defined(__GNUC__)
#define ALIGN __attribute__ ((aligned(16)))
#else
#define ALIGN
#endif
#define rf1(r,c) (r)
#define word_in(x,c) (*((uint32_t*)(x)+(c)))
#define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v))
#define s(x,c) x[c]
#define si(y,x,c) (s(y,c) = word_in(x, c))
#define so(y,x,c) word_out(y, c, s(x,c))
#define state_in(y,x) si(y,x,0); si(y,x,1); si(y,x,2); si(y,x,3)
#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
#define to_byte(x) ((x) & 0xff)
#define bval(x,n) to_byte((x) >> (8 * (n)))
#define fwd_var(x,r,c)\
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
: r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
: ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
#define sb_data(w) {\
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
#define rc_data(w) {\
w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
w(0x1b), w(0x36) }
#define bytes2word(b0, b1, b2, b3) (((uint32_t)(b3) << 24) | \
((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
#define h0(x) (x)
#define w0(p) bytes2word(p, 0, 0, 0)
#define w1(p) bytes2word(0, p, 0, 0)
#define w2(p) bytes2word(0, 0, p, 0)
#define w3(p) bytes2word(0, 0, 0, p)
#define u0(p) bytes2word(f2(p), p, p, f3(p))
#define u1(p) bytes2word(f3(p), f2(p), p, p)
#define u2(p) bytes2word(p, f3(p), f2(p), p)
#define u3(p) bytes2word(p, p, f3(p), f2(p))
#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY))
#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) ^ (((x>>5) & 4) * WPOLY))
#define f3(x) (f2(x) ^ x)
#define f9(x) (f8(x) ^ x)
#define fb(x) (f8(x) ^ f2(x) ^ x)
#define fd(x) (f8(x) ^ f4(x) ^ x)
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
#define t_dec(m,n) t_##m##n
#define t_set(m,n) t_##m##n
#define t_use(m,n) t_##m##n
#define d_4(t,n,b,e,f,g,h) ALIGN const t n[4][256] = { b(e), b(f), b(g), b(h) }
#define four_tables(x,tab,vf,rf,c) \
(tab[0][bval(vf(x,0,c),rf(0,c))] \
^ tab[1][bval(vf(x,1,c),rf(1,c))] \
^ tab[2][bval(vf(x,2,c),rf(2,c))] \
^ tab[3][bval(vf(x,3,c),rf(3,c))])
d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3);
void aesb_single_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey)
{
uint32_t b0[4], b1[4];
const uint32_t *kp = (uint32_t *) expandedKey;
state_in(b0, in);
round(fwd_rnd, b1, b0, kp);
state_out(out, b1);
}
void aesb_pseudo_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey)
{
uint32_t b0[4], b1[4];
const uint32_t *kp = (uint32_t *) expandedKey;
state_in(b0, in);
round(fwd_rnd, b1, b0, kp);
round(fwd_rnd, b0, b1, kp + 1 * N_COLS);
round(fwd_rnd, b1, b0, kp + 2 * N_COLS);
round(fwd_rnd, b0, b1, kp + 3 * N_COLS);
round(fwd_rnd, b1, b0, kp + 4 * N_COLS);
round(fwd_rnd, b0, b1, kp + 5 * N_COLS);
round(fwd_rnd, b1, b0, kp + 6 * N_COLS);
round(fwd_rnd, b0, b1, kp + 7 * N_COLS);
round(fwd_rnd, b1, b0, kp + 8 * N_COLS);
round(fwd_rnd, b0, b1, kp + 9 * N_COLS);
state_out(out, b0);
}
#if defined(__cplusplus)
}
#endif
+23 -2
View File
@@ -50,6 +50,7 @@ namespace crypto {
return &reinterpret_cast<const unsigned char &>(scalar);
}
/* generate a random 32-byte (256-bit) integer and copy it to res */
static inline void random_scalar(ec_scalar &res) {
unsigned char tmp[64];
generate_random_bytes(64, tmp);
@@ -62,12 +63,32 @@ namespace crypto {
sc_reduce32(&res);
}
void crypto_ops::generate_keys(public_key &pub, secret_key &sec) {
/*
* generate public and secret keys from a random 256-bit integer
* TODO: allow specifiying random value (for wallet recovery)
*
*/
secret_key crypto_ops::generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover) {
lock_guard<mutex> lock(random_lock);
ge_p3 point;
random_scalar(sec);
secret_key rng;
if (recover)
{
rng = recovery_key;
}
else
{
random_scalar(rng);
}
sec = rng;
sc_reduce32(&sec); // reduce in case second round of keys (sendkeys)
ge_scalarmult_base(&point, &sec);
ge_p3_tobytes(&pub, &point);
return rng;
}
bool crypto_ops::check_key(const public_key &key) {
+4 -4
View File
@@ -62,8 +62,8 @@ namespace crypto {
void operator=(const crypto_ops &);
~crypto_ops();
static void generate_keys(public_key &, secret_key &);
friend void generate_keys(public_key &, secret_key &);
static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false);
friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover);
static bool check_key(const public_key &);
friend bool check_key(const public_key &);
static bool secret_key_to_public_key(const secret_key &, public_key &);
@@ -102,8 +102,8 @@ namespace crypto {
/* Generate a new key pair
*/
inline void generate_keys(public_key &pub, secret_key &sec) {
crypto_ops::generate_keys(pub, sec);
inline secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false) {
return crypto_ops::generate_keys(pub, sec, recovery_key, recover);
}
/* Check a public key. Returns true if it is valid, false otherwise.
+1
View File
@@ -6,6 +6,7 @@
#define CRYPTONOTE_MAX_BLOCK_NUMBER 500000000
#define CRYPTONOTE_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used!
#define CRYPTONOTE_GETBLOCKTEMPLATE_MAX_BLOCK_SIZE 196608 //size of block (bytes) that is the maximum that miners will produce
#define CRYPTONOTE_MAX_TX_SIZE 1000000000
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
#define CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX 0xB2
+13 -3
View File
@@ -10,6 +10,10 @@
#include "account.h"
#include "warnings.h"
#include "crypto/crypto.h"
extern "C"
{
#include "crypto/keccak.h"
}
#include "cryptonote_core/cryptonote_basic_impl.h"
#include "cryptonote_core/cryptonote_format_utils.h"
using namespace std;
@@ -29,11 +33,17 @@ DISABLE_VS_WARNINGS(4244 4345)
m_keys = account_keys();
}
//-----------------------------------------------------------------
void account_base::generate()
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
{
generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key);
generate_keys(m_keys.m_account_address.m_view_public_key, m_keys.m_view_secret_key);
crypto::secret_key first = generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, recovery_key, recover);
// rng for generating second set of keys is hash of first rng. means only one set of electrum-style words needed for recovery
crypto::secret_key second;
keccak((uint8_t *)&first, sizeof(crypto::secret_key), (uint8_t *)&second, sizeof(crypto::secret_key));
generate_keys(m_keys.m_account_address.m_view_public_key, m_keys.m_view_secret_key, second, two_random ? false : true);
m_creation_timestamp = time(NULL);
return first;
}
//-----------------------------------------------------------------
const account_keys& account_base::get_keys() const
+1 -1
View File
@@ -31,7 +31,7 @@ namespace cryptonote
{
public:
account_base();
void generate();
crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
const account_keys& get_keys() const;
std::string get_public_address_str();
+11 -3
View File
@@ -152,7 +152,7 @@ namespace cryptonote
<< "transaction id = " << get_transaction_hash(tx));
auto it_in_set = key_image_set.find(get_transaction_hash(tx));
CHECK_AND_ASSERT_MES(key_image_set.size(), false, "transaction id not found in key_image set, img=" << txin.k_image << ENDL
CHECK_AND_ASSERT_MES(it_in_set != key_image_set.end(), false, "transaction id not found in key_image set, img=" << txin.k_image << ENDL
<< "transaction id = " << get_transaction_hash(tx));
key_image_set.erase(it_in_set);
if(!key_image_set.size())
@@ -351,7 +351,7 @@ namespace cryptonote
ss << "id: " << txe.first << ENDL
<< "blob_size: " << txd.blob_size << ENDL
<< "fee: " << txd.fee << ENDL
<< "kept_by_block: " << txd.kept_by_block << ENDL
<< "kept_by_block: " << (txd.kept_by_block ? "true":"false") << ENDL
<< "max_used_block_height: " << txd.max_used_block_height << ENDL
<< "max_used_block_id: " << txd.max_used_block_id << ENDL
<< "last_failed_height: " << txd.last_failed_height << ENDL
@@ -363,7 +363,7 @@ namespace cryptonote
<< obj_to_json_str(txd.tx) << ENDL
<< "blob_size: " << txd.blob_size << ENDL
<< "fee: " << txd.fee << ENDL
<< "kept_by_block: " << txd.kept_by_block << ENDL
<< "kept_by_block: " << (txd.kept_by_block ? "true":"false") << ENDL
<< "max_used_block_height: " << txd.max_used_block_height << ENDL
<< "max_used_block_id: " << txd.max_used_block_id << ENDL
<< "last_failed_height: " << txd.last_failed_height << ENDL
@@ -424,6 +424,14 @@ namespace cryptonote
if (tx.second.blob_size > upper_transaction_size_limit)
continue;
// If adding this tx will make the block size
// greater than CRYPTONOTE_GETBLOCKTEMPLATE_MAX
// _BLOCK_SIZE bytes, reject the tx; this will
// keep block sizes from becoming too unwieldly
// to propagate at 60s block times.
if ( (total_size + tx.second.blob_size) > CRYPTONOTE_GETBLOCKTEMPLATE_MAX_BLOCK_SIZE )
continue;
// If adding this tx will make the block size
// greater than 130% of the median, reject the
// tx; this will keep down largely punitive tx
+126 -32
View File
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <thread>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
@@ -17,6 +18,8 @@
#include "rpc/core_rpc_server_commands_defs.h"
#include "wallet/wallet_rpc_server.h"
#include "version.h"
#include "crypto/crypto.h" // for crypto::secret_key definition
#include "crypto/electrum-words.h"
#if defined(WIN32)
#include <crtdbg.h>
@@ -38,6 +41,9 @@ namespace
const command_line::arg_descriptor<std::string> arg_daemon_address = {"daemon-address", "Use daemon instance at <host>:<port>", ""};
const command_line::arg_descriptor<std::string> arg_daemon_host = {"daemon-host", "Use daemon instance at host <arg> instead of localhost", ""};
const command_line::arg_descriptor<std::string> arg_password = {"password", "Wallet password", "", true};
const command_line::arg_descriptor<std::string> arg_electrum_seed = {"electrum-seed", "Specify electrum seed for wallet recovery/creation", ""};
const command_line::arg_descriptor<bool> arg_restore_deterministic_wallet = {"restore-deterministic-wallet", "Recover wallet using electrum-style mnemonic", false};
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", "creates non-deterministic view and spend keys", false};
const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", "Use daemon instance at port <arg> instead of 8081", 0};
const command_line::arg_descriptor<uint32_t> arg_log_level = {"set_log", "", 0, true};
@@ -208,17 +214,25 @@ bool simple_wallet::ask_wallet_create_if_needed()
{
std::string wallet_path;
std::cout << "Specify wallet file name (e.g., wallet.bin). If the wallet doesn't exist, it will be created.\n";
std::cout << "Wallet file name: ";
std::getline(std::cin, wallet_path);
wallet_path = string_tools::trim(wallet_path);
wallet_path = command_line::input_line(
"Specify wallet file name (e.g., wallet.bin). If the wallet doesn't exist, it will be created.\n"
"Wallet file name: "
);
bool keys_file_exists;
bool wallet_file_exists;
tools::wallet2::wallet_exists(wallet_path, keys_file_exists, wallet_file_exists);
// add logic to error out if new wallet requested but named wallet file exists
if (keys_file_exists || wallet_file_exists)
{
if (!m_generate_new.empty() || m_restore_deterministic_wallet)
{
fail_msg_writer() << "Attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting.";
return false;
}
}
bool r;
if(keys_file_exists)
{
@@ -251,13 +265,14 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
size_t c = 0;
if(!m_generate_new.empty()) ++c;
if(!m_wallet_file.empty()) ++c;
if (1 != c)
if(!m_generate_new.empty() && !m_wallet_file.empty())
{
if(!ask_wallet_create_if_needed())
return false;
fail_msg_writer() << "Specifying both --generate-new-wallet=\"wallet_name\" and --wallet-file=\"wallet_name\" doesn't make sense!";
return false;
}
else if (m_generate_new.empty() && m_wallet_file.empty())
{
if(!ask_wallet_create_if_needed()) return false;
}
if (m_daemon_host.empty())
@@ -282,9 +297,36 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
}
if (!m_generate_new.empty())
if (!m_generate_new.empty() || m_restore_deterministic_wallet)
{
bool r = new_wallet(m_generate_new, pwd_container.password());
if (m_wallet_file.empty()) m_wallet_file = m_generate_new; // alias for simplicity later
// check for recover flag. if present, require electrum word list (only recovery option for now).
if (m_restore_deterministic_wallet)
{
if (m_non_deterministic)
{
fail_msg_writer() << "Cannot specify both --restore-deterministic-wallet and --non-deterministic";
return false;
}
if (m_electrum_seed.empty())
{
m_electrum_seed = command_line::input_line("Specify electrum seed: ");
if (m_electrum_seed.empty())
{
fail_msg_writer() << "specify a recovery parameter with the --electrum-seed=\"words list here\"";
return false;
}
}
if (!crypto::ElectrumWords::words_to_bytes(m_electrum_seed, m_recovery_key))
{
fail_msg_writer() << "electrum-style word list failed verification";
return false;
}
}
bool r = new_wallet(m_wallet_file, pwd_container.password(), m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic);
CHECK_AND_ASSERT_MES(r, false, "account creation failed");
}
else
@@ -306,11 +348,14 @@ bool simple_wallet::deinit()
//----------------------------------------------------------------------------------------------------
void simple_wallet::handle_command_line(const boost::program_options::variables_map& vm)
{
m_wallet_file = command_line::get_arg(vm, arg_wallet_file);
m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet);
m_daemon_address = command_line::get_arg(vm, arg_daemon_address);
m_daemon_host = command_line::get_arg(vm, arg_daemon_host);
m_daemon_port = command_line::get_arg(vm, arg_daemon_port);
m_wallet_file = command_line::get_arg(vm, arg_wallet_file);
m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet);
m_daemon_address = command_line::get_arg(vm, arg_daemon_address);
m_daemon_host = command_line::get_arg(vm, arg_daemon_host);
m_daemon_port = command_line::get_arg(vm, arg_daemon_port);
m_electrum_seed = command_line::get_arg(vm, arg_electrum_seed);
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::try_connect_to_daemon()
@@ -324,16 +369,19 @@ bool simple_wallet::try_connect_to_daemon()
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password)
bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key, bool recover, bool two_random)
{
m_wallet_file = wallet_file;
m_wallet.reset(new tools::wallet2());
m_wallet->callback(this);
crypto::secret_key recovery_val;
try
{
m_wallet->generate(wallet_file, password);
recovery_val = m_wallet->generate(wallet_file, password, recovery_key, recover, two_random);
message_writer(epee::log_space::console_color_white, true) << "Generated new wallet: " << m_wallet->get_account().get_public_address_str() << std::endl << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key);
}
catch (const std::exception& e)
@@ -344,6 +392,13 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
m_wallet->init(m_daemon_address);
// convert rng value to electrum-style word list
std::string electrum_words;
crypto::ElectrumWords::bytes_to_words(recovery_val, electrum_words);
std::string print_electrum = "";
success_msg_writer() <<
"**********************************************************************\n" <<
"Your wallet has been generated.\n" <<
@@ -351,8 +406,16 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
"Use \"help\" command to see the list of available commands.\n" <<
"Always use \"exit\" command when closing simplewallet to save\n" <<
"current session's state. Otherwise, you will possibly need to synchronize \n" <<
"your wallet again. Your wallet key is NOT under risk anyway.\n" <<
"**********************************************************************";
"your wallet again. Your wallet key is NOT under risk anyway.\n"
;
if (!two_random)
{
success_msg_writer(true) << "\nPLEASE NOTE: the following 24 words can be used to recover access to your wallet. Please write them down and store them somewhere safe and secure. Please do not store them in your email or on file storage services outside of your immediate control. You will not be able to view these words again, so it is imperative to make note of them now.\n";
std::cout << electrum_words << std::endl;
}
success_msg_writer() << "**********************************************************************";
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -722,6 +785,7 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
fail_msg_writer() << "failed to get blockchain height: " << err;
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer(const std::vector<std::string> &args_)
{
@@ -788,9 +852,38 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
try
{
cryptonote::transaction tx;
m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, extra, tx);
success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(tx);
// figure out what tx will be necessary
auto ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, DEFAULT_FEE, extra);
// if more than one tx necessary, prompt user to confirm
if (ptx_vector.size() > 1)
{
std::string prompt_str = "Your transaction needs to be split into ";
prompt_str += std::to_string(ptx_vector.size());
prompt_str += " transactions. This will result in a fee of ";
prompt_str += print_money(ptx_vector.size() * DEFAULT_FEE);
prompt_str += ". Is this okay? (Y/Yes/N/No)";
std::string accepted = command_line::input_line(prompt_str);
if (accepted != "Y" && accepted != "y" && accepted != "Yes" && accepted != "yes")
{
fail_msg_writer() << "Transaction cancelled.";
// would like to return false, because no tx made, but everything else returns true
// and I don't know what returning false might adversely affect. *sigh*
return true;
}
}
// actually commit the transactions
while (!ptx_vector.empty())
{
auto & ptx = ptx_vector.back();
m_wallet->commit_tx(ptx);
success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(ptx.tx);
// if no exception, remove element from vector
ptx_vector.pop_back();
}
}
catch (const tools::error::daemon_busy&)
{
@@ -836,16 +929,14 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
{
fail_msg_writer() << e.what();
}
catch (const tools::error::tx_too_big& e)
{
cryptonote::transaction tx = e.tx();
fail_msg_writer() << "transaction " << get_transaction_hash(e.tx()) << " is too big. Transaction size: " <<
get_object_blobsize(e.tx()) << " bytes, transaction size limit: " << e.tx_size_limit() << " bytes";
}
catch (const tools::error::zero_destination&)
{
fail_msg_writer() << "one of destinations is zero";
}
catch (const tools::error::tx_too_big& e)
{
fail_msg_writer() << "Failed to find a suitable way to split transactions";
}
catch (const tools::error::transfer_error& e)
{
LOG_ERROR("unknown transfer error: " << e.to_string());
@@ -916,6 +1007,9 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_daemon_port);
command_line::add_arg(desc_params, arg_command);
command_line::add_arg(desc_params, arg_log_level);
command_line::add_arg(desc_params, arg_restore_deterministic_wallet );
command_line::add_arg(desc_params, arg_non_deterministic );
command_line::add_arg(desc_params, arg_electrum_seed );
tools::wallet_rpc_server::init_options(desc_params);
po::positional_options_description positional_options;
+11 -1
View File
@@ -13,6 +13,7 @@
#include "wallet/wallet2.h"
#include "console_handler.h"
#include "password_container.h"
#include "crypto/crypto.h" // for definition of crypto::secret_key
namespace cryptonote
@@ -39,7 +40,7 @@ namespace cryptonote
bool run_console_handler();
bool new_wallet(const std::string &wallet_file, const std::string& password);
bool new_wallet(const std::string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
bool open_wallet(const std::string &wallet_file, const std::string& password);
bool close_wallet();
@@ -53,6 +54,9 @@ namespace cryptonote
bool show_payments(const std::vector<std::string> &args);
bool show_blockchain_height(const std::vector<std::string> &args);
bool transfer(const std::vector<std::string> &args);
std::vector<std::vector<cryptonote::tx_destination_entry>> split_amounts(
std::vector<cryptonote::tx_destination_entry> dsts, size_t num_splits
);
bool print_address(const std::vector<std::string> &args = std::vector<std::string>());
bool save(const std::vector<std::string> &args);
bool set_log(const std::vector<std::string> &args);
@@ -125,6 +129,12 @@ namespace cryptonote
std::string m_generate_new;
std::string m_import_path;
std::string m_electrum_seed; // electrum-style seed parameter
crypto::secret_key m_recovery_key; // recovery key (used as random for wallet gen)
bool m_restore_deterministic_wallet; // recover flag
bool m_non_deterministic; // old 2-random generation
std::string m_daemon_address;
std::string m_daemon_host;
int m_daemon_port;
+190 -5
View File
@@ -38,10 +38,14 @@ void do_prepare_file_names(const std::string& file_path, std::string& keys_file,
keys_file += ".keys";
}
}
} //namespace
namespace tools
{
// for now, limit to 30 attempts. TODO: discuss a good number to limit to.
const size_t MAX_SPLIT_ATTEMPTS = 30;
//----------------------------------------------------------------------------------------------------
void wallet2::init(const std::string& daemon_address, uint64_t upper_transaction_size_limit)
{
@@ -435,7 +439,7 @@ void wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password);
}
//----------------------------------------------------------------------------------------------------
void wallet2::generate(const std::string& wallet_, const std::string& password)
crypto::secret_key wallet2::generate(const std::string& wallet_, const std::string& password, const crypto::secret_key& recovery_param, bool recover, bool two_random)
{
clear();
prepare_file_names(wallet_);
@@ -444,7 +448,8 @@ void wallet2::generate(const std::string& wallet_, const std::string& password)
THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
m_account.generate();
crypto::secret_key retval = m_account.generate(recovery_param, recover, two_random);
m_account_public_address = m_account.get_keys().m_account_address;
bool r = store_keys(m_keys_file, password);
@@ -454,6 +459,7 @@ void wallet2::generate(const std::string& wallet_, const std::string& password)
if(!r) LOG_PRINT_RED_L0("String with address text not saved");
store();
return retval;
}
//----------------------------------------------------------------------------------------------------
void wallet2::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exists)
@@ -627,10 +633,17 @@ namespace
}
}
//----------------------------------------------------------------------------------------------------
// Select random input sources for transaction.
// returns:
// direct return: amount of money found
// modified reference: selected_transfers, a list of iterators/indices of input sources
uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers)
{
std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices;
// aggregate sources available for transfers
// if dust needed, take dust from only one source (so require source has at least dust amount)
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
@@ -675,16 +688,188 @@ void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t cha
}
//----------------------------------------------------------------------------------------------------
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx)
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx)
{
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(fee), tx);
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(fee), tx, ptx);
}
//----------------------------------------------------------------------------------------------------
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra)
{
cryptonote::transaction tx;
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, tx);
pending_tx ptx;
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, tx, ptx);
}
namespace {
// split_amounts(vector<cryptonote::tx_destination_entry> dsts, size_t num_splits)
//
// split amount for each dst in dsts into num_splits parts
// and make num_splits new vector<crypt...> instances to hold these new amounts
std::vector<std::vector<cryptonote::tx_destination_entry>> split_amounts(
std::vector<cryptonote::tx_destination_entry> dsts, size_t num_splits)
{
std::vector<std::vector<cryptonote::tx_destination_entry>> retVal;
if (num_splits <= 1)
{
retVal.push_back(dsts);
return retVal;
}
// for each split required
for (size_t i=0; i < num_splits; i++)
{
std::vector<cryptonote::tx_destination_entry> new_dsts;
// for each destination
for (size_t j=0; j < dsts.size(); j++)
{
cryptonote::tx_destination_entry de;
uint64_t amount;
amount = dsts[j].amount;
amount = amount / num_splits;
// if last split, add remainder
if (i + 1 == num_splits)
{
amount += dsts[j].amount % num_splits;
}
de.addr = dsts[j].addr;
de.amount = amount;
new_dsts.push_back(de);
}
retVal.push_back(new_dsts);
}
return retVal;
}
} // anonymous namespace
//----------------------------------------------------------------------------------------------------
// take a pending tx and actually send it to the daemon
void wallet2::commit_tx(pending_tx& ptx)
{
using namespace cryptonote;
COMMAND_RPC_SEND_RAW_TX::request req;
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, daemon_send_resp.status);
add_unconfirmed_tx(ptx.tx, ptx.change_dts.amount);
LOG_PRINT_L2("transaction " << get_transaction_hash(ptx.tx) << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]");
BOOST_FOREACH(transfer_container::iterator it, ptx.selected_transfers)
it->m_spent = true;
LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(ptx.tx) << ">" << ENDL
<< "Commission: " << print_money(ptx.fee+ptx.dust) << " (dust: " << print_money(ptx.dust) << ")" << ENDL
<< "Balance: " << print_money(balance()) << ENDL
<< "Unlocked: " << print_money(unlocked_balance()) << ENDL
<< "Please, wait for confirmation for your balance to be unlocked.");
}
void wallet2::commit_tx(std::vector<pending_tx>& ptx_vector)
{
for (auto & ptx : ptx_vector)
{
commit_tx(ptx);
}
}
//----------------------------------------------------------------------------------------------------
// separated the call(s) to wallet2::transfer into their own function
//
// this function will make multiple calls to wallet2::transfer if multiple
// transactions will be required
std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector<uint8_t> extra)
{
// failsafe split attempt counter
size_t attempt_count = 0;
for(attempt_count = 1; ;attempt_count++)
{
auto split_values = split_amounts(dsts, attempt_count);
// Throw if split_amounts comes back with a vector of size different than it should
if (split_values.size() != attempt_count)
{
throw std::runtime_error("Splitting transactions returned a number of potential tx not equal to what was requested");
}
std::vector<pending_tx> ptx_vector;
try
{
// for each new destination vector (i.e. for each new tx)
for (auto & dst_vector : split_values)
{
cryptonote::transaction tx;
pending_tx ptx;
transfer(dst_vector, fake_outs_count, unlock_time, fee, extra, tx, ptx);
ptx_vector.push_back(ptx);
// mark transfers to be used as "spent"
BOOST_FOREACH(transfer_container::iterator it, ptx.selected_transfers)
it->m_spent = true;
}
// if we made it this far, we've selected our transactions. committing them will mark them spent,
// so this is a failsafe in case they don't go through
// unmark pending tx transfers as spent
for (auto & ptx : ptx_vector)
{
// mark transfers to be used as not spent
BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers)
it2->m_spent = false;
}
// if we made it this far, we're OK to actually send the transactions
return ptx_vector;
}
// only catch this here, other exceptions need to pass through to the calling function
catch (const tools::error::tx_too_big& e)
{
// unmark pending tx transfers as spent
for (auto & ptx : ptx_vector)
{
// mark transfers to be used as not spent
BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers)
it2->m_spent = false;
}
if (attempt_count >= MAX_SPLIT_ATTEMPTS)
{
throw;
}
}
catch (...)
{
// in case of some other exception, make sure any tx in queue are marked unspent again
// unmark pending tx transfers as spent
for (auto & ptx : ptx_vector)
{
// mark transfers to be used as not spent
BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers)
it2->m_spent = false;
}
throw;
}
}
}
}
+34 -24
View File
@@ -23,6 +23,7 @@
#include "wallet_errors.h"
#include <iostream>
#define DEFAULT_TX_SPENDABLE_AGE 10
#define WALLET_RCP_CONNECTION_TIMEOUT 200000
@@ -86,6 +87,15 @@ namespace tools
typedef std::vector<transfer_details> transfer_container;
typedef std::unordered_multimap<crypto::hash, payment_details> payment_container;
struct pending_tx
{
cryptonote::transaction tx;
uint64_t dust, fee;
cryptonote::tx_destination_entry change_dts;
std::list<transfer_container::iterator> selected_transfers;
std::string key_images;
};
struct keys_file_data
{
crypto::chacha8_iv iv;
@@ -97,7 +107,7 @@ namespace tools
END_SERIALIZE()
};
void generate(const std::string& wallet, const std::string& password);
crypto::secret_key generate(const std::string& wallet, const std::string& password, const crypto::secret_key& recovery_param = crypto::secret_key(), bool recover = false, bool two_random = false);
void load(const std::string& wallet, const std::string& password);
void store();
cryptonote::account_base& get_account(){return m_account;}
@@ -125,9 +135,12 @@ namespace tools
template<typename T>
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy);
template<typename T>
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx);
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx& ptx);
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra);
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx);
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx);
void commit_tx(pending_tx& ptx_vector);
void commit_tx(std::vector<pending_tx>& ptx_vector);
std::vector<pending_tx> create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector<uint8_t> extra);
bool check_connection();
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments) const;
@@ -227,6 +240,7 @@ namespace boost
namespace tools
{
namespace detail
{
//----------------------------------------------------------------------------------------------------
@@ -294,18 +308,23 @@ namespace tools
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy)
{
pending_tx ptx;
cryptonote::transaction tx;
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx);
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx, ptx);
}
template<typename T>
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx)
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx)
{
using namespace cryptonote;
// throw if attempting a transaction with no destinations
THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
uint64_t needed_money = fee;
// calculate total amount being sent to all destinations
// throw if total amount overflows uint64_t
BOOST_FOREACH(auto& dt, dsts)
{
THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination);
@@ -313,6 +332,8 @@ namespace tools
THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee);
}
// randomly select inputs for transaction
// throw if requested send amount is greater than amount available to send
std::list<transfer_container::iterator> selected_transfers;
uint64_t found_money = select_transfers(needed_money, 0 == fake_outputs_count, dust_policy.dust_threshold, selected_transfers);
THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
@@ -425,25 +446,14 @@ namespace tools
});
THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx);
COMMAND_RPC_SEND_RAW_TX::request req;
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx));
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, tx, daemon_send_resp.status);
ptx.key_images = key_images;
ptx.fee = fee;
ptx.dust = dust;
ptx.tx = tx;
ptx.change_dts = change_dts;
ptx.selected_transfers = selected_transfers;
add_unconfirmed_tx(tx, change_dts.amount);
LOG_PRINT_L2("transaction " << get_transaction_hash(tx) << " generated ok and sent to daemon, key_images: [" << key_images << "]");
BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
it->m_spent = true;
LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(tx) << ">" << ENDL
<< "Commission: " << print_money(fee+dust) << " (dust: " << print_money(dust) << ")" << ENDL
<< "Balance: " << print_money(balance()) << ENDL
<< "Unlocked: " << print_money(unlocked_balance()) << ENDL
<< "Please, wait for confirmation for your balance to be unlocked.");
}
}
+11
View File
@@ -188,6 +188,17 @@ namespace tools
std::string to_string() const { return wallet_logic_error::to_string(); }
};
//----------------------------------------------------------------------------------------------------
struct invalid_pregenerated_random : public wallet_logic_error
{
explicit invalid_pregenerated_random (std::string&& loc)
: wallet_logic_error(std::move(loc), "invalid pregenerated random for wallet creation/recovery")
{
}
std::string to_string() const { return wallet_logic_error::to_string(); }
};
//----------------------------------------------------------------------------------------------------
struct refresh_error : public wallet_logic_error
{
+84 -11
View File
@@ -10,6 +10,7 @@ using namespace epee;
#include "common/command_line.h"
#include "cryptonote_core/cryptonote_format_utils.h"
#include "cryptonote_core/account.h"
#include "wallet_rpc_server_commands_defs.h"
#include "misc_language.h"
#include "string_tools.h"
#include "crypto/hash.h"
@@ -85,12 +86,11 @@ namespace tools
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::vector<cryptonote::tx_destination_entry> dsts;
for (auto it = req.destinations.begin(); it != req.destinations.end(); it++)
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination> destinations, const std::string payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t> extra, epee::json_rpc::error& er)
{
for (auto it = destinations.begin(); it != destinations.end(); it++)
{
cryptonote::tx_destination_entry de;
if(!get_account_address_from_str(de.addr, it->address))
@@ -103,11 +103,11 @@ namespace tools
dsts.push_back(de);
}
std::vector<uint8_t> extra;
if (!req.payment_id.empty()) {
if (!payment_id.empty())
{
/* Just to clarify */
const std::string& payment_id_str = req.payment_id;
const std::string& payment_id_str = payment_id;
crypto::hash payment_id;
/* Parse payment ID */
@@ -128,12 +128,85 @@ namespace tools
}
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::vector<cryptonote::tx_destination_entry> dsts;
std::vector<uint8_t> extra;
// validate the transfer requested and populate dsts & extra
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er))
{
return false;
}
try
{
cryptonote::transaction tx;
m_wallet.transfer(dsts, req.mixin, req.unlock_time, req.fee, extra, tx);
res.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(tx));
std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions(dsts, req.mixin, req.unlock_time, req.fee, extra);
// reject proposed transactions if there are more than one. see on_transfer_split below.
if (ptx_vector.size() != 1)
{
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
er.message = "Transaction would be too large. try /transfer_split.";
return false;
}
m_wallet.commit_tx(ptx_vector);
// populate response with tx hash
res.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(ptx_vector.back().tx));
return true;
}
catch (const tools::error::daemon_busy& e)
{
er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
er.message = e.what();
return false;
}
catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
er.message = e.what();
return false;
}
catch (...)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
std::vector<cryptonote::tx_destination_entry> dsts;
std::vector<uint8_t> extra;
// validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types.
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er))
{
return false;
}
try
{
std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions(dsts, req.mixin, req.unlock_time, req.fee, extra);
m_wallet.commit_tx(ptx_vector);
// populate response with tx hashes
for (auto & ptx : ptx_vector)
{
res.tx_hash_list.push_back(boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(ptx.tx)));
}
return true;
}
catch (const tools::error::daemon_busy& e)
+4 -1
View File
@@ -7,7 +7,7 @@
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include "net/http_server_impl_base.h"
#include "wallet_rpc_server_commans_defs.h"
#include "wallet_rpc_server_commands_defs.h"
#include "wallet2.h"
#include "common/command_line.h"
namespace tools
@@ -38,6 +38,7 @@ namespace tools
MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE)
MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_rpc::COMMAND_RPC_GET_ADDRESS)
MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
MAP_JON_RPC_WE("transfer_split", on_transfer_split, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT)
MAP_JON_RPC_WE("store", on_store, wallet_rpc::COMMAND_RPC_STORE)
MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_rpc::COMMAND_RPC_GET_PAYMENTS)
MAP_JON_RPC_WE("incoming_transfers", on_incoming_transfers, wallet_rpc::COMMAND_RPC_INCOMING_TRANSFERS)
@@ -47,7 +48,9 @@ namespace tools
//json_rpc
bool on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_getaddress(const wallet_rpc::COMMAND_RPC_GET_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool validate_transfer(const std::list<wallet_rpc::transfer_destination> destinations, const std::string payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t> extra, epee::json_rpc::error& er);
bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_incoming_transfers(const wallet_rpc::COMMAND_RPC_INCOMING_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_INCOMING_TRANSFERS::response& res, epee::json_rpc::error& er, connection_context& cntx);
-182
View File
@@ -1,182 +0,0 @@
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
#include "cryptonote_core/cryptonote_basic.h"
#include "crypto/hash.h"
#include "wallet_rpc_server_error_codes.h"
namespace tools
{
namespace wallet_rpc
{
#define WALLET_RPC_STATUS_OK "OK"
#define WALLET_RPC_STATUS_BUSY "BUSY"
struct COMMAND_RPC_GET_BALANCE
{
struct request
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
struct response
{
uint64_t balance;
uint64_t unlocked_balance;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balance)
KV_SERIALIZE(unlocked_balance)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_GET_ADDRESS
{
struct request
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string address;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
END_KV_SERIALIZE_MAP()
};
};
struct trnsfer_destination
{
uint64_t amount;
std::string address;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE(address)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_RPC_TRANSFER
{
struct request
{
std::list<trnsfer_destination> destinations;
uint64_t fee;
uint64_t mixin;
uint64_t unlock_time;
std::string payment_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(destinations)
KV_SERIALIZE(fee)
KV_SERIALIZE(mixin)
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(payment_id)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string tx_hash;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_STORE
{
struct request
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
struct response
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
};
struct payment_details
{
std::string tx_hash;
uint64_t amount;
uint64_t block_height;
uint64_t unlock_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(amount)
KV_SERIALIZE(block_height)
KV_SERIALIZE(unlock_time)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_RPC_GET_PAYMENTS
{
struct request
{
std::string payment_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payment_id)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::list<payment_details> payments;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payments)
END_KV_SERIALIZE_MAP()
};
};
struct transfer_details
{
uint64_t amount;
bool spent;
uint64_t global_index;
std::string tx_hash;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE(spent)
KV_SERIALIZE(global_index)
KV_SERIALIZE(tx_hash)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_RPC_INCOMING_TRANSFERS
{
struct request
{
std::string transfer_type;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(transfer_type)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::list<transfer_details> transfers;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(transfers)
END_KV_SERIALIZE_MAP()
};
};
}
}