mirror of
https://github.com/jwinterm/aeon.git
synced 2026-10-17 05:01:26 +02:00
version-1.4
This commit is contained in:
+1
-1
@@ -23,7 +23,7 @@ set(STATIC ${MSVC} CACHE BOOL "Link libraries statically")
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
# Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(Threads)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
|
||||
@@ -233,6 +233,7 @@ namespace epee
|
||||
|
||||
void stop()
|
||||
{
|
||||
m_running = false;
|
||||
m_stdin_reader.stop();
|
||||
}
|
||||
|
||||
@@ -244,6 +245,10 @@ namespace epee
|
||||
bool continue_handle = true;
|
||||
while(continue_handle)
|
||||
{
|
||||
if (!m_running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!prompt.empty())
|
||||
{
|
||||
epee::log_space::set_console_color(epee::log_space::console_color_yellow, true);
|
||||
@@ -257,9 +262,7 @@ namespace epee
|
||||
std::string command;
|
||||
if(!m_stdin_reader.get_line(command))
|
||||
{
|
||||
LOG_PRINT("Failed to read line. Stopping...", LOG_LEVEL_0);
|
||||
continue_handle = false;
|
||||
break;
|
||||
LOG_PRINT("Failed to read line.", LOG_LEVEL_0);
|
||||
}
|
||||
string_tools::trim(command);
|
||||
|
||||
@@ -287,6 +290,7 @@ namespace epee
|
||||
|
||||
private:
|
||||
async_stdin_reader m_stdin_reader;
|
||||
bool m_running = true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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.");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,9 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor,
|
||||
|
||||
try
|
||||
{
|
||||
w1.transfer(dsts, mix_in_factor, 0, DEFAULT_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(DEFAULT_FEE), tx);
|
||||
tools::wallet2::pending_tx ptx;
|
||||
w1.transfer(dsts, mix_in_factor, 0, DEFAULT_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(DEFAULT_FEE), tx, ptx);
|
||||
w1.commit_tx(ptx);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception&)
|
||||
|
||||
Reference in New Issue
Block a user