Change donation
This commit is contained in:
parent
6c35e24634
commit
00915e6d34
52 changed files with 943 additions and 400 deletions
|
@ -31,7 +31,8 @@ const uint32_t WALLET_UNCONFIRMED_TRANSACTION_HEIGHT = std::numeric_limits<uint3
|
||||||
enum class WalletTransactionState : uint8_t {
|
enum class WalletTransactionState : uint8_t {
|
||||||
SUCCEEDED = 0,
|
SUCCEEDED = 0,
|
||||||
FAILED,
|
FAILED,
|
||||||
CANCELLED
|
CANCELLED,
|
||||||
|
CREATED
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WalletEventType {
|
enum WalletEventType {
|
||||||
|
@ -77,11 +78,37 @@ struct WalletTransaction {
|
||||||
bool isBase;
|
bool isBase;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class WalletTransferType : uint8_t {
|
||||||
|
USUAL = 0,
|
||||||
|
DONATION
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WalletOrder {
|
||||||
|
std::string address;
|
||||||
|
uint64_t amount;
|
||||||
|
};
|
||||||
|
|
||||||
struct WalletTransfer {
|
struct WalletTransfer {
|
||||||
|
WalletTransferType type;
|
||||||
std::string address;
|
std::string address;
|
||||||
int64_t amount;
|
int64_t amount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DonationSettings {
|
||||||
|
std::string address;
|
||||||
|
uint64_t threshold = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TransactionParameters {
|
||||||
|
std::string sourceAddress;
|
||||||
|
std::vector<WalletOrder> destinations;
|
||||||
|
uint64_t fee = 0;
|
||||||
|
uint64_t mixIn = 0;
|
||||||
|
std::string extra;
|
||||||
|
uint64_t unlockTimestamp = 0;
|
||||||
|
DonationSettings donation;
|
||||||
|
};
|
||||||
|
|
||||||
class IWallet {
|
class IWallet {
|
||||||
public:
|
public:
|
||||||
virtual ~IWallet() {}
|
virtual ~IWallet() {}
|
||||||
|
@ -113,10 +140,11 @@ public:
|
||||||
virtual size_t getTransactionTransferCount(size_t transactionIndex) const = 0;
|
virtual size_t getTransactionTransferCount(size_t transactionIndex) const = 0;
|
||||||
virtual WalletTransfer getTransactionTransfer(size_t transactionIndex, size_t transferIndex) const = 0;
|
virtual WalletTransfer getTransactionTransfer(size_t transactionIndex, size_t transferIndex) const = 0;
|
||||||
|
|
||||||
virtual size_t transfer(const WalletTransfer& destination, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) = 0;
|
virtual size_t transfer(const WalletOrder& destination, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) = 0;
|
||||||
virtual size_t transfer(const std::vector<WalletTransfer>& destinations, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) = 0;
|
virtual size_t transfer(const std::vector<WalletOrder>& destinations, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) = 0;
|
||||||
virtual size_t transfer(const std::string& sourceAddress, const WalletTransfer& destination, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) = 0;
|
virtual size_t transfer(const std::string& sourceAddress, const WalletOrder& destination, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) = 0;
|
||||||
virtual size_t transfer(const std::string& sourceAddress, const std::vector<WalletTransfer>& destinations, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) = 0;
|
virtual size_t transfer(const std::string& sourceAddress, const std::vector<WalletOrder>& destinations, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) = 0;
|
||||||
|
virtual size_t transfer(const TransactionParameters& sendingTransaction) = 0;
|
||||||
|
|
||||||
virtual void start() = 0;
|
virtual void start() = 0;
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
|
|
|
@ -78,12 +78,72 @@ private:
|
||||||
const std::function<void(const INode::Callback&)> requestFunc;
|
const std::function<void(const INode::Callback&)> requestFunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BlockchainExplorer::PoolUpdateGuard::PoolUpdateGuard() :
|
||||||
|
m_state(State::NONE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BlockchainExplorer::PoolUpdateGuard::beginUpdate() {
|
||||||
|
auto state = m_state.load();
|
||||||
|
for (;;) {
|
||||||
|
switch (state) {
|
||||||
|
case State::NONE:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case State::UPDATING:
|
||||||
|
if (m_state.compare_exchange_weak(state, State::UPDATE_REQUIRED)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case State::UPDATE_REQUIRED:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BlockchainExplorer::PoolUpdateGuard::endUpdate() {
|
||||||
|
auto state = m_state.load();
|
||||||
|
for (;;) {
|
||||||
|
assert(state != State::NONE);
|
||||||
|
|
||||||
|
if (m_state.compare_exchange_weak(state, State::NONE)) {
|
||||||
|
return state == State::UPDATE_REQUIRED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScopeExitHandler {
|
||||||
|
public:
|
||||||
|
ScopeExitHandler(std::function<void()>&& handler) :
|
||||||
|
m_handler(std::move(handler)),
|
||||||
|
m_cancelled(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopeExitHandler() {
|
||||||
|
if (!m_cancelled) {
|
||||||
|
m_handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
m_cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> m_handler;
|
||||||
|
bool m_cancelled;
|
||||||
|
};
|
||||||
|
|
||||||
BlockchainExplorer::BlockchainExplorer(INode& node, Logging::ILogger& logger) :
|
BlockchainExplorer::BlockchainExplorer(INode& node, Logging::ILogger& logger) :
|
||||||
node(node),
|
node(node),
|
||||||
logger(logger, "BlockchainExplorer"),
|
logger(logger, "BlockchainExplorer"),
|
||||||
state(NOT_INITIALIZED),
|
state(NOT_INITIALIZED),
|
||||||
synchronized(false),
|
synchronized(false),
|
||||||
observersCounter(0) {}
|
observersCounter(0) {
|
||||||
|
}
|
||||||
|
|
||||||
BlockchainExplorer::~BlockchainExplorer() {}
|
BlockchainExplorer::~BlockchainExplorer() {}
|
||||||
|
|
||||||
|
@ -432,6 +492,12 @@ void BlockchainExplorer::poolChanged() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!poolUpdateGuard.beginUpdate()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeExitHandler poolUpdateEndGuard(std::bind(&BlockchainExplorer::poolUpdateEndHandler, this));
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
|
|
||||||
std::shared_ptr<std::vector<std::unique_ptr<ITransactionReader>>> rawNewTransactionsPtr = std::make_shared<std::vector<std::unique_ptr<ITransactionReader>>>();
|
std::shared_ptr<std::vector<std::unique_ptr<ITransactionReader>>> rawNewTransactionsPtr = std::make_shared<std::vector<std::unique_ptr<ITransactionReader>>>();
|
||||||
|
@ -454,8 +520,11 @@ void BlockchainExplorer::poolChanged() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
request.performAsync(asyncContextCounter,
|
request.performAsync(asyncContextCounter,
|
||||||
[this, rawNewTransactionsPtr, removedTransactionsPtr, isBlockchainActualPtr](std::error_code ec) {
|
[this, rawNewTransactionsPtr, removedTransactionsPtr, isBlockchainActualPtr](std::error_code ec) {
|
||||||
|
ScopeExitHandler poolUpdateEndGuard(std::bind(&BlockchainExplorer::poolUpdateEndHandler, this));
|
||||||
|
|
||||||
if (ec) {
|
if (ec) {
|
||||||
logger(ERROR) << "Can't send poolChanged notification because can't get pool symmetric difference: " << ec.message();
|
logger(ERROR) << "Can't send poolChanged notification because can't get pool symmetric difference: " << ec.message();
|
||||||
return;
|
return;
|
||||||
|
@ -503,21 +572,34 @@ void BlockchainExplorer::poolChanged() {
|
||||||
std::placeholders::_1
|
std::placeholders::_1
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
request.performAsync(asyncContextCounter,
|
request.performAsync(asyncContextCounter,
|
||||||
[this, newTransactionsHashesPtr, newTransactionsPtr, removedTransactionsHashesPtr](std::error_code ec) {
|
[this, newTransactionsHashesPtr, newTransactionsPtr, removedTransactionsHashesPtr](std::error_code ec) {
|
||||||
|
ScopeExitHandler poolUpdateEndGuard(std::bind(&BlockchainExplorer::poolUpdateEndHandler, this));
|
||||||
|
|
||||||
if (ec) {
|
if (ec) {
|
||||||
logger(ERROR) << "Can't send poolChanged notification because can't get transactions: " << ec.message();
|
logger(ERROR) << "Can't send poolChanged notification because can't get transactions: " << ec.message();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newTransactionsPtr->empty() || !removedTransactionsHashesPtr->empty()) {
|
if (!newTransactionsPtr->empty() || !removedTransactionsHashesPtr->empty()) {
|
||||||
observerManager.notify(&IBlockchainObserver::poolUpdated, *newTransactionsPtr, *removedTransactionsHashesPtr);
|
observerManager.notify(&IBlockchainObserver::poolUpdated, *newTransactionsPtr, *removedTransactionsHashesPtr);
|
||||||
logger(DEBUGGING) << "poolUpdated notification was successfully sent.";
|
logger(DEBUGGING) << "poolUpdated notification was successfully sent.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
poolUpdateEndGuard.reset();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
poolUpdateEndGuard.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockchainExplorer::poolUpdateEndHandler() {
|
||||||
|
if (poolUpdateGuard.endUpdate()) {
|
||||||
|
poolChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockchainExplorer::blockchainSynchronized(uint32_t topHeight) {
|
void BlockchainExplorer::blockchainSynchronized(uint32_t topHeight) {
|
||||||
|
|
|
@ -74,6 +74,25 @@ public:
|
||||||
typedef WalletAsyncContextCounter AsyncContextCounter;
|
typedef WalletAsyncContextCounter AsyncContextCounter;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void poolUpdateEndHandler();
|
||||||
|
|
||||||
|
class PoolUpdateGuard {
|
||||||
|
public:
|
||||||
|
PoolUpdateGuard();
|
||||||
|
|
||||||
|
bool beginUpdate();
|
||||||
|
bool endUpdate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class State {
|
||||||
|
NONE,
|
||||||
|
UPDATING,
|
||||||
|
UPDATE_REQUIRED
|
||||||
|
};
|
||||||
|
|
||||||
|
std::atomic<State> m_state;
|
||||||
|
};
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
NOT_INITIALIZED,
|
NOT_INITIALIZED,
|
||||||
INITIALIZED
|
INITIALIZED
|
||||||
|
@ -94,6 +113,6 @@ private:
|
||||||
Logging::LoggerRef logger;
|
Logging::LoggerRef logger;
|
||||||
|
|
||||||
AsyncContextCounter asyncContextCounter;
|
AsyncContextCounter asyncContextCounter;
|
||||||
|
PoolUpdateGuard poolUpdateGuard;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,7 @@ void readVarint(IInputStream& in, uint64_t& value) {
|
||||||
throw std::runtime_error("readVarint, value overflow");
|
throw std::runtime_error("readVarint, value overflow");
|
||||||
}
|
}
|
||||||
|
|
||||||
temp |= static_cast<size_t>(piece & 0x7f) << shift;
|
temp |= static_cast<uint64_t>(piece & 0x7f) << shift;
|
||||||
if ((piece & 0x80) == 0) {
|
if ((piece & 0x80) == 0) {
|
||||||
if (piece == 0 && shift != 0) {
|
if (piece == 0 && shift != 0) {
|
||||||
throw std::runtime_error("readVarint, invalid value representation");
|
throw std::runtime_error("readVarint, invalid value representation");
|
||||||
|
|
|
@ -164,7 +164,8 @@ const CheckpointData CHECKPOINTS[] = {
|
||||||
{804000, "bcc8b3782499aae508c40d5587d1cc5d68281435ea9bfc6804a262047f7b934d"},
|
{804000, "bcc8b3782499aae508c40d5587d1cc5d68281435ea9bfc6804a262047f7b934d"},
|
||||||
{810500, "302b2349f221232820adc3dadafd8a61b035491e33af669c78a687949eb0a381"},
|
{810500, "302b2349f221232820adc3dadafd8a61b035491e33af669c78a687949eb0a381"},
|
||||||
{816000, "32b7fdd4e4d715db81f8f09f4ba5e5c78e8113f2804d61a57378baee479ce745"},
|
{816000, "32b7fdd4e4d715db81f8f09f4ba5e5c78e8113f2804d61a57378baee479ce745"},
|
||||||
{822000, "a3c9603c6813a0dc0efc40db288c356d1a7f02d1d2e47bee04346e73715f8984"}
|
{822000, "a3c9603c6813a0dc0efc40db288c356d1a7f02d1d2e47bee04346e73715f8984"},
|
||||||
|
{841000, "2cffb6504ee38f708a6256a63585f9382b3b426e64b4504236c70678bd160dce"}
|
||||||
};
|
};
|
||||||
} // CryptoNote
|
} // CryptoNote
|
||||||
|
|
||||||
|
|
|
@ -48,18 +48,18 @@ namespace CryptoNote {
|
||||||
core(const Currency& currency, i_cryptonote_protocol* pprotocol, Logging::ILogger& logger);
|
core(const Currency& currency, i_cryptonote_protocol* pprotocol, Logging::ILogger& logger);
|
||||||
~core();
|
~core();
|
||||||
|
|
||||||
bool on_idle();
|
bool on_idle() override;
|
||||||
virtual bool handle_incoming_tx(const BinaryArray& tx_blob, tx_verification_context& tvc, bool keeped_by_block); //Deprecated. Should be removed with CryptoNoteProtocolHandler.
|
virtual bool handle_incoming_tx(const BinaryArray& tx_blob, tx_verification_context& tvc, bool keeped_by_block) override; //Deprecated. Should be removed with CryptoNoteProtocolHandler.
|
||||||
bool handle_incoming_block_blob(const BinaryArray& block_blob, block_verification_context& bvc, bool control_miner, bool relay_block);
|
bool handle_incoming_block_blob(const BinaryArray& block_blob, block_verification_context& bvc, bool control_miner, bool relay_block) override;
|
||||||
virtual i_cryptonote_protocol* get_protocol(){return m_pprotocol;}
|
virtual i_cryptonote_protocol* get_protocol() override {return m_pprotocol;}
|
||||||
const Currency& currency() const { return m_currency; }
|
const Currency& currency() const { return m_currency; }
|
||||||
|
|
||||||
//-------------------- IMinerHandler -----------------------
|
//-------------------- IMinerHandler -----------------------
|
||||||
virtual bool handle_block_found(Block& b);
|
virtual bool handle_block_found(Block& b) override;
|
||||||
virtual bool get_block_template(Block& b, const AccountPublicAddress& adr, difficulty_type& diffic, uint32_t& height, const BinaryArray& ex_nonce);
|
virtual bool get_block_template(Block& b, const AccountPublicAddress& adr, difficulty_type& diffic, uint32_t& height, const BinaryArray& ex_nonce) override;
|
||||||
|
|
||||||
bool addObserver(ICoreObserver* observer);
|
bool addObserver(ICoreObserver* observer) override;
|
||||||
bool removeObserver(ICoreObserver* observer);
|
bool removeObserver(ICoreObserver* observer) override;
|
||||||
|
|
||||||
miner& get_miner() { return *m_miner; }
|
miner& get_miner() { return *m_miner; }
|
||||||
static void init_options(boost::program_options::options_description& desc);
|
static void init_options(boost::program_options::options_description& desc);
|
||||||
|
@ -93,13 +93,13 @@ namespace CryptoNote {
|
||||||
virtual bool removeMessageQueue(MessageQueue<BlockchainMessage>& messageQueue) override;
|
virtual bool removeMessageQueue(MessageQueue<BlockchainMessage>& messageQueue) override;
|
||||||
|
|
||||||
uint32_t get_current_blockchain_height();
|
uint32_t get_current_blockchain_height();
|
||||||
bool have_block(const Crypto::Hash& id);
|
bool have_block(const Crypto::Hash& id) override;
|
||||||
std::vector<Crypto::Hash> buildSparseChain() override;
|
std::vector<Crypto::Hash> buildSparseChain() override;
|
||||||
std::vector<Crypto::Hash> buildSparseChain(const Crypto::Hash& startBlockId) override;
|
std::vector<Crypto::Hash> buildSparseChain(const Crypto::Hash& startBlockId) override;
|
||||||
void on_synchronized();
|
void on_synchronized() override;
|
||||||
bool is_ready() override;
|
bool is_ready() override;
|
||||||
|
|
||||||
virtual void get_blockchain_top(uint32_t& height, Crypto::Hash& top_id);
|
virtual void get_blockchain_top(uint32_t& height, Crypto::Hash& top_id) override;
|
||||||
bool get_blocks(uint32_t start_offset, uint32_t count, std::list<Block>& blocks, std::list<Transaction>& txs);
|
bool get_blocks(uint32_t start_offset, uint32_t count, std::list<Block>& blocks, std::list<Transaction>& txs);
|
||||||
bool get_blocks(uint32_t start_offset, uint32_t count, std::list<Block>& blocks);
|
bool get_blocks(uint32_t start_offset, uint32_t count, std::list<Block>& blocks);
|
||||||
template<class t_ids_container, class t_blocks_container, class t_missed_container>
|
template<class t_ids_container, class t_blocks_container, class t_missed_container>
|
||||||
|
@ -129,13 +129,13 @@ namespace CryptoNote {
|
||||||
//bool get_outs(uint64_t amount, std::list<Crypto::PublicKey>& pkeys);
|
//bool get_outs(uint64_t amount, std::list<Crypto::PublicKey>& pkeys);
|
||||||
virtual std::vector<Crypto::Hash> findBlockchainSupplement(const std::vector<Crypto::Hash>& remoteBlockIds, size_t maxCount,
|
virtual std::vector<Crypto::Hash> findBlockchainSupplement(const std::vector<Crypto::Hash>& remoteBlockIds, size_t maxCount,
|
||||||
uint32_t& totalBlockCount, uint32_t& startBlockIndex) override;
|
uint32_t& totalBlockCount, uint32_t& startBlockIndex) override;
|
||||||
bool get_stat_info(core_stat_info& st_inf);
|
bool get_stat_info(core_stat_info& st_inf) override;
|
||||||
|
|
||||||
virtual bool get_tx_outputs_gindexs(const Crypto::Hash& tx_id, std::vector<uint32_t>& indexs);
|
virtual bool get_tx_outputs_gindexs(const Crypto::Hash& tx_id, std::vector<uint32_t>& indexs) override;
|
||||||
Crypto::Hash get_tail_id();
|
Crypto::Hash get_tail_id();
|
||||||
virtual bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& res);
|
virtual bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& res) override;
|
||||||
void pause_mining();
|
void pause_mining() override;
|
||||||
void update_block_template_and_resume_mining();
|
void update_block_template_and_resume_mining() override;
|
||||||
//Blockchain& get_blockchain_storage(){return m_blockchain;}
|
//Blockchain& get_blockchain_storage(){return m_blockchain;}
|
||||||
//debug functions
|
//debug functions
|
||||||
void print_blockchain(uint32_t start_index, uint32_t end_index);
|
void print_blockchain(uint32_t start_index, uint32_t end_index);
|
||||||
|
|
|
@ -50,8 +50,8 @@ namespace CryptoNote
|
||||||
|
|
||||||
CryptoNoteProtocolHandler(const Currency& currency, System::Dispatcher& dispatcher, ICore& rcore, IP2pEndpoint* p_net_layout, Logging::ILogger& log);
|
CryptoNoteProtocolHandler(const Currency& currency, System::Dispatcher& dispatcher, ICore& rcore, IP2pEndpoint* p_net_layout, Logging::ILogger& log);
|
||||||
|
|
||||||
virtual bool addObserver(ICryptoNoteProtocolObserver* observer);
|
virtual bool addObserver(ICryptoNoteProtocolObserver* observer) override;
|
||||||
virtual bool removeObserver(ICryptoNoteProtocolObserver* observer);
|
virtual bool removeObserver(ICryptoNoteProtocolObserver* observer) override;
|
||||||
|
|
||||||
void set_p2p_endpoint(IP2pEndpoint* p2p);
|
void set_p2p_endpoint(IP2pEndpoint* p2p);
|
||||||
// ICore& get_core() { return m_core; }
|
// ICore& get_core() { return m_core; }
|
||||||
|
@ -68,8 +68,8 @@ namespace CryptoNote
|
||||||
bool get_payload_sync_data(CORE_SYNC_DATA& hshd);
|
bool get_payload_sync_data(CORE_SYNC_DATA& hshd);
|
||||||
bool process_payload_sync_data(const CORE_SYNC_DATA& hshd, CryptoNoteConnectionContext& context, bool is_inital);
|
bool process_payload_sync_data(const CORE_SYNC_DATA& hshd, CryptoNoteConnectionContext& context, bool is_inital);
|
||||||
int handleCommand(bool is_notify, int command, const BinaryArray& in_buff, BinaryArray& buff_out, CryptoNoteConnectionContext& context, bool& handled);
|
int handleCommand(bool is_notify, int command, const BinaryArray& in_buff, BinaryArray& buff_out, CryptoNoteConnectionContext& context, bool& handled);
|
||||||
virtual size_t getPeerCount() const;
|
virtual size_t getPeerCount() const override;
|
||||||
virtual uint32_t getObservedHeight() const;
|
virtual uint32_t getObservedHeight() const override;
|
||||||
void requestMissingPoolTransactions(const CryptoNoteConnectionContext& context);
|
void requestMissingPoolTransactions(const CryptoNoteConnectionContext& context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -41,7 +41,7 @@ const char* getErrorBody(CryptoNote::HttpResponse::HTTP_STATUS status) {
|
||||||
case CryptoNote::HttpResponse::STATUS_404:
|
case CryptoNote::HttpResponse::STATUS_404:
|
||||||
return "Requested url is not found\n";
|
return "Requested url is not found\n";
|
||||||
case CryptoNote::HttpResponse::STATUS_500:
|
case CryptoNote::HttpResponse::STATUS_500:
|
||||||
return "Internal server error is occured\n";
|
return "Internal server error is occurred\n";
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Error body for given status is not available");
|
throw std::runtime_error("Error body for given status is not available");
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,9 @@ public:
|
||||||
virtual bool addObserver(INodeObserver* observer) override;
|
virtual bool addObserver(INodeObserver* observer) override;
|
||||||
virtual bool removeObserver(INodeObserver* observer) override;
|
virtual bool removeObserver(INodeObserver* observer) override;
|
||||||
|
|
||||||
virtual size_t getPeerCount() const;
|
virtual size_t getPeerCount() const override;
|
||||||
virtual uint32_t getLastLocalBlockHeight() const;
|
virtual uint32_t getLastLocalBlockHeight() const override;
|
||||||
virtual uint32_t getLastKnownBlockHeight() const;
|
virtual uint32_t getLastKnownBlockHeight() const override;
|
||||||
virtual uint32_t getLocalBlockCount() const override;
|
virtual uint32_t getLocalBlockCount() const override;
|
||||||
virtual uint32_t getKnownBlockCount() const override;
|
virtual uint32_t getKnownBlockCount() const override;
|
||||||
virtual uint64_t getLastLocalBlockTimestamp() const override;
|
virtual uint64_t getLastLocalBlockTimestamp() const override;
|
||||||
|
|
|
@ -48,25 +48,25 @@ public:
|
||||||
NodeRpcProxy(const std::string& nodeHost, unsigned short nodePort);
|
NodeRpcProxy(const std::string& nodeHost, unsigned short nodePort);
|
||||||
virtual ~NodeRpcProxy();
|
virtual ~NodeRpcProxy();
|
||||||
|
|
||||||
virtual bool addObserver(CryptoNote::INodeObserver* observer);
|
virtual bool addObserver(CryptoNote::INodeObserver* observer) override;
|
||||||
virtual bool removeObserver(CryptoNote::INodeObserver* observer);
|
virtual bool removeObserver(CryptoNote::INodeObserver* observer) override;
|
||||||
|
|
||||||
virtual bool addObserver(CryptoNote::INodeRpcProxyObserver* observer);
|
virtual bool addObserver(CryptoNote::INodeRpcProxyObserver* observer);
|
||||||
virtual bool removeObserver(CryptoNote::INodeRpcProxyObserver* observer);
|
virtual bool removeObserver(CryptoNote::INodeRpcProxyObserver* observer);
|
||||||
|
|
||||||
virtual void init(const Callback& callback);
|
virtual void init(const Callback& callback) override;
|
||||||
virtual bool shutdown();
|
virtual bool shutdown() override;
|
||||||
|
|
||||||
virtual size_t getPeerCount() const;
|
virtual size_t getPeerCount() const override;
|
||||||
virtual uint32_t getLastLocalBlockHeight() const;
|
virtual uint32_t getLastLocalBlockHeight() const override;
|
||||||
virtual uint32_t getLastKnownBlockHeight() const;
|
virtual uint32_t getLastKnownBlockHeight() const override;
|
||||||
virtual uint32_t getLocalBlockCount() const override;
|
virtual uint32_t getLocalBlockCount() const override;
|
||||||
virtual uint32_t getKnownBlockCount() const override;
|
virtual uint32_t getKnownBlockCount() const override;
|
||||||
virtual uint64_t getLastLocalBlockTimestamp() const override;
|
virtual uint64_t getLastLocalBlockTimestamp() const override;
|
||||||
|
|
||||||
virtual void relayTransaction(const CryptoNote::Transaction& transaction, const Callback& callback);
|
virtual void relayTransaction(const CryptoNote::Transaction& transaction, const Callback& callback) override;
|
||||||
virtual void getRandomOutsByAmounts(std::vector<uint64_t>&& amounts, uint64_t outsCount, std::vector<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount>& result, const Callback& callback);
|
virtual void getRandomOutsByAmounts(std::vector<uint64_t>&& amounts, uint64_t outsCount, std::vector<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount>& result, const Callback& callback) override;
|
||||||
virtual void getNewBlocks(std::vector<Crypto::Hash>&& knownBlockIds, std::vector<CryptoNote::block_complete_entry>& newBlocks, uint32_t& startHeight, const Callback& callback);
|
virtual void getNewBlocks(std::vector<Crypto::Hash>&& knownBlockIds, std::vector<CryptoNote::block_complete_entry>& newBlocks, uint32_t& startHeight, const Callback& callback) override;
|
||||||
virtual void getTransactionOutsGlobalIndices(const Crypto::Hash& transactionHash, std::vector<uint32_t>& outsGlobalIndices, const Callback& callback) override;
|
virtual void getTransactionOutsGlobalIndices(const Crypto::Hash& transactionHash, std::vector<uint32_t>& outsGlobalIndices, const Callback& callback) override;
|
||||||
virtual void queryBlocks(std::vector<Crypto::Hash>&& knownBlockIds, uint64_t timestamp, std::vector<BlockShortEntry>& newBlocks, uint32_t& startHeight, const Callback& callback) override;
|
virtual void queryBlocks(std::vector<Crypto::Hash>&& knownBlockIds, uint64_t timestamp, std::vector<BlockShortEntry>& newBlocks, uint32_t& startHeight, const Callback& callback) override;
|
||||||
virtual void getPoolSymmetricDifference(std::vector<Crypto::Hash>&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual,
|
virtual void getPoolSymmetricDifference(std::vector<Crypto::Hash>&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual,
|
||||||
|
|
|
@ -80,6 +80,7 @@ NetNodeConfig::NetNodeConfig() {
|
||||||
allowLocalIp = false;
|
allowLocalIp = false;
|
||||||
hideMyPort = false;
|
hideMyPort = false;
|
||||||
configFolder = Tools::getDefaultDataDirectory();
|
configFolder = Tools::getDefaultDataDirectory();
|
||||||
|
testnet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetNodeConfig::init(const boost::program_options::variables_map& vm)
|
bool NetNodeConfig::init(const boost::program_options::variables_map& vm)
|
||||||
|
|
|
@ -70,7 +70,7 @@ private:
|
||||||
bool hideMyPort;
|
bool hideMyPort;
|
||||||
std::string configFolder;
|
std::string configFolder;
|
||||||
std::string p2pStateFilename;
|
std::string p2pStateFilename;
|
||||||
bool testnet = false;
|
bool testnet;
|
||||||
};
|
};
|
||||||
|
|
||||||
} //namespace nodetool
|
} //namespace nodetool
|
||||||
|
|
|
@ -26,13 +26,13 @@ namespace PaymentService {
|
||||||
class NodeRpcStub: public CryptoNote::INode {
|
class NodeRpcStub: public CryptoNote::INode {
|
||||||
public:
|
public:
|
||||||
virtual ~NodeRpcStub() {}
|
virtual ~NodeRpcStub() {}
|
||||||
virtual bool addObserver(CryptoNote::INodeObserver* observer) { return true; }
|
virtual bool addObserver(CryptoNote::INodeObserver* observer) override { return true; }
|
||||||
virtual bool removeObserver(CryptoNote::INodeObserver* observer) { return true; }
|
virtual bool removeObserver(CryptoNote::INodeObserver* observer) override { return true; }
|
||||||
|
|
||||||
virtual void init(const Callback& callback) { }
|
virtual void init(const Callback& callback) override { }
|
||||||
virtual bool shutdown() { return true; }
|
virtual bool shutdown() override { return true; }
|
||||||
|
|
||||||
virtual size_t getPeerCount() const { return 0; }
|
virtual size_t getPeerCount() const override { return 0; }
|
||||||
virtual uint32_t getLastLocalBlockHeight() const override { return 0; }
|
virtual uint32_t getLastLocalBlockHeight() const override { return 0; }
|
||||||
virtual uint32_t getLastKnownBlockHeight() const override { return 0; }
|
virtual uint32_t getLastKnownBlockHeight() const override { return 0; }
|
||||||
virtual uint32_t getLocalBlockCount() const override { return 0; }
|
virtual uint32_t getLocalBlockCount() const override { return 0; }
|
||||||
|
@ -56,7 +56,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void getPoolSymmetricDifference(std::vector<Crypto::Hash>&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual,
|
virtual void getPoolSymmetricDifference(std::vector<Crypto::Hash>&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual,
|
||||||
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>>& newTxs, std::vector<Crypto::Hash>& deletedTxIds, const Callback& callback) {
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>>& newTxs, std::vector<Crypto::Hash>& deletedTxIds, const Callback& callback) override {
|
||||||
isBcActual = true;
|
isBcActual = true;
|
||||||
callback(std::error_code());
|
callback(std::error_code());
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,7 @@ void TransactionRpcInfo::serialize(CryptoNote::ISerializer& serializer) {
|
||||||
serializer(fee, "fee");
|
serializer(fee, "fee");
|
||||||
serializer(hash, "hash");
|
serializer(hash, "hash");
|
||||||
serializer(blockHeight, "block_height");
|
serializer(blockHeight, "block_height");
|
||||||
|
serializer(state, "state");
|
||||||
serializer(timestamp, "timestamp");
|
serializer(timestamp, "timestamp");
|
||||||
serializer(extra, "extra");
|
serializer(extra, "extra");
|
||||||
serializer(transfers, "transfers");
|
serializer(transfers, "transfers");
|
||||||
|
@ -154,6 +155,7 @@ void ListTransactionsResponse::serialize(CryptoNote::ISerializer& serializer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransferRpcInfo::serialize(CryptoNote::ISerializer& serializer) {
|
void TransferRpcInfo::serialize(CryptoNote::ISerializer& serializer) {
|
||||||
|
serializer(type, "type");
|
||||||
serializer(address, "address");
|
serializer(address, "address");
|
||||||
serializer(amount, "amount");
|
serializer(amount, "amount");
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,7 @@ struct GetTransactionRequest {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TransferRpcInfo {
|
struct TransferRpcInfo {
|
||||||
|
uint8_t type;
|
||||||
std::string address;
|
std::string address;
|
||||||
int64_t amount;
|
int64_t amount;
|
||||||
|
|
||||||
|
@ -152,6 +153,7 @@ struct TransactionRpcInfo {
|
||||||
uint64_t blockHeight;
|
uint64_t blockHeight;
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
std::string extra;
|
std::string extra;
|
||||||
|
uint8_t state;
|
||||||
std::vector<TransferRpcInfo> transfers;
|
std::vector<TransferRpcInfo> transfers;
|
||||||
|
|
||||||
void serialize(CryptoNote::ISerializer& serializer);
|
void serialize(CryptoNote::ISerializer& serializer);
|
||||||
|
|
|
@ -240,8 +240,8 @@ void WalletService::loadWallet() {
|
||||||
|
|
||||||
void WalletService::loadPaymentsCacheAndTransferIndices() {
|
void WalletService::loadPaymentsCacheAndTransferIndices() {
|
||||||
size_t txCount = wallet->getTransactionCount();
|
size_t txCount = wallet->getTransactionCount();
|
||||||
transfersIndices.resize(1);
|
transfersIndices.reserve(txCount + 1);
|
||||||
transfersIndices[0] = 0;
|
transfersIndices.push_back(0);
|
||||||
|
|
||||||
logger(Logging::DEBUGGING) << "seeking for payments among " << txCount << " transactions";
|
logger(Logging::DEBUGGING) << "seeking for payments among " << txCount << " transactions";
|
||||||
|
|
||||||
|
@ -273,18 +273,18 @@ std::error_code WalletService::sendTransaction(const SendTransactionRequest& req
|
||||||
logger(Logging::DEBUGGING) << "Send transaction request came";
|
logger(Logging::DEBUGGING) << "Send transaction request came";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::vector<CryptoNote::WalletTransfer> transfers;
|
std::vector<CryptoNote::WalletOrder> orders;
|
||||||
makeTransfers(req.destinations, transfers);
|
makeOrders(req.destinations, orders);
|
||||||
|
|
||||||
std::string extra;
|
std::string extra;
|
||||||
if (!req.paymentId.empty()) {
|
if (!req.paymentId.empty()) {
|
||||||
addPaymentIdToExtra(req.paymentId, extra);
|
addPaymentIdToExtra(req.paymentId, extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t txId = wallet->transfer(transfers, req.fee, req.mixin, extra, req.unlockTime);
|
size_t txId = wallet->transfer(orders, req.fee, req.mixin, extra, req.unlockTime);
|
||||||
if (txId == CryptoNote::WALLET_INVALID_TRANSACTION_ID) {
|
if (txId == CryptoNote::WALLET_INVALID_TRANSACTION_ID) {
|
||||||
logger(Logging::WARNING) << "Unable to send transaction";
|
logger(Logging::WARNING) << "Unable to send transaction";
|
||||||
throw std::runtime_error("Error occured while sending transaction");
|
throw std::runtime_error("Error occurred while sending transaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.transactionId = txId;
|
resp.transactionId = txId;
|
||||||
|
@ -296,11 +296,11 @@ std::error_code WalletService::sendTransaction(const SendTransactionRequest& req
|
||||||
return std::error_code();
|
return std::error_code();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletService::makeTransfers(const std::vector<PaymentService::TransferDestination>& destinations, std::vector<CryptoNote::WalletTransfer>& transfers) {
|
void WalletService::makeOrders(const std::vector<PaymentService::TransferDestination>& destinations, std::vector<CryptoNote::WalletOrder>& orders) {
|
||||||
transfers.reserve(destinations.size());
|
orders.reserve(destinations.size());
|
||||||
|
|
||||||
for (auto dest: destinations) {
|
for (auto dest: destinations) {
|
||||||
transfers.push_back( { dest.address, static_cast<int64_t>(dest.amount) } );
|
orders.push_back( { dest.address, dest.amount } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +429,8 @@ std::error_code WalletService::getTransactionByTransferId(size_t transferId, siz
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nextTxId = std::upper_bound(transfersIndices.begin(), transfersIndices.end(), transferId);
|
auto nextTxId = std::upper_bound(transfersIndices.begin(), transfersIndices.end(), transferId);
|
||||||
transactionId = (nextTxId - transfersIndices.begin()) - 1;
|
assert(nextTxId != transfersIndices.begin());
|
||||||
|
transactionId = std::distance(transfersIndices.begin(), nextTxId) - 1;
|
||||||
|
|
||||||
return std::error_code();
|
return std::error_code();
|
||||||
}
|
}
|
||||||
|
@ -443,9 +444,10 @@ void WalletService::fillTransactionRpcInfo(size_t txId, const CryptoNote::Wallet
|
||||||
rpcInfo.timestamp = tx.timestamp;
|
rpcInfo.timestamp = tx.timestamp;
|
||||||
rpcInfo.extra = Common::toHex(tx.extra.data(), tx.extra.size());
|
rpcInfo.extra = Common::toHex(tx.extra.data(), tx.extra.size());
|
||||||
rpcInfo.hash = Common::podToHex(tx.hash);
|
rpcInfo.hash = Common::podToHex(tx.hash);
|
||||||
|
rpcInfo.state = static_cast<uint8_t>(tx.state);
|
||||||
for (size_t transferId = 0; transferId < rpcInfo.transferCount; ++transferId) {
|
for (size_t transferId = 0; transferId < rpcInfo.transferCount; ++transferId) {
|
||||||
auto transfer = wallet->getTransactionTransfer(txId, transferId);
|
auto transfer = wallet->getTransactionTransfer(txId, transferId);
|
||||||
TransferRpcInfo rpcTransfer{ transfer.address, transfer.amount };
|
TransferRpcInfo rpcTransfer{ static_cast<uint8_t>(transfer.type), transfer.address, transfer.amount };
|
||||||
rpcInfo.transfers.push_back(rpcTransfer);
|
rpcInfo.transfers.push_back(rpcTransfer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,7 +512,9 @@ std::error_code WalletService::getTransfer(size_t globalTransferId, bool& found,
|
||||||
logger(Logging::DEBUGGING) << "getTransfer request came";
|
logger(Logging::DEBUGGING) << "getTransfer request came";
|
||||||
found = false;
|
found = false;
|
||||||
try {
|
try {
|
||||||
size_t txId = (std::upper_bound(transfersIndices.begin(), transfersIndices.end(), globalTransferId) - transfersIndices.begin()) - 1;
|
auto nextTxIt = std::upper_bound(transfersIndices.begin(), transfersIndices.end(), globalTransferId);
|
||||||
|
assert(nextTxIt != transfersIndices.begin());
|
||||||
|
size_t txId = std::distance(transfersIndices.begin(), nextTxIt) - 1;
|
||||||
size_t fakeTxId = transfersIndices.size() - 1;
|
size_t fakeTxId = transfersIndices.size() - 1;
|
||||||
|
|
||||||
if (txId == fakeTxId) {
|
if (txId == fakeTxId) {
|
||||||
|
@ -520,6 +524,7 @@ std::error_code WalletService::getTransfer(size_t globalTransferId, bool& found,
|
||||||
auto transferId = globalTransferId - transfersIndices[txId];
|
auto transferId = globalTransferId - transfersIndices[txId];
|
||||||
auto transfer = wallet->getTransactionTransfer(txId, transferId);
|
auto transfer = wallet->getTransactionTransfer(txId, transferId);
|
||||||
|
|
||||||
|
rpcInfo.type = static_cast<uint8_t>(transfer.type);
|
||||||
rpcInfo.address = transfer.address;
|
rpcInfo.address = transfer.address;
|
||||||
rpcInfo.amount = transfer.amount;
|
rpcInfo.amount = transfer.amount;
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -572,12 +577,22 @@ void WalletService::refresh() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto event = wallet->getEvent();
|
auto event = wallet->getEvent();
|
||||||
if (event.type == CryptoNote::TRANSACTION_CREATED || event.type == CryptoNote::TRANSACTION_UPDATED) {
|
if (event.type == CryptoNote::TRANSACTION_CREATED || event.type == CryptoNote::TRANSACTION_UPDATED) {
|
||||||
size_t transactionId;
|
size_t transactionId = event.transactionCreated.transactionIndex;
|
||||||
|
size_t transferCount = wallet->getTransactionTransferCount(transactionId);
|
||||||
|
|
||||||
if (event.type == CryptoNote::TRANSACTION_CREATED) {
|
if (event.type == CryptoNote::TRANSACTION_CREATED) {
|
||||||
transactionId = event.transactionCreated.transactionIndex;
|
assert(transactionId == transfersIndices.size() - 1);
|
||||||
transfersIndices.push_back(transfersIndices[transactionId] + wallet->getTransactionTransferCount(transactionId));
|
transfersIndices.push_back(transfersIndices[transactionId] + transferCount);
|
||||||
} else {
|
} else {
|
||||||
transactionId = event.transactionUpdated.transactionIndex;
|
assert(event.type == CryptoNote::TRANSACTION_UPDATED);
|
||||||
|
assert(transactionId < transfersIndices.size() - 1);
|
||||||
|
size_t oldTransferCount = transfersIndices[transactionId + 1] - transfersIndices[transactionId];
|
||||||
|
int change = static_cast<int>(transferCount) - static_cast<int>(oldTransferCount);
|
||||||
|
if (change != 0) {
|
||||||
|
for (size_t i = transactionId + 1; i < transfersIndices.size(); ++i) {
|
||||||
|
transfersIndices[i] = static_cast<size_t>(static_cast<int>(transfersIndices[i]) + change);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tx = wallet->getTransaction(transactionId);
|
auto tx = wallet->getTransaction(transactionId);
|
||||||
|
|
|
@ -83,7 +83,7 @@ private:
|
||||||
void insertTransaction(size_t id, const Crypto::Hash& paymentIdBin, bool confirmed);
|
void insertTransaction(size_t id, const Crypto::Hash& paymentIdBin, bool confirmed);
|
||||||
|
|
||||||
void fillTransactionRpcInfo(size_t txId, const CryptoNote::WalletTransaction& tx, TransactionRpcInfo& rpcInfo);
|
void fillTransactionRpcInfo(size_t txId, const CryptoNote::WalletTransaction& tx, TransactionRpcInfo& rpcInfo);
|
||||||
void makeTransfers(const std::vector<TransferDestination>& destinations, std::vector<CryptoNote::WalletTransfer>& transfers);
|
void makeOrders(const std::vector<TransferDestination>& destinations, std::vector<CryptoNote::WalletOrder>& transfers);
|
||||||
|
|
||||||
struct PaymentItem {
|
struct PaymentItem {
|
||||||
std::string paymentId;
|
std::string paymentId;
|
||||||
|
|
|
@ -39,13 +39,13 @@ bool ConfigurationManager::init(int argc, char** argv) {
|
||||||
|
|
||||||
po::options_description confGeneralOptions;
|
po::options_description confGeneralOptions;
|
||||||
confGeneralOptions.add(cmdGeneralOptions).add_options()
|
confGeneralOptions.add(cmdGeneralOptions).add_options()
|
||||||
("testnet", po::value<bool>(), "")
|
("testnet", po::bool_switch(), "")
|
||||||
("local", po::value<bool>(), "");
|
("local", po::bool_switch(), "");
|
||||||
|
|
||||||
cmdGeneralOptions.add_options()
|
cmdGeneralOptions.add_options()
|
||||||
("help,h", "produce this help message and exit")
|
("help,h", "produce this help message and exit")
|
||||||
("local", "start with local node (remote is default)")
|
("local", po::bool_switch(), "start with local node (remote is default)")
|
||||||
("testnet", "testnet mode");
|
("testnet", po::bool_switch(), "testnet mode");
|
||||||
|
|
||||||
command_line::add_arg(cmdGeneralOptions, command_line::arg_data_dir, Tools::getDefaultDataDirectory());
|
command_line::add_arg(cmdGeneralOptions, command_line::arg_data_dir, Tools::getDefaultDataDirectory());
|
||||||
command_line::add_arg(confGeneralOptions, command_line::arg_data_dir, Tools::getDefaultDataDirectory());
|
command_line::add_arg(confGeneralOptions, command_line::arg_data_dir, Tools::getDefaultDataDirectory());
|
||||||
|
@ -90,9 +90,8 @@ bool ConfigurationManager::init(int argc, char** argv) {
|
||||||
coreConfig.init(confOptions);
|
coreConfig.init(confOptions);
|
||||||
remoteNodeConfig.init(confOptions);
|
remoteNodeConfig.init(confOptions);
|
||||||
|
|
||||||
if (confOptions.count("local")) {
|
netNodeConfig.setTestnet(confOptions["testnet"].as<bool>());
|
||||||
startInprocess = confOptions["local"].as<bool>();
|
startInprocess = confOptions["local"].as<bool>();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//command line options should override options from config file
|
//command line options should override options from config file
|
||||||
|
@ -101,7 +100,11 @@ bool ConfigurationManager::init(int argc, char** argv) {
|
||||||
coreConfig.init(cmdOptions);
|
coreConfig.init(cmdOptions);
|
||||||
remoteNodeConfig.init(cmdOptions);
|
remoteNodeConfig.init(cmdOptions);
|
||||||
|
|
||||||
if (cmdOptions.count("local")) {
|
if (cmdOptions["testnet"].as<bool>()) {
|
||||||
|
netNodeConfig.setTestnet(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdOptions["local"].as<bool>()) {
|
||||||
startInprocess = true;
|
startInprocess = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ void PaymentGateService::runInProcess(Logging::LoggerRef& log) {
|
||||||
|
|
||||||
node->init([&initPromise, &log](std::error_code ec) {
|
node->init([&initPromise, &log](std::error_code ec) {
|
||||||
if (ec) {
|
if (ec) {
|
||||||
log(Logging::INFO) << "Failed to init node: " << ec.message();
|
log(Logging::WARNING, Logging::YELLOW) << "Failed to init node: " << ec.message();
|
||||||
} else {
|
} else {
|
||||||
log(Logging::INFO) << "node is inited successfully";
|
log(Logging::INFO) << "node is inited successfully";
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,7 @@ void PaymentGateService::runWalletService(const CryptoNote::Currency& currency,
|
||||||
try {
|
try {
|
||||||
service->init();
|
service->init();
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
Logging::LoggerRef(logger, "run")(Logging::ERROR) << "Failed to init walletService reason: " << e.what();
|
Logging::LoggerRef(logger, "run")(Logging::ERROR, Logging::BRIGHT_RED) << "Failed to init walletService reason: " << e.what();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ void PaymentGateService::runWalletService(const CryptoNote::Currency& currency,
|
||||||
try {
|
try {
|
||||||
service->saveWallet();
|
service->saveWallet();
|
||||||
} catch (std::exception& ex) {
|
} catch (std::exception& ex) {
|
||||||
Logging::LoggerRef(logger, "saveWallet")(Logging::WARNING) << "Couldn't save wallet: " << ex.what();
|
Logging::LoggerRef(logger, "saveWallet")(Logging::WARNING, Logging::YELLOW) << "Couldn't save wallet: " << ex.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ void Configuration::init(const boost::program_options::variables_map& options) {
|
||||||
throw ConfigurationError("It's impossible to use both \"register-service\" and \"unregister-service\" at the same time");
|
throw ConfigurationError("It's impossible to use both \"register-service\" and \"unregister-service\" at the same time");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.count("testnet") != 0) {
|
if (options["testnet"].as<bool>()) {
|
||||||
testnet = true;
|
testnet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ std::string GetLastErrorMessage(DWORD errorMessageID)
|
||||||
void __stdcall serviceHandler(DWORD fdwControl) {
|
void __stdcall serviceHandler(DWORD fdwControl) {
|
||||||
if (fdwControl == SERVICE_CONTROL_STOP) {
|
if (fdwControl == SERVICE_CONTROL_STOP) {
|
||||||
Logging::LoggerRef log(ppg->getLogger(), "serviceHandler");
|
Logging::LoggerRef log(ppg->getLogger(), "serviceHandler");
|
||||||
log(Logging::INFO) << "Stop signal caught";
|
log(Logging::INFO, Logging::BRIGHT_YELLOW) << "Stop signal caught";
|
||||||
|
|
||||||
SERVICE_STATUS serviceStatus{ SERVICE_WIN32_OWN_PROCESS, SERVICE_STOP_PENDING, 0, NO_ERROR, 0, 0, 0 };
|
SERVICE_STATUS serviceStatus{ SERVICE_WIN32_OWN_PROCESS, SERVICE_STOP_PENDING, 0, NO_ERROR, 0, 0, 0 };
|
||||||
SetServiceStatus(serviceStatusHandle, &serviceStatus);
|
SetServiceStatus(serviceStatusHandle, &serviceStatus);
|
||||||
|
@ -73,26 +73,26 @@ void __stdcall serviceMain(DWORD dwArgc, char **lpszArgv) {
|
||||||
|
|
||||||
serviceStatusHandle = RegisterServiceCtrlHandler("PaymentGate", serviceHandler);
|
serviceStatusHandle = RegisterServiceCtrlHandler("PaymentGate", serviceHandler);
|
||||||
if (serviceStatusHandle == NULL) {
|
if (serviceStatusHandle == NULL) {
|
||||||
logRef(Logging::FATAL) << "Couldn't make RegisterServiceCtrlHandler call: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't make RegisterServiceCtrlHandler call: " << GetLastErrorMessage(GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SERVICE_STATUS serviceStatus{ SERVICE_WIN32_OWN_PROCESS, SERVICE_START_PENDING, 0, NO_ERROR, 0, 1, 3000 };
|
SERVICE_STATUS serviceStatus{ SERVICE_WIN32_OWN_PROCESS, SERVICE_START_PENDING, 0, NO_ERROR, 0, 1, 3000 };
|
||||||
if (SetServiceStatus(serviceStatusHandle, &serviceStatus) != TRUE) {
|
if (SetServiceStatus(serviceStatusHandle, &serviceStatus) != TRUE) {
|
||||||
logRef(Logging::FATAL) << "Couldn't make SetServiceStatus call: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't make SetServiceStatus call: " << GetLastErrorMessage(GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceStatus = { SERVICE_WIN32_OWN_PROCESS, SERVICE_RUNNING, SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0 };
|
serviceStatus = { SERVICE_WIN32_OWN_PROCESS, SERVICE_RUNNING, SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0 };
|
||||||
if (SetServiceStatus(serviceStatusHandle, &serviceStatus) != TRUE) {
|
if (SetServiceStatus(serviceStatusHandle, &serviceStatus) != TRUE) {
|
||||||
logRef(Logging::FATAL) << "Couldn't make SetServiceStatus call: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't make SetServiceStatus call: " << GetLastErrorMessage(GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ppg->run();
|
ppg->run();
|
||||||
} catch (std::exception& ex) {
|
} catch (std::exception& ex) {
|
||||||
logRef(Logging::FATAL) << "Error occured: " << ex.what();
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Error occurred: " << ex.what();
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceStatus = { SERVICE_WIN32_OWN_PROCESS, SERVICE_STOPPED, 0, NO_ERROR, 0, 0, 0 };
|
serviceStatus = { SERVICE_WIN32_OWN_PROCESS, SERVICE_STOPPED, 0, NO_ERROR, 0, 0, 0 };
|
||||||
|
@ -138,10 +138,14 @@ int runDaemon() {
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Logging::LoggerRef logRef(ppg->getLogger(), "RunService");
|
||||||
|
|
||||||
if (StartServiceCtrlDispatcher(serviceTable) != TRUE) {
|
if (StartServiceCtrlDispatcher(serviceTable) != TRUE) {
|
||||||
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't start service: " << GetLastErrorMessage(GetLastError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logRef(Logging::INFO) << "Service stopped";
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -151,7 +155,7 @@ int runDaemon() {
|
||||||
//parent
|
//parent
|
||||||
return 0;
|
return 0;
|
||||||
} else if (daemonResult < 0) {
|
} else if (daemonResult < 0) {
|
||||||
//error occured
|
//error occurred
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +178,7 @@ int registerService() {
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (GetModuleFileName(NULL, pathBuff, ARRAYSIZE(pathBuff)) == 0) {
|
if (GetModuleFileName(NULL, pathBuff, ARRAYSIZE(pathBuff)) == 0) {
|
||||||
logRef(Logging::FATAL) << "GetModuleFileName failed with error: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "GetModuleFileName failed with error: " << GetLastErrorMessage(GetLastError());
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +190,7 @@ int registerService() {
|
||||||
|
|
||||||
scManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
|
scManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
|
||||||
if (scManager == NULL) {
|
if (scManager == NULL) {
|
||||||
logRef(Logging::FATAL) << "OpenSCManager failed with error: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "OpenSCManager failed with error: " << GetLastErrorMessage(GetLastError());
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +199,7 @@ int registerService() {
|
||||||
SERVICE_ERROR_NORMAL, modulePath.c_str(), NULL, NULL, NULL, NULL, NULL);
|
SERVICE_ERROR_NORMAL, modulePath.c_str(), NULL, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
if (scService == NULL) {
|
if (scService == NULL) {
|
||||||
logRef(Logging::FATAL) << "CreateService failed with error: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "CreateService failed with error: " << GetLastErrorMessage(GetLastError());
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -231,14 +235,14 @@ int unregisterService() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
scManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
scManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
||||||
if (scManager == NULL) {
|
if (scManager == NULL) {
|
||||||
logRef(Logging::FATAL) << "OpenSCManager failed with error: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "OpenSCManager failed with error: " << GetLastErrorMessage(GetLastError());
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
scService = OpenService(scManager, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
|
scService = OpenService(scManager, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
|
||||||
if (scService == NULL) {
|
if (scService == NULL) {
|
||||||
logRef(Logging::FATAL) << "OpenService failed with error: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "OpenService failed with error: " << GetLastErrorMessage(GetLastError());
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -260,12 +264,12 @@ int unregisterService() {
|
||||||
if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED) {
|
if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED) {
|
||||||
logRef(Logging::INFO) << SERVICE_NAME << " is stopped";
|
logRef(Logging::INFO) << SERVICE_NAME << " is stopped";
|
||||||
} else {
|
} else {
|
||||||
logRef(Logging::FATAL) << SERVICE_NAME << " failed to stop" << std::endl;
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << SERVICE_NAME << " failed to stop" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DeleteService(scService)) {
|
if (!DeleteService(scService)) {
|
||||||
logRef(Logging::FATAL) << "DeleteService failed with error: " << GetLastErrorMessage(GetLastError());
|
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "DeleteService failed with error: " << GetLastErrorMessage(GetLastError());
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
BinaryInputStreamSerializer(Common::IInputStream& strm) : stream(strm) {}
|
BinaryInputStreamSerializer(Common::IInputStream& strm) : stream(strm) {}
|
||||||
virtual ~BinaryInputStreamSerializer() {}
|
virtual ~BinaryInputStreamSerializer() {}
|
||||||
|
|
||||||
virtual ISerializer::SerializerType type() const;
|
virtual ISerializer::SerializerType type() const override;
|
||||||
|
|
||||||
virtual bool beginObject(Common::StringView name) override;
|
virtual bool beginObject(Common::StringView name) override;
|
||||||
virtual void endObject() override;
|
virtual void endObject() override;
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
BinaryOutputStreamSerializer(Common::IOutputStream& strm) : stream(strm) {}
|
BinaryOutputStreamSerializer(Common::IOutputStream& strm) : stream(strm) {}
|
||||||
virtual ~BinaryOutputStreamSerializer() {}
|
virtual ~BinaryOutputStreamSerializer() {}
|
||||||
|
|
||||||
virtual ISerializer::SerializerType type() const;
|
virtual ISerializer::SerializerType type() const override;
|
||||||
|
|
||||||
virtual bool beginObject(Common::StringView name) override;
|
virtual bool beginObject(Common::StringView name) override;
|
||||||
virtual void endObject() override;
|
virtual void endObject() override;
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
JsonInputValueSerializer(Common::JsonValue&& value);
|
JsonInputValueSerializer(Common::JsonValue&& value);
|
||||||
virtual ~JsonInputValueSerializer();
|
virtual ~JsonInputValueSerializer();
|
||||||
|
|
||||||
SerializerType type() const;
|
SerializerType type() const override;
|
||||||
|
|
||||||
virtual bool beginObject(Common::StringView name) override;
|
virtual bool beginObject(Common::StringView name) override;
|
||||||
virtual void endObject() override;
|
virtual void endObject() override;
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
JsonOutputStreamSerializer();
|
JsonOutputStreamSerializer();
|
||||||
virtual ~JsonOutputStreamSerializer();
|
virtual ~JsonOutputStreamSerializer();
|
||||||
|
|
||||||
SerializerType type() const;
|
SerializerType type() const override;
|
||||||
|
|
||||||
virtual bool beginObject(Common::StringView name) override;
|
virtual bool beginObject(Common::StringView name) override;
|
||||||
virtual void endObject() override;
|
virtual void endObject() override;
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
|
|
||||||
void dump(Common::IOutputStream& target);
|
void dump(Common::IOutputStream& target);
|
||||||
|
|
||||||
virtual ISerializer::SerializerType type() const;
|
virtual ISerializer::SerializerType type() const override;
|
||||||
|
|
||||||
virtual bool beginObject(Common::StringView name) override;
|
virtual bool beginObject(Common::StringView name) override;
|
||||||
virtual void endObject() override;
|
virtual void endObject() override;
|
||||||
|
|
|
@ -464,7 +464,8 @@ simple_wallet::simple_wallet(System::Dispatcher& dispatcher, const CryptoNote::C
|
||||||
logManager(log),
|
logManager(log),
|
||||||
logger(log, "simplewallet"),
|
logger(log, "simplewallet"),
|
||||||
m_refresh_progress_reporter(*this),
|
m_refresh_progress_reporter(*this),
|
||||||
m_initResultPromise(nullptr) {
|
m_initResultPromise(nullptr),
|
||||||
|
m_walletSynchronized(false) {
|
||||||
m_consoleHandler.setHandler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining [<number_of_threads>] - Start mining in daemon");
|
m_consoleHandler.setHandler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining [<number_of_threads>] - Start mining in daemon");
|
||||||
m_consoleHandler.setHandler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon");
|
m_consoleHandler.setHandler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon");
|
||||||
//m_consoleHandler.setHandler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance");
|
//m_consoleHandler.setHandler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance");
|
||||||
|
@ -734,8 +735,21 @@ bool simple_wallet::save(const std::vector<std::string> &args)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool simple_wallet::reset(const std::vector<std::string> &args) {
|
bool simple_wallet::reset(const std::vector<std::string> &args) {
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_walletSynchronizedMutex);
|
||||||
|
m_walletSynchronized = false;
|
||||||
|
}
|
||||||
|
|
||||||
m_wallet->reset();
|
m_wallet->reset();
|
||||||
success_msg_writer(true) << "Reset is complete successfully";
|
success_msg_writer(true) << "Reset completed successfully.";
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(m_walletSynchronizedMutex);
|
||||||
|
while (!m_walletSynchronized) {
|
||||||
|
m_walletSynchronizedCV.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,10 +828,6 @@ void simple_wallet::initCompleted(std::error_code result) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void simple_wallet::localBlockchainUpdated(uint32_t height) {
|
|
||||||
m_refresh_progress_reporter.update(height, false);
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
|
||||||
void simple_wallet::connectionStatusUpdated(bool connected) {
|
void simple_wallet::connectionStatusUpdated(bool connected) {
|
||||||
if (connected) {
|
if (connected) {
|
||||||
logger(INFO, GREEN) << "Wallet connected to daemon.";
|
logger(INFO, GREEN) << "Wallet connected to daemon.";
|
||||||
|
@ -854,6 +864,19 @@ void simple_wallet::externalTransactionCreated(CryptoNote::TransactionId transac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
void simple_wallet::synchronizationCompleted(std::error_code result) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_walletSynchronizedMutex);
|
||||||
|
m_walletSynchronized = true;
|
||||||
|
m_walletSynchronizedCV.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_wallet::synchronizationProgressUpdated(uint32_t current, uint32_t total) {
|
||||||
|
std::unique_lock<std::mutex> lock(m_walletSynchronizedMutex);
|
||||||
|
if (!m_walletSynchronized) {
|
||||||
|
m_refresh_progress_reporter.update(current, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::vector<std::string>()*/) {
|
bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::vector<std::string>()*/) {
|
||||||
success_msg_writer() << "available balance: " << m_currency.formatAmount(m_wallet->actualBalance()) <<
|
success_msg_writer() << "available balance: " << m_currency.formatAmount(m_wallet->actualBalance()) <<
|
||||||
", locked amount: " << m_currency.formatAmount(m_wallet->pendingBalance());
|
", locked amount: " << m_currency.formatAmount(m_wallet->pendingBalance());
|
||||||
|
@ -1010,6 +1033,15 @@ bool simple_wallet::transfer(const std::vector<std::string> &args) {
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool simple_wallet::run() {
|
bool simple_wallet::run() {
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_walletSynchronizedMutex);
|
||||||
|
while (!m_walletSynchronized) {
|
||||||
|
m_walletSynchronizedCV.wait(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
std::string addr_start = m_wallet->getAddress().substr(0, 6);
|
std::string addr_start = m_wallet->getAddress().substr(0, 6);
|
||||||
m_consoleHandler.start(false, "[wallet " + addr_start + "]: ", Common::Console::Color::BrightYellow);
|
m_consoleHandler.start(false, "[wallet " + addr_start + "]: ", Common::Console::Color::BrightYellow);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <condition_variable>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <boost/program_options/variables_map.hpp>
|
#include <boost/program_options/variables_map.hpp>
|
||||||
|
|
||||||
|
@ -95,13 +97,11 @@ namespace CryptoNote
|
||||||
|
|
||||||
void printConnectionError() const;
|
void printConnectionError() const;
|
||||||
|
|
||||||
//---------------- IWalletObserver -------------------------
|
//---------------- IWalletLegacyObserver -------------------------
|
||||||
virtual void initCompleted(std::error_code result) override;
|
virtual void initCompleted(std::error_code result) override;
|
||||||
virtual void externalTransactionCreated(CryptoNote::TransactionId transactionId) override;
|
virtual void externalTransactionCreated(CryptoNote::TransactionId transactionId) override;
|
||||||
//----------------------------------------------------------
|
virtual void synchronizationCompleted(std::error_code result) override;
|
||||||
|
virtual void synchronizationProgressUpdated(uint32_t current, uint32_t total) override;
|
||||||
//----------------- INodeObserver --------------------------
|
|
||||||
virtual void localBlockchainUpdated(uint32_t height) override;
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
|
||||||
//----------------- INodeRpcProxyObserver --------------------------
|
//----------------- INodeRpcProxyObserver --------------------------
|
||||||
|
@ -130,8 +130,7 @@ namespace CryptoNote
|
||||||
m_blockchain_height = (std::max)(m_blockchain_height, height);
|
m_blockchain_height = (std::max)(m_blockchain_height, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::chrono::milliseconds(1) < current_time - m_print_time || force)
|
if (std::chrono::milliseconds(1) < current_time - m_print_time || force) {
|
||||||
{
|
|
||||||
std::cout << "Height " << height << " of " << m_blockchain_height << '\r';
|
std::cout << "Height " << height << " of " << m_blockchain_height << '\r';
|
||||||
m_print_time = current_time;
|
m_print_time = current_time;
|
||||||
}
|
}
|
||||||
|
@ -140,17 +139,9 @@ namespace CryptoNote
|
||||||
private:
|
private:
|
||||||
void update_blockchain_height()
|
void update_blockchain_height()
|
||||||
{
|
{
|
||||||
std::string err;
|
|
||||||
uint64_t blockchain_height = m_simple_wallet.m_node->getLastLocalBlockHeight();
|
uint64_t blockchain_height = m_simple_wallet.m_node->getLastLocalBlockHeight();
|
||||||
if (err.empty())
|
m_blockchain_height = blockchain_height;
|
||||||
{
|
m_blockchain_height_update_time = std::chrono::system_clock::now();
|
||||||
m_blockchain_height = blockchain_height;
|
|
||||||
m_blockchain_height_update_time = std::chrono::system_clock::now();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to get current blockchain height: " << err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -182,5 +173,9 @@ namespace CryptoNote
|
||||||
std::unique_ptr<CryptoNote::NodeRpcProxy> m_node;
|
std::unique_ptr<CryptoNote::NodeRpcProxy> m_node;
|
||||||
std::unique_ptr<CryptoNote::IWalletLegacy> m_wallet;
|
std::unique_ptr<CryptoNote::IWalletLegacy> m_wallet;
|
||||||
refresh_progress_reporter_t m_refresh_progress_reporter;
|
refresh_progress_reporter_t m_refresh_progress_reporter;
|
||||||
|
|
||||||
|
bool m_walletSynchronized;
|
||||||
|
std::mutex m_walletSynchronizedMutex;
|
||||||
|
std::condition_variable m_walletSynchronizedCV;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,7 +372,7 @@ void BlockchainSynchronizer::processBlocks(GetBlocksResponse& response) {
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case UpdateConsumersResult::errorOccured:
|
case UpdateConsumersResult::errorOccurred:
|
||||||
if (setFutureStateIf(State::idle, std::bind(
|
if (setFutureStateIf(State::idle, std::bind(
|
||||||
[](State futureState) -> bool {
|
[](State futureState) -> bool {
|
||||||
return futureState != State::stopped;
|
return futureState != State::stopped;
|
||||||
|
@ -435,7 +435,7 @@ BlockchainSynchronizer::UpdateConsumersResult BlockchainSynchronizer::updateCons
|
||||||
static_cast<uint32_t>(interval.blocks.size()) - startOffset);
|
static_cast<uint32_t>(interval.blocks.size()) - startOffset);
|
||||||
smthChanged = true;
|
smthChanged = true;
|
||||||
} else {
|
} else {
|
||||||
return UpdateConsumersResult::errorOccured;
|
return UpdateConsumersResult::errorOccurred;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ private:
|
||||||
enum class UpdateConsumersResult {
|
enum class UpdateConsumersResult {
|
||||||
nothingChanged = 0,
|
nothingChanged = 0,
|
||||||
addedNewBlocks = 1,
|
addedNewBlocks = 1,
|
||||||
errorOccured = 2
|
errorOccurred = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
//void startSync();
|
//void startSync();
|
||||||
|
|
|
@ -45,7 +45,8 @@ enum WalletErrorCodes {
|
||||||
KEY_GENERATION_ERROR,
|
KEY_GENERATION_ERROR,
|
||||||
INDEX_OUT_OF_RANGE,
|
INDEX_OUT_OF_RANGE,
|
||||||
ADDRESS_ALREADY_EXISTS,
|
ADDRESS_ALREADY_EXISTS,
|
||||||
TRACKING_MODE
|
TRACKING_MODE,
|
||||||
|
WRONG_PARAMETERS
|
||||||
};
|
};
|
||||||
|
|
||||||
// custom category:
|
// custom category:
|
||||||
|
@ -66,7 +67,7 @@ public:
|
||||||
case NOT_INITIALIZED: return "Object was not initialized";
|
case NOT_INITIALIZED: return "Object was not initialized";
|
||||||
case WRONG_PASSWORD: return "The password is wrong";
|
case WRONG_PASSWORD: return "The password is wrong";
|
||||||
case ALREADY_INITIALIZED: return "The object is already initialized";
|
case ALREADY_INITIALIZED: return "The object is already initialized";
|
||||||
case INTERNAL_WALLET_ERROR: return "Internal error occured";
|
case INTERNAL_WALLET_ERROR: return "Internal error occurred";
|
||||||
case MIXIN_COUNT_TOO_BIG: return "MixIn count is too big";
|
case MIXIN_COUNT_TOO_BIG: return "MixIn count is too big";
|
||||||
case BAD_ADDRESS: return "Bad address";
|
case BAD_ADDRESS: return "Bad address";
|
||||||
case TRANSACTION_SIZE_TOO_BIG: return "Transaction size is too big";
|
case TRANSACTION_SIZE_TOO_BIG: return "Transaction size is too big";
|
||||||
|
@ -83,6 +84,7 @@ public:
|
||||||
case INDEX_OUT_OF_RANGE: return "Index is out of range";
|
case INDEX_OUT_OF_RANGE: return "Index is out of range";
|
||||||
case ADDRESS_ALREADY_EXISTS: return "Address already exists";
|
case ADDRESS_ALREADY_EXISTS: return "Address already exists";
|
||||||
case TRACKING_MODE: return "The wallet is in tracking mode";
|
case TRACKING_MODE: return "The wallet is in tracking mode";
|
||||||
|
case WRONG_PARAMETERS: return "Wrong parameters passed";
|
||||||
default: return "Unknown error";
|
default: return "Unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,6 +153,64 @@ size_t getTransactionSize(const ITransactionReader& transaction) {
|
||||||
return transaction.getTransactionData().size();
|
return transaction.getTransactionData().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<WalletTransfer> convertOrdersToTransfer(const std::vector<WalletOrder>& orders) {
|
||||||
|
std::vector<WalletTransfer> transfers;
|
||||||
|
transfers.reserve(orders.size());
|
||||||
|
|
||||||
|
for (const auto& order: orders) {
|
||||||
|
WalletTransfer transfer;
|
||||||
|
|
||||||
|
if (order.amount > std::numeric_limits<int64_t>::max()) {
|
||||||
|
throw std::system_error(make_error_code(CryptoNote::error::WRONG_AMOUNT),
|
||||||
|
"Order amount must not exceed " + std::to_string(std::numeric_limits<decltype(transfer.amount)>::max()));
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer.type = WalletTransferType::USUAL;
|
||||||
|
transfer.address = order.address;
|
||||||
|
transfer.amount = static_cast<int64_t>(order.amount);
|
||||||
|
|
||||||
|
transfers.emplace_back(std::move(transfer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return transfers;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t calculateDonationAmount(uint64_t freeAmount, uint64_t donationThreshold, uint64_t dustThreshold) {
|
||||||
|
std::vector<uint64_t> decomposedAmounts;
|
||||||
|
decomposeAmount(freeAmount, dustThreshold, decomposedAmounts);
|
||||||
|
|
||||||
|
std::sort(decomposedAmounts.begin(), decomposedAmounts.end(), std::greater<uint64_t>());
|
||||||
|
|
||||||
|
uint64_t donationAmount = 0;
|
||||||
|
for (auto amount: decomposedAmounts) {
|
||||||
|
if (amount > donationThreshold - donationAmount) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
donationAmount += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(donationAmount <= freeAmount);
|
||||||
|
return donationAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pushDonationTransferIfPossible(const DonationSettings& donation, uint64_t freeAmount, uint64_t dustThreshold, std::vector<WalletTransfer>& destinations) {
|
||||||
|
uint64_t donationAmount = 0;
|
||||||
|
if (!donation.address.empty() && donation.threshold != 0) {
|
||||||
|
if (donation.threshold > std::numeric_limits<int64_t>::max()) {
|
||||||
|
throw std::system_error(make_error_code(error::WRONG_AMOUNT),
|
||||||
|
"Donation threshold must not exceed " + std::to_string(std::numeric_limits<int64_t>::max()));
|
||||||
|
}
|
||||||
|
|
||||||
|
donationAmount = calculateDonationAmount(freeAmount, donation.threshold, dustThreshold);
|
||||||
|
if (donationAmount != 0) {
|
||||||
|
destinations.emplace_back(WalletTransfer {WalletTransferType::DONATION, donation.address, static_cast<int64_t>(donationAmount)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return donationAmount;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CryptoNote {
|
namespace CryptoNote {
|
||||||
|
@ -163,7 +221,7 @@ WalletGreen::WalletGreen(System::Dispatcher& dispatcher, const Currency& currenc
|
||||||
m_node(node),
|
m_node(node),
|
||||||
m_blockchainSynchronizer(node, currency.genesisBlockHash()),
|
m_blockchainSynchronizer(node, currency.genesisBlockHash()),
|
||||||
m_synchronizer(currency, m_blockchainSynchronizer, node),
|
m_synchronizer(currency, m_blockchainSynchronizer, node),
|
||||||
m_eventOccured(m_dispatcher),
|
m_eventOccurred(m_dispatcher),
|
||||||
m_readyEvent(m_dispatcher),
|
m_readyEvent(m_dispatcher),
|
||||||
m_transactionSoftLockTime(transactionSoftLockTime)
|
m_transactionSoftLockTime(transactionSoftLockTime)
|
||||||
{
|
{
|
||||||
|
@ -549,9 +607,7 @@ WalletTransfer WalletGreen::getTransactionTransfer(size_t transactionIndex, size
|
||||||
throw std::system_error(std::make_error_code(std::errc::invalid_argument));
|
throw std::system_error(std::make_error_code(std::errc::invalid_argument));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = bounds.first;
|
return std::next(bounds.first, transferIndex)->second;
|
||||||
std::advance(it, transferIndex);
|
|
||||||
return it->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<WalletTransfers::const_iterator, WalletTransfers::const_iterator> WalletGreen::getTransactionTransfers(
|
std::pair<WalletTransfers::const_iterator, WalletTransfers::const_iterator> WalletGreen::getTransactionTransfers(
|
||||||
|
@ -566,73 +622,111 @@ std::pair<WalletTransfers::const_iterator, WalletTransfers::const_iterator> Wall
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletGreen::transfer(const WalletTransfer& destination,
|
size_t WalletGreen::transfer(const WalletOrder& destination,
|
||||||
uint64_t fee,
|
|
||||||
uint64_t mixIn,
|
|
||||||
std::string const& extra,
|
|
||||||
uint64_t unlockTimestamp)
|
|
||||||
{
|
|
||||||
std::vector<WalletTransfer> destinations { destination };
|
|
||||||
return transfer(destinations, fee, mixIn, extra, unlockTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t WalletGreen::transfer(
|
|
||||||
const std::vector<WalletTransfer>& destinations,
|
|
||||||
uint64_t fee,
|
uint64_t fee,
|
||||||
uint64_t mixIn,
|
uint64_t mixIn,
|
||||||
const std::string& extra,
|
const std::string& extra,
|
||||||
uint64_t unlockTimestamp) {
|
uint64_t unlockTimestamp) {
|
||||||
|
|
||||||
System::EventLock lk(m_readyEvent);
|
TransactionParameters transactionParameters;
|
||||||
|
transactionParameters.destinations.emplace_back(destination);
|
||||||
|
transactionParameters.fee = fee;
|
||||||
|
transactionParameters.mixIn = mixIn;
|
||||||
|
transactionParameters.extra = extra;
|
||||||
|
transactionParameters.unlockTimestamp = unlockTimestamp;
|
||||||
|
|
||||||
throwIfNotInitialized();
|
return transfer(transactionParameters);
|
||||||
throwIfStopped();
|
}
|
||||||
throwIfTrackingMode();
|
|
||||||
|
|
||||||
return doTransfer(pickWalletsWithMoney(), destinations, fee, mixIn, extra, unlockTimestamp);
|
size_t WalletGreen::transfer(
|
||||||
|
const std::vector<WalletOrder>& destinations,
|
||||||
|
uint64_t fee,
|
||||||
|
uint64_t mixIn,
|
||||||
|
const std::string& extra,
|
||||||
|
uint64_t unlockTimestamp) {
|
||||||
|
|
||||||
|
TransactionParameters transactionParameters;
|
||||||
|
transactionParameters.destinations = destinations;
|
||||||
|
transactionParameters.fee = fee;
|
||||||
|
transactionParameters.mixIn = mixIn;
|
||||||
|
transactionParameters.extra = extra;
|
||||||
|
transactionParameters.unlockTimestamp = unlockTimestamp;
|
||||||
|
|
||||||
|
return transfer(transactionParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletGreen::transfer(
|
size_t WalletGreen::transfer(
|
||||||
const std::string& sourceAddress,
|
const std::string& sourceAddress,
|
||||||
const WalletTransfer& destination,
|
const WalletOrder& destination,
|
||||||
uint64_t fee,
|
uint64_t fee,
|
||||||
uint64_t mixIn,
|
uint64_t mixIn,
|
||||||
std::string const& extra,
|
std::string const& extra,
|
||||||
uint64_t unlockTimestamp) {
|
uint64_t unlockTimestamp) {
|
||||||
std::vector<WalletTransfer> destinations { destination };
|
|
||||||
return transfer(sourceAddress, destinations, fee, mixIn, extra, unlockTimestamp);
|
TransactionParameters transactionParameters;
|
||||||
|
transactionParameters.sourceAddress = sourceAddress;
|
||||||
|
transactionParameters.destinations.emplace_back(destination);
|
||||||
|
transactionParameters.fee = fee;
|
||||||
|
transactionParameters.mixIn = mixIn;
|
||||||
|
transactionParameters.extra = extra;
|
||||||
|
transactionParameters.unlockTimestamp = unlockTimestamp;
|
||||||
|
|
||||||
|
return transfer(transactionParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletGreen::transfer(
|
size_t WalletGreen::transfer(
|
||||||
const std::string& sourceAddress,
|
const std::string& sourceAddress,
|
||||||
const std::vector<WalletTransfer>& destinations,
|
const std::vector<WalletOrder>& destinations,
|
||||||
uint64_t fee,
|
uint64_t fee,
|
||||||
uint64_t mixIn,
|
uint64_t mixIn,
|
||||||
const std::string& extra,
|
const std::string& extra,
|
||||||
uint64_t unlockTimestamp) {
|
uint64_t unlockTimestamp) {
|
||||||
|
|
||||||
|
TransactionParameters transactionParameters;
|
||||||
|
transactionParameters.sourceAddress = sourceAddress;
|
||||||
|
transactionParameters.destinations = destinations;
|
||||||
|
transactionParameters.fee = fee;
|
||||||
|
transactionParameters.mixIn = mixIn;
|
||||||
|
transactionParameters.extra = extra;
|
||||||
|
transactionParameters.unlockTimestamp = unlockTimestamp;
|
||||||
|
|
||||||
|
return transfer(transactionParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WalletGreen::transfer(const TransactionParameters& transactionParameters) {
|
||||||
System::EventLock lk(m_readyEvent);
|
System::EventLock lk(m_readyEvent);
|
||||||
|
|
||||||
throwIfNotInitialized();
|
throwIfNotInitialized();
|
||||||
throwIfStopped();
|
|
||||||
throwIfTrackingMode();
|
throwIfTrackingMode();
|
||||||
|
throwIfStopped();
|
||||||
|
|
||||||
WalletOuts wallet = pickWallet(sourceAddress);
|
|
||||||
std::vector<WalletOuts> wallets;
|
std::vector<WalletOuts> wallets;
|
||||||
|
if (!transactionParameters.sourceAddress.empty()) {
|
||||||
if (!wallet.outs.empty()) {
|
WalletOuts wallet = pickWallet(transactionParameters.sourceAddress);
|
||||||
wallets.push_back(wallet);
|
if (!wallet.outs.empty()) {
|
||||||
|
wallets.emplace_back(std::move(wallet));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wallets = pickWalletsWithMoney();
|
||||||
}
|
}
|
||||||
|
|
||||||
return doTransfer(std::move(wallets), destinations, fee, mixIn, extra, unlockTimestamp);
|
return doTransfer(std::move(wallets),
|
||||||
|
transactionParameters.destinations,
|
||||||
|
transactionParameters.fee,
|
||||||
|
transactionParameters.mixIn,
|
||||||
|
transactionParameters.extra,
|
||||||
|
transactionParameters.unlockTimestamp,
|
||||||
|
transactionParameters.donation);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletGreen::doTransfer(std::vector<WalletOuts>&& wallets,
|
size_t WalletGreen::doTransfer(std::vector<WalletOuts>&& wallets,
|
||||||
const std::vector<WalletTransfer>& destinations,
|
const std::vector<WalletOrder>& orders,
|
||||||
uint64_t fee,
|
uint64_t fee,
|
||||||
uint64_t mixIn,
|
uint64_t mixIn,
|
||||||
const std::string& extra,
|
const std::string& extra,
|
||||||
uint64_t unlockTimestamp) {
|
uint64_t unlockTimestamp,
|
||||||
if (destinations.empty()) {
|
const DonationSettings& donation) {
|
||||||
|
if (orders.empty()) {
|
||||||
throw std::system_error(make_error_code(error::ZERO_DESTINATION));
|
throw std::system_error(make_error_code(error::ZERO_DESTINATION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,6 +734,11 @@ size_t WalletGreen::doTransfer(std::vector<WalletOuts>&& wallets,
|
||||||
throw std::system_error(make_error_code(error::FEE_TOO_SMALL));
|
throw std::system_error(make_error_code(error::FEE_TOO_SMALL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (donation.address.empty() ^ (donation.threshold == 0)) {
|
||||||
|
throw std::system_error(make_error_code(error::WRONG_PARAMETERS), "DonationSettings must have both address and threshold parameters filled");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<WalletTransfer> destinations = convertOrdersToTransfer(orders);
|
||||||
validateAddresses(destinations, m_currency);
|
validateAddresses(destinations, m_currency);
|
||||||
|
|
||||||
uint64_t neededMoney = countNeededMoney(destinations, fee);
|
uint64_t neededMoney = countNeededMoney(destinations, fee);
|
||||||
|
@ -661,16 +760,19 @@ size_t WalletGreen::doTransfer(std::vector<WalletOuts>&& wallets,
|
||||||
std::vector<InputInfo> keysInfo;
|
std::vector<InputInfo> keysInfo;
|
||||||
prepareInputs(selectedTransfers, mixinResult, mixIn, keysInfo);
|
prepareInputs(selectedTransfers, mixinResult, mixIn, keysInfo);
|
||||||
|
|
||||||
WalletTransfer changeDestination;
|
uint64_t donationAmount = pushDonationTransferIfPossible(donation, foundMoney - neededMoney, m_currency.defaultDustThreshold(), destinations);
|
||||||
changeDestination.address = m_currency.accountAddressAsString({ m_walletsContainer.get<RandomAccessIndex>()[0].spendPublicKey, m_viewPublicKey });
|
uint64_t changeAmount = foundMoney - neededMoney - donationAmount;
|
||||||
changeDestination.amount = foundMoney - neededMoney;
|
|
||||||
|
|
||||||
std::vector<ReceiverAmounts> decomposedOutputs;
|
std::vector<ReceiverAmounts> decomposedOutputs = splitDestinations(destinations, m_currency.defaultDustThreshold(), m_currency);
|
||||||
splitDestinations(destinations, changeDestination, m_currency.defaultDustThreshold(), m_currency, decomposedOutputs);
|
if (changeAmount != 0) {
|
||||||
|
CryptoNote::AccountPublicAddress changeDestination = { m_walletsContainer.get<RandomAccessIndex>()[0].spendPublicKey, m_viewPublicKey };
|
||||||
|
auto splittedChange = splitAmount(changeAmount, changeDestination, m_currency.defaultDustThreshold());
|
||||||
|
decomposedOutputs.emplace_back(std::move(splittedChange));
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<ITransaction> tx = makeTransaction(decomposedOutputs, keysInfo, extra, unlockTimestamp);
|
std::unique_ptr<ITransaction> tx = makeTransaction(decomposedOutputs, keysInfo, extra, unlockTimestamp);
|
||||||
|
|
||||||
size_t txId = insertOutgoingTransaction(tx->getTransactionHash(), -static_cast<int64_t>(neededMoney), fee, tx->getExtra(), unlockTimestamp);
|
size_t txId = insertOutgoingTransactionAndPushEvent(tx->getTransactionHash(), -static_cast<int64_t>(neededMoney), fee, tx->getExtra(), unlockTimestamp);
|
||||||
pushBackOutgoingTransfers(txId, destinations);
|
pushBackOutgoingTransfers(txId, destinations);
|
||||||
m_fusionTxsCache.emplace(txId, false);
|
m_fusionTxsCache.emplace(txId, false);
|
||||||
|
|
||||||
|
@ -679,34 +781,34 @@ size_t WalletGreen::doTransfer(std::vector<WalletOuts>&& wallets,
|
||||||
try {
|
try {
|
||||||
sendTransaction(tx.get());
|
sendTransaction(tx.get());
|
||||||
} catch (std::exception&) {
|
} catch (std::exception&) {
|
||||||
|
updateTransactionStateAndPushEvent(txId, WalletTransactionState::FAILED);
|
||||||
deleteSpentOutputs(tx->getTransactionHash());
|
deleteSpentOutputs(tx->getTransactionHash());
|
||||||
pushEvent(makeTransactionCreatedEvent(txId));
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto txIt = m_transactions.get<RandomAccessIndex>().begin();
|
m_change[tx->getTransactionHash()] = changeAmount;
|
||||||
std::advance(txIt, txId);
|
updateTransactionStateAndPushEvent(txId, WalletTransactionState::SUCCEEDED);
|
||||||
m_transactions.get<RandomAccessIndex>().modify(txIt,
|
|
||||||
[] (WalletTransaction& tx) { tx.state = WalletTransactionState::SUCCEEDED; });
|
|
||||||
|
|
||||||
m_change[tx->getTransactionHash()] = changeDestination.amount;
|
|
||||||
updateUsedWalletsBalances(selectedTransfers);
|
updateUsedWalletsBalances(selectedTransfers);
|
||||||
|
|
||||||
pushEvent(makeTransactionCreatedEvent(txId));
|
|
||||||
|
|
||||||
return txId;
|
return txId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletGreen::pushBackOutgoingTransfers(size_t txId, const std::vector<WalletTransfer> &destinations) {
|
void WalletGreen::pushBackOutgoingTransfers(size_t txId, const std::vector<WalletTransfer>& destinations) {
|
||||||
for (const auto& dest: destinations) {
|
for (const auto& dest: destinations) {
|
||||||
WalletTransfer d { dest.address, -dest.amount };
|
WalletTransfer d;
|
||||||
|
d.type = dest.type;
|
||||||
|
d.address = dest.address;
|
||||||
|
d.amount = -dest.amount;
|
||||||
|
|
||||||
m_transfers.push_back(std::make_pair(txId, d));
|
m_transfers.push_back(std::make_pair(txId, d));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletGreen::insertOutgoingTransaction(const Hash& transactionHash, int64_t totalAmount, uint64_t fee, const BinaryArray& extra, uint64_t unlockTimestamp) {
|
size_t WalletGreen::insertOutgoingTransactionAndPushEvent(const Hash& transactionHash,
|
||||||
|
int64_t totalAmount, uint64_t fee, const BinaryArray& extra, uint64_t unlockTimestamp) {
|
||||||
|
|
||||||
WalletTransaction insertTx;
|
WalletTransaction insertTx;
|
||||||
insertTx.state = WalletTransactionState::FAILED;
|
insertTx.state = WalletTransactionState::CREATED;
|
||||||
insertTx.creationTime = static_cast<uint64_t>(time(nullptr));
|
insertTx.creationTime = static_cast<uint64_t>(time(nullptr));
|
||||||
insertTx.unlockTime = unlockTimestamp;
|
insertTx.unlockTime = unlockTimestamp;
|
||||||
insertTx.blockHeight = CryptoNote::WALLET_UNCONFIRMED_TRANSACTION_HEIGHT;
|
insertTx.blockHeight = CryptoNote::WALLET_UNCONFIRMED_TRANSACTION_HEIGHT;
|
||||||
|
@ -720,59 +822,67 @@ size_t WalletGreen::insertOutgoingTransaction(const Hash& transactionHash, int64
|
||||||
size_t txId = m_transactions.get<RandomAccessIndex>().size();
|
size_t txId = m_transactions.get<RandomAccessIndex>().size();
|
||||||
m_transactions.get<RandomAccessIndex>().push_back(std::move(insertTx));
|
m_transactions.get<RandomAccessIndex>().push_back(std::move(insertTx));
|
||||||
|
|
||||||
|
pushEvent(makeTransactionCreatedEvent(txId));
|
||||||
|
|
||||||
return txId;
|
return txId;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletGreen::transactionExists(const Hash& hash) {
|
void WalletGreen::updateTransactionStateAndPushEvent(size_t transactionId, WalletTransactionState state) {
|
||||||
auto& hashIndex = m_transactions.get<TransactionIndex>();
|
auto it = std::next(m_transactions.get<RandomAccessIndex>().begin(), transactionId);
|
||||||
auto it = hashIndex.find(hash);
|
|
||||||
return it != hashIndex.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WalletGreen::updateWalletTransactionInfo(const Hash& hash, const CryptoNote::TransactionInformation& info) {
|
if (it->state != state) {
|
||||||
auto& hashIndex = m_transactions.get<TransactionIndex>();
|
m_transactions.get<RandomAccessIndex>().modify(it, [state](WalletTransaction& tx) {
|
||||||
|
tx.state = state;
|
||||||
bool updated = false;
|
|
||||||
auto it = hashIndex.find(hash);
|
|
||||||
if (it != hashIndex.end()) {
|
|
||||||
bool r = hashIndex.modify(it, [&info, &updated] (WalletTransaction& transaction) {
|
|
||||||
if (transaction.blockHeight != info.blockHeight) {
|
|
||||||
transaction.blockHeight = info.blockHeight;
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction.timestamp != info.timestamp) {
|
|
||||||
transaction.timestamp = info.timestamp;
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction.state != WalletTransactionState::SUCCEEDED) {
|
|
||||||
//transaction may be deleted first then added again
|
|
||||||
transaction.state = WalletTransactionState::SUCCEEDED;
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix LegacyWallet error. Some old versions didn't fill extra field
|
|
||||||
if (transaction.extra.empty() && !info.extra.empty()) {
|
|
||||||
transaction.extra = Common::asString(info.extra);
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isBase = info.totalAmountIn == 0;
|
|
||||||
if (transaction.isBase != isBase) {
|
|
||||||
transaction.isBase = isBase;
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assert(r);
|
pushEvent(makeTransactionUpdatedEvent(transactionId));
|
||||||
return updated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::system_error(make_error_code(std::errc::invalid_argument));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletGreen::insertBlockchainTransaction(const TransactionInformation& info, int64_t txBalance) {
|
void WalletGreen::updateWalletTransactionInfoAndPushEvent(size_t transactionId, const CryptoNote::TransactionInformation& info, bool transfersUpdated) {
|
||||||
|
auto& txIdIndex = m_transactions.get<RandomAccessIndex>();
|
||||||
|
assert(transactionId < txIdIndex.size());
|
||||||
|
auto it = std::next(txIdIndex.begin(), transactionId);
|
||||||
|
|
||||||
|
bool updated = false;
|
||||||
|
bool r = txIdIndex.modify(it, [&info, &updated](WalletTransaction& transaction) {
|
||||||
|
if (transaction.blockHeight != info.blockHeight) {
|
||||||
|
transaction.blockHeight = info.blockHeight;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transaction.timestamp != info.timestamp) {
|
||||||
|
transaction.timestamp = info.timestamp;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transaction.state != WalletTransactionState::SUCCEEDED) {
|
||||||
|
//transaction may be deleted first then added again
|
||||||
|
transaction.state = WalletTransactionState::SUCCEEDED;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix LegacyWallet error. Some old versions didn't fill extra field
|
||||||
|
if (transaction.extra.empty() && !info.extra.empty()) {
|
||||||
|
transaction.extra = Common::asString(info.extra);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isBase = info.totalAmountIn == 0;
|
||||||
|
if (transaction.isBase != isBase) {
|
||||||
|
transaction.isBase = isBase;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(r);
|
||||||
|
|
||||||
|
if (updated || transfersUpdated) {
|
||||||
|
pushEvent(makeTransactionUpdatedEvent(transactionId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WalletGreen::insertBlockchainTransactionAndPushEvent(const TransactionInformation& info, int64_t txBalance) {
|
||||||
auto& index = m_transactions.get<RandomAccessIndex>();
|
auto& index = m_transactions.get<RandomAccessIndex>();
|
||||||
|
|
||||||
WalletTransaction tx;
|
WalletTransaction tx;
|
||||||
|
@ -787,8 +897,12 @@ size_t WalletGreen::insertBlockchainTransaction(const TransactionInformation& in
|
||||||
tx.creationTime = info.timestamp;
|
tx.creationTime = info.timestamp;
|
||||||
tx.isBase = info.totalAmountIn == 0;
|
tx.isBase = info.totalAmountIn == 0;
|
||||||
|
|
||||||
|
size_t txId = index.size();
|
||||||
index.push_back(std::move(tx));
|
index.push_back(std::move(tx));
|
||||||
return index.size() - 1;
|
|
||||||
|
pushEvent(makeTransactionCreatedEvent(txId));
|
||||||
|
|
||||||
|
return txId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletGreen::insertIncomingTransfer(size_t txId, const std::string& address, int64_t amount) {
|
void WalletGreen::insertIncomingTransfer(size_t txId, const std::string& address, int64_t amount) {
|
||||||
|
@ -796,7 +910,7 @@ void WalletGreen::insertIncomingTransfer(size_t txId, const std::string& address
|
||||||
return val < a.first;
|
return val < a.first;
|
||||||
});
|
});
|
||||||
|
|
||||||
WalletTransfer tr { address, amount };
|
WalletTransfer tr { WalletTransferType::USUAL, address, amount };
|
||||||
m_transfers.insert(it, std::make_pair(txId, std::move(tr)));
|
m_transfers.insert(it, std::make_pair(txId, std::move(tr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -805,12 +919,23 @@ std::unique_ptr<CryptoNote::ITransaction> WalletGreen::makeTransaction(const std
|
||||||
|
|
||||||
std::unique_ptr<ITransaction> tx = createTransaction();
|
std::unique_ptr<ITransaction> tx = createTransaction();
|
||||||
|
|
||||||
|
typedef std::pair<const AccountPublicAddress*, uint64_t> AmountToAddress;
|
||||||
|
std::vector<AmountToAddress> amountsToAddresses;
|
||||||
for (const auto& output: decomposedOutputs) {
|
for (const auto& output: decomposedOutputs) {
|
||||||
for (auto amount: output.amounts) {
|
for (auto amount: output.amounts) {
|
||||||
tx->addOutput(amount, output.receiver);
|
amountsToAddresses.emplace_back(AmountToAddress{&output.receiver, amount});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shuffle(amountsToAddresses.begin(), amountsToAddresses.end(), std::default_random_engine{Crypto::rand<std::default_random_engine::result_type>()});
|
||||||
|
std::sort(amountsToAddresses.begin(), amountsToAddresses.end(), [] (const AmountToAddress& left, const AmountToAddress& right) {
|
||||||
|
return left.second < right.second;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const auto& amountToAddress: amountsToAddresses) {
|
||||||
|
tx->addOutput(amountToAddress.second, *amountToAddress.first);
|
||||||
|
}
|
||||||
|
|
||||||
tx->setUnlockTime(unlockTimestamp);
|
tx->setUnlockTime(unlockTimestamp);
|
||||||
tx->appendExtra(Common::asBinaryArray(extra));
|
tx->appendExtra(Common::asBinaryArray(extra));
|
||||||
|
|
||||||
|
@ -984,26 +1109,30 @@ WalletGreen::WalletOuts WalletGreen::pickWallet(const std::string& address) {
|
||||||
return outs;
|
return outs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletGreen::splitDestinations(const std::vector<CryptoNote::WalletTransfer>& destinations,
|
std::vector<CryptoNote::WalletGreen::ReceiverAmounts> WalletGreen::splitDestinations(const std::vector<CryptoNote::WalletTransfer>& destinations,
|
||||||
const CryptoNote::WalletTransfer& changeDestination,
|
|
||||||
uint64_t dustThreshold,
|
uint64_t dustThreshold,
|
||||||
const CryptoNote::Currency& currency,
|
const CryptoNote::Currency& currency) {
|
||||||
std::vector<ReceiverAmounts>& decomposedOutputs) {
|
|
||||||
|
|
||||||
|
std::vector<ReceiverAmounts> decomposedOutputs;
|
||||||
for (const auto& destination: destinations) {
|
for (const auto& destination: destinations) {
|
||||||
ReceiverAmounts receiverAmounts;
|
AccountPublicAddress address;
|
||||||
|
parseAddressString(destination.address, currency, address);
|
||||||
parseAddressString(destination.address, currency, receiverAmounts.receiver);
|
decomposedOutputs.push_back(splitAmount(destination.amount, address, dustThreshold));
|
||||||
decomposeAmount(destination.amount, dustThreshold, receiverAmounts.amounts);
|
|
||||||
|
|
||||||
decomposedOutputs.push_back(std::move(receiverAmounts));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReceiverAmounts changeAmounts;
|
return decomposedOutputs;
|
||||||
parseAddressString(changeDestination.address, currency, changeAmounts.receiver);
|
}
|
||||||
decomposeAmount(changeDestination.amount, dustThreshold, changeAmounts.amounts);
|
|
||||||
|
|
||||||
decomposedOutputs.push_back(std::move(changeAmounts));
|
CryptoNote::WalletGreen::ReceiverAmounts WalletGreen::splitAmount(
|
||||||
|
uint64_t amount,
|
||||||
|
const AccountPublicAddress& destination,
|
||||||
|
uint64_t dustThreshold) {
|
||||||
|
|
||||||
|
ReceiverAmounts receiverAmounts;
|
||||||
|
|
||||||
|
receiverAmounts.receiver = destination;
|
||||||
|
decomposeAmount(amount, dustThreshold, receiverAmounts.amounts);
|
||||||
|
return receiverAmounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletGreen::prepareInputs(
|
void WalletGreen::prepareInputs(
|
||||||
|
@ -1067,7 +1196,7 @@ void WalletGreen::start() {
|
||||||
|
|
||||||
void WalletGreen::stop() {
|
void WalletGreen::stop() {
|
||||||
m_stopped = true;
|
m_stopped = true;
|
||||||
m_eventOccured.set();
|
m_eventOccurred.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletEvent WalletGreen::getEvent() {
|
WalletEvent WalletGreen::getEvent() {
|
||||||
|
@ -1075,8 +1204,8 @@ WalletEvent WalletGreen::getEvent() {
|
||||||
throwIfStopped();
|
throwIfStopped();
|
||||||
|
|
||||||
while(m_events.empty()) {
|
while(m_events.empty()) {
|
||||||
m_eventOccured.wait();
|
m_eventOccurred.wait();
|
||||||
m_eventOccured.clear();
|
m_eventOccurred.clear();
|
||||||
throwIfStopped();
|
throwIfStopped();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1161,25 +1290,23 @@ void WalletGreen::transactionUpdated(ITransfersSubscription* object, const Hash&
|
||||||
int64_t txBalance;
|
int64_t txBalance;
|
||||||
bool found = container->getTransactionInformation(transactionHash, info, txBalance);
|
bool found = container->getTransactionInformation(transactionHash, info, txBalance);
|
||||||
assert(found);
|
assert(found);
|
||||||
|
bool addTransfer = txBalance > 0;
|
||||||
|
|
||||||
if (transactionExists(info.transactionHash)) {
|
auto& hashIndex = m_transactions.get<TransactionIndex>();
|
||||||
bool updated = updateWalletTransactionInfo(info.transactionHash, info);
|
auto it = hashIndex.find(info.transactionHash);
|
||||||
|
|
||||||
auto id = getTransactionId(info.transactionHash);
|
size_t transactionId;
|
||||||
|
if (it != hashIndex.end()) {
|
||||||
if (updated) {
|
transactionId = std::distance(m_transactions.get<RandomAccessIndex>().begin(), m_transactions.project<RandomAccessIndex>(it));
|
||||||
pushEvent(makeTransactionUpdatedEvent(id));
|
updateWalletTransactionInfoAndPushEvent(transactionId, info, addTransfer);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
auto id = insertBlockchainTransaction(info, txBalance);
|
transactionId = insertBlockchainTransactionAndPushEvent(info, txBalance);
|
||||||
if (txBalance > 0) {
|
m_fusionTxsCache.emplace(transactionId, isFusionTransaction(m_transactions.get<RandomAccessIndex>()[transactionId]));
|
||||||
AccountPublicAddress walletAddress{ getWalletRecord(container).spendPublicKey, m_viewPublicKey };
|
}
|
||||||
insertIncomingTransfer(id, m_currency.accountAddressAsString(walletAddress), txBalance);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_fusionTxsCache.emplace(id, isFusionTransaction(m_transactions.get<RandomAccessIndex>()[id]));
|
if (addTransfer) {
|
||||||
|
AccountPublicAddress walletAddress{ getWalletRecord(container).spendPublicKey, m_viewPublicKey };
|
||||||
pushEvent(makeTransactionCreatedEvent(id));
|
insertIncomingTransfer(transactionId, m_currency.accountAddressAsString(walletAddress), txBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_change.erase(transactionHash);
|
m_change.erase(transactionHash);
|
||||||
|
@ -1194,7 +1321,7 @@ void WalletGreen::transactionUpdated(ITransfersSubscription* object, const Hash&
|
||||||
|
|
||||||
void WalletGreen::pushEvent(const WalletEvent& event) {
|
void WalletGreen::pushEvent(const WalletEvent& event) {
|
||||||
m_events.push(event);
|
m_events.push(event);
|
||||||
m_eventOccured.set();
|
m_eventOccurred.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletGreen::getTransactionId(const Hash& transactionHash) const {
|
size_t WalletGreen::getTransactionId(const Hash& transactionHash) const {
|
||||||
|
@ -1393,9 +1520,9 @@ size_t WalletGreen::createFusionTransaction(uint64_t threshold, uint64_t mixin)
|
||||||
System::EventLock lk(m_readyEvent);
|
System::EventLock lk(m_readyEvent);
|
||||||
|
|
||||||
throwIfNotInitialized();
|
throwIfNotInitialized();
|
||||||
|
throwIfTrackingMode();
|
||||||
throwIfStopped();
|
throwIfStopped();
|
||||||
|
|
||||||
//TODO: check if wallet is not in tracking mode
|
|
||||||
const size_t MAX_FUSION_OUTPUT_COUNT = 4;
|
const size_t MAX_FUSION_OUTPUT_COUNT = 4;
|
||||||
|
|
||||||
if (threshold <= m_currency.defaultDustThreshold()) {
|
if (threshold <= m_currency.defaultDustThreshold()) {
|
||||||
|
@ -1455,11 +1582,11 @@ size_t WalletGreen::createFusionTransaction(uint64_t threshold, uint64_t mixin)
|
||||||
throw std::runtime_error("Unable to create fusion transaction");
|
throw std::runtime_error("Unable to create fusion transaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t transactionId = insertOutgoingTransaction(fusionTransaction->getTransactionHash(), 0, 0, fusionTransaction->getExtra(), 0);
|
size_t transactionId = insertOutgoingTransactionAndPushEvent(fusionTransaction->getTransactionHash(), 0, 0, fusionTransaction->getExtra(), 0);
|
||||||
m_fusionTxsCache.emplace(transactionId, true);
|
m_fusionTxsCache.emplace(transactionId, true);
|
||||||
|
|
||||||
WalletTransfer destination = {m_currency.accountAddressAsString({m_walletsContainer.get<RandomAccessIndex>().begin()->spendPublicKey,
|
std::string address = m_currency.accountAddressAsString({m_walletsContainer.get<RandomAccessIndex>().begin()->spendPublicKey, m_viewPublicKey });
|
||||||
m_viewPublicKey }), 0};
|
WalletTransfer destination = {WalletTransferType::USUAL, address, 0};
|
||||||
pushBackOutgoingTransfers(transactionId, std::vector<WalletTransfer> {destination});
|
pushBackOutgoingTransfers(transactionId, std::vector<WalletTransfer> {destination});
|
||||||
|
|
||||||
markOutputsSpent(fusionTransaction->getTransactionHash(), fusionInputs);
|
markOutputsSpent(fusionTransaction->getTransactionHash(), fusionInputs);
|
||||||
|
@ -1467,22 +1594,15 @@ size_t WalletGreen::createFusionTransaction(uint64_t threshold, uint64_t mixin)
|
||||||
try {
|
try {
|
||||||
sendTransaction(fusionTransaction.get());
|
sendTransaction(fusionTransaction.get());
|
||||||
} catch (std::exception&) {
|
} catch (std::exception&) {
|
||||||
|
updateTransactionStateAndPushEvent(transactionId, WalletTransactionState::FAILED);
|
||||||
deleteSpentOutputs(fusionTransaction->getTransactionHash());
|
deleteSpentOutputs(fusionTransaction->getTransactionHash());
|
||||||
pushEvent(makeTransactionCreatedEvent(transactionId));
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto txIt = m_transactions.get<RandomAccessIndex>().begin();
|
|
||||||
std::advance(txIt, transactionId);
|
|
||||||
m_transactions.get<RandomAccessIndex>().modify(txIt,
|
|
||||||
[] (WalletTransaction& tx) { tx.state = WalletTransactionState::SUCCEEDED; });
|
|
||||||
|
|
||||||
m_change[fusionTransaction->getTransactionHash()] = transactionAmount;
|
m_change[fusionTransaction->getTransactionHash()] = transactionAmount;
|
||||||
|
updateTransactionStateAndPushEvent(transactionId, WalletTransactionState::SUCCEEDED);
|
||||||
updateUsedWalletsBalances(fusionInputs);
|
updateUsedWalletsBalances(fusionInputs);
|
||||||
|
|
||||||
pushEvent(makeTransactionCreatedEvent(transactionId));
|
|
||||||
|
|
||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,10 +66,11 @@ public:
|
||||||
virtual size_t getTransactionTransferCount(size_t transactionIndex) const override;
|
virtual size_t getTransactionTransferCount(size_t transactionIndex) const override;
|
||||||
virtual WalletTransfer getTransactionTransfer(size_t transactionIndex, size_t transferIndex) const override;
|
virtual WalletTransfer getTransactionTransfer(size_t transactionIndex, size_t transferIndex) const override;
|
||||||
|
|
||||||
virtual size_t transfer(const WalletTransfer& destination, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) override;
|
virtual size_t transfer(const WalletOrder& destination, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) override;
|
||||||
virtual size_t transfer(const std::vector<WalletTransfer>& destinations, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) override;
|
virtual size_t transfer(const std::vector<WalletOrder>& destinations, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) override;
|
||||||
virtual size_t transfer(const std::string& sourceAddress, const WalletTransfer& destination, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) override;
|
virtual size_t transfer(const std::string& sourceAddress, const WalletOrder& destination, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) override;
|
||||||
virtual size_t transfer(const std::string& sourceAddress, const std::vector<WalletTransfer>& destinations, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) override;
|
virtual size_t transfer(const std::string& sourceAddress, const std::vector<WalletOrder>& destinations, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0) override;
|
||||||
|
virtual size_t transfer(const TransactionParameters& sendingTransaction) override;
|
||||||
|
|
||||||
virtual void start() override;
|
virtual void start() override;
|
||||||
virtual void stop() override;
|
virtual void stop() override;
|
||||||
|
@ -145,11 +146,12 @@ protected:
|
||||||
bool isFusionTransaction(const WalletTransaction& walletTx) const;
|
bool isFusionTransaction(const WalletTransaction& walletTx) const;
|
||||||
|
|
||||||
size_t doTransfer(std::vector<WalletOuts>&& wallets,
|
size_t doTransfer(std::vector<WalletOuts>&& wallets,
|
||||||
const std::vector<WalletTransfer>& destinations,
|
const std::vector<WalletOrder>& orders,
|
||||||
uint64_t fee,
|
uint64_t fee,
|
||||||
uint64_t mixIn,
|
uint64_t mixIn,
|
||||||
const std::string& extra,
|
const std::string& extra,
|
||||||
uint64_t unlockTimestamp);
|
uint64_t unlockTimestamp,
|
||||||
|
const DonationSettings& donation);
|
||||||
|
|
||||||
void requestMixinOuts(const std::vector<OutputToTransfer>& selectedTransfers,
|
void requestMixinOuts(const std::vector<OutputToTransfer>& selectedTransfers,
|
||||||
uint64_t mixIn,
|
uint64_t mixIn,
|
||||||
|
@ -166,18 +168,20 @@ protected:
|
||||||
std::vector<WalletOuts>&& wallets,
|
std::vector<WalletOuts>&& wallets,
|
||||||
std::vector<OutputToTransfer>& selectedTransfers);
|
std::vector<OutputToTransfer>& selectedTransfers);
|
||||||
|
|
||||||
void splitDestinations(const std::vector<WalletTransfer>& destinations, const WalletTransfer& changeDestination,
|
std::vector<ReceiverAmounts> splitDestinations(const std::vector<WalletTransfer>& destinations,
|
||||||
uint64_t dustThreshold, const Currency& currency, std::vector<ReceiverAmounts>& decomposedOutputs);
|
uint64_t dustThreshold, const Currency& currency);
|
||||||
|
ReceiverAmounts splitAmount(uint64_t amount, const AccountPublicAddress& destination, uint64_t dustThreshold);
|
||||||
|
|
||||||
std::unique_ptr<CryptoNote::ITransaction> makeTransaction(const std::vector<ReceiverAmounts>& decomposedOutputs,
|
std::unique_ptr<CryptoNote::ITransaction> makeTransaction(const std::vector<ReceiverAmounts>& decomposedOutputs,
|
||||||
std::vector<InputInfo>& keysInfo, const std::string& extra, uint64_t unlockTimestamp);
|
std::vector<InputInfo>& keysInfo, const std::string& extra, uint64_t unlockTimestamp);
|
||||||
|
|
||||||
void sendTransaction(ITransaction* tx);
|
void sendTransaction(ITransaction* tx);
|
||||||
|
|
||||||
size_t insertOutgoingTransaction(const Crypto::Hash& transactionHash, int64_t totalAmount, uint64_t fee, const BinaryArray& extra, uint64_t unlockTimestamp);
|
size_t insertBlockchainTransactionAndPushEvent(const TransactionInformation& info, int64_t txBalance);
|
||||||
bool transactionExists(const Crypto::Hash& hash);
|
size_t insertOutgoingTransactionAndPushEvent(const Crypto::Hash& transactionHash,
|
||||||
bool updateWalletTransactionInfo(const Crypto::Hash& hash, const CryptoNote::TransactionInformation& info);
|
int64_t totalAmount, uint64_t fee, const BinaryArray& extra, uint64_t unlockTimestamp);
|
||||||
size_t insertBlockchainTransaction(const TransactionInformation& info, int64_t txBalance);
|
void updateTransactionStateAndPushEvent(size_t transactionId, WalletTransactionState state);
|
||||||
|
void updateWalletTransactionInfoAndPushEvent(size_t transactionId, const CryptoNote::TransactionInformation& info, bool transfersUpdated);
|
||||||
void insertIncomingTransfer(size_t txId, const std::string& address, int64_t amount);
|
void insertIncomingTransfer(size_t txId, const std::string& address, int64_t amount);
|
||||||
void pushBackOutgoingTransfers(size_t txId, const std::vector<WalletTransfer> &destinations);
|
void pushBackOutgoingTransfers(size_t txId, const std::vector<WalletTransfer> &destinations);
|
||||||
void insertUnlockTransactionJob(const Crypto::Hash& transactionHash, uint32_t blockHeight, CryptoNote::ITransfersContainer* container);
|
void insertUnlockTransactionJob(const Crypto::Hash& transactionHash, uint32_t blockHeight, CryptoNote::ITransfersContainer* container);
|
||||||
|
@ -219,7 +223,7 @@ protected:
|
||||||
BlockchainSynchronizer m_blockchainSynchronizer;
|
BlockchainSynchronizer m_blockchainSynchronizer;
|
||||||
TransfersSyncronizer m_synchronizer;
|
TransfersSyncronizer m_synchronizer;
|
||||||
|
|
||||||
System::Event m_eventOccured;
|
System::Event m_eventOccurred;
|
||||||
std::queue<WalletEvent> m_events;
|
std::queue<WalletEvent> m_events;
|
||||||
mutable System::Event m_readyEvent;
|
mutable System::Event m_readyEvent;
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ using CryptoNote::ISerializer;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct trnsfer_destination
|
struct transfer_destination
|
||||||
{
|
{
|
||||||
uint64_t amount;
|
uint64_t amount;
|
||||||
std::string address;
|
std::string address;
|
||||||
|
@ -63,7 +63,7 @@ using CryptoNote::ISerializer;
|
||||||
{
|
{
|
||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
std::list<trnsfer_destination> destinations;
|
std::list<transfer_destination> destinations;
|
||||||
uint64_t fee;
|
uint64_t fee;
|
||||||
uint64_t mixin;
|
uint64_t mixin;
|
||||||
uint64_t unlock_time;
|
uint64_t unlock_time;
|
||||||
|
|
|
@ -99,14 +99,18 @@ struct WalletTransactionDto {
|
||||||
|
|
||||||
//DO NOT CHANGE IT
|
//DO NOT CHANGE IT
|
||||||
struct WalletTransferDto {
|
struct WalletTransferDto {
|
||||||
WalletTransferDto() {}
|
WalletTransferDto(uint32_t version) : version(version) {}
|
||||||
WalletTransferDto(const CryptoNote::WalletTransfer& tr) {
|
WalletTransferDto(const CryptoNote::WalletTransfer& tr, uint32_t version) : WalletTransferDto(version) {
|
||||||
address = tr.address;
|
address = tr.address;
|
||||||
amount = tr.amount;
|
amount = tr.amount;
|
||||||
|
type = static_cast<uint8_t>(tr.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string address;
|
std::string address;
|
||||||
uint64_t amount;
|
uint64_t amount;
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
uint32_t version;
|
||||||
};
|
};
|
||||||
|
|
||||||
void serialize(WalletRecordDto& value, CryptoNote::ISerializer& serializer) {
|
void serialize(WalletRecordDto& value, CryptoNote::ISerializer& serializer) {
|
||||||
|
@ -156,8 +160,11 @@ void serialize(WalletTransactionDto& value, CryptoNote::ISerializer& serializer)
|
||||||
void serialize(WalletTransferDto& value, CryptoNote::ISerializer& serializer) {
|
void serialize(WalletTransferDto& value, CryptoNote::ISerializer& serializer) {
|
||||||
serializer(value.address, "address");
|
serializer(value.address, "address");
|
||||||
serializer(value.amount, "amount");
|
serializer(value.amount, "amount");
|
||||||
}
|
|
||||||
|
|
||||||
|
if (value.version > 2) {
|
||||||
|
serializer(value.type, "type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Object>
|
template <typename Object>
|
||||||
std::string serialize(Object& obj, const std::string& name) {
|
std::string serialize(Object& obj, const std::string& name) {
|
||||||
|
@ -266,7 +273,7 @@ CryptoNote::WalletTransfer convert(const CryptoNote::WalletLegacyTransfer& tr) {
|
||||||
|
|
||||||
namespace CryptoNote {
|
namespace CryptoNote {
|
||||||
|
|
||||||
const uint32_t WalletSerializer::SERIALIZATION_VERSION = 2;
|
const uint32_t WalletSerializer::SERIALIZATION_VERSION = 3;
|
||||||
|
|
||||||
void CryptoContext::incIv() {
|
void CryptoContext::incIv() {
|
||||||
uint64_t * i = reinterpret_cast<uint64_t *>(&iv.data[0]);
|
uint64_t * i = reinterpret_cast<uint64_t *>(&iv.data[0]);
|
||||||
|
@ -503,7 +510,7 @@ void WalletSerializer::saveTransfers(Common::IOutputStream& destination, CryptoC
|
||||||
|
|
||||||
for (const auto& kv: m_transfers) {
|
for (const auto& kv: m_transfers) {
|
||||||
uint64_t txId = kv.first;
|
uint64_t txId = kv.first;
|
||||||
WalletTransferDto tr(kv.second);
|
WalletTransferDto tr(kv.second, SERIALIZATION_VERSION);
|
||||||
|
|
||||||
serializeEncrypted(txId, "transaction_id", cryptoContext, destination);
|
serializeEncrypted(txId, "transaction_id", cryptoContext, destination);
|
||||||
cryptoContext.incIv();
|
cryptoContext.incIv();
|
||||||
|
@ -519,18 +526,18 @@ void WalletSerializer::load(const std::string& password, Common::IInputStream& s
|
||||||
|
|
||||||
uint32_t version = loadVersion(source);
|
uint32_t version = loadVersion(source);
|
||||||
|
|
||||||
if (version == SERIALIZATION_VERSION) {
|
if (version > SERIALIZATION_VERSION) {
|
||||||
loadCurrentVersion(source, password);
|
|
||||||
} else if (version == 1) {
|
|
||||||
loadWalletV1(source, password);
|
|
||||||
} else {
|
|
||||||
throw std::system_error(make_error_code(error::WRONG_VERSION));
|
throw std::system_error(make_error_code(error::WRONG_VERSION));
|
||||||
|
} else if (version != 1) {
|
||||||
|
loadWallet(source, password, version);
|
||||||
|
} else {
|
||||||
|
loadWalletV1(source, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.endObject();
|
s.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletSerializer::loadCurrentVersion(Common::IInputStream& source, const std::string& password) {
|
void WalletSerializer::loadWallet(Common::IInputStream& source, const std::string& password, uint32_t version) {
|
||||||
CryptoNote::CryptoContext cryptoContext;
|
CryptoNote::CryptoContext cryptoContext;
|
||||||
|
|
||||||
bool details = false;
|
bool details = false;
|
||||||
|
@ -549,7 +556,7 @@ void WalletSerializer::loadCurrentVersion(Common::IInputStream& source, const st
|
||||||
|
|
||||||
if (details) {
|
if (details) {
|
||||||
loadTransactions(source, cryptoContext);
|
loadTransactions(source, cryptoContext);
|
||||||
loadTransfers(source, cryptoContext);
|
loadTransfers(source, cryptoContext, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache) {
|
if (cache) {
|
||||||
|
@ -869,7 +876,7 @@ void WalletSerializer::loadTransactions(Common::IInputStream& source, CryptoCont
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WalletSerializer::loadTransfers(Common::IInputStream& source, CryptoContext& cryptoContext) {
|
void WalletSerializer::loadTransfers(Common::IInputStream& source, CryptoContext& cryptoContext, uint32_t version) {
|
||||||
uint64_t count = 0;
|
uint64_t count = 0;
|
||||||
deserializeEncrypted(count, "transfers_count", cryptoContext, source);
|
deserializeEncrypted(count, "transfers_count", cryptoContext, source);
|
||||||
cryptoContext.incIv();
|
cryptoContext.incIv();
|
||||||
|
@ -881,7 +888,7 @@ void WalletSerializer::loadTransfers(Common::IInputStream& source, CryptoContext
|
||||||
deserializeEncrypted(txId, "transaction_id", cryptoContext, source);
|
deserializeEncrypted(txId, "transaction_id", cryptoContext, source);
|
||||||
cryptoContext.incIv();
|
cryptoContext.incIv();
|
||||||
|
|
||||||
WalletTransferDto dto;
|
WalletTransferDto dto(version);
|
||||||
deserializeEncrypted(dto, "transfer", cryptoContext, source);
|
deserializeEncrypted(dto, "transfer", cryptoContext, source);
|
||||||
cryptoContext.incIv();
|
cryptoContext.incIv();
|
||||||
|
|
||||||
|
@ -889,6 +896,12 @@ void WalletSerializer::loadTransfers(Common::IInputStream& source, CryptoContext
|
||||||
tr.address = dto.address;
|
tr.address = dto.address;
|
||||||
tr.amount = dto.amount;
|
tr.amount = dto.amount;
|
||||||
|
|
||||||
|
if (version > 2) {
|
||||||
|
tr.type = static_cast<WalletTransferType>(dto.type);
|
||||||
|
} else {
|
||||||
|
tr.type = WalletTransferType::USUAL;
|
||||||
|
}
|
||||||
|
|
||||||
m_transfers.push_back(std::make_pair(txId, tr));
|
m_transfers.push_back(std::make_pair(txId, tr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ public:
|
||||||
private:
|
private:
|
||||||
static const uint32_t SERIALIZATION_VERSION;
|
static const uint32_t SERIALIZATION_VERSION;
|
||||||
|
|
||||||
void loadCurrentVersion(Common::IInputStream& source, const std::string& password);
|
void loadWallet(Common::IInputStream& source, const std::string& password, uint32_t version);
|
||||||
void loadWalletV1(Common::IInputStream& source, const std::string& password);
|
void loadWalletV1(Common::IInputStream& source, const std::string& password);
|
||||||
|
|
||||||
CryptoContext generateCryptoContext(const std::string& password);
|
CryptoContext generateCryptoContext(const std::string& password);
|
||||||
|
@ -95,7 +95,7 @@ private:
|
||||||
void loadUnlockTransactionsJobs(Common::IInputStream& source, CryptoContext& cryptoContext);
|
void loadUnlockTransactionsJobs(Common::IInputStream& source, CryptoContext& cryptoContext);
|
||||||
void loadChange(Common::IInputStream& source, CryptoContext& cryptoContext);
|
void loadChange(Common::IInputStream& source, CryptoContext& cryptoContext);
|
||||||
void loadTransactions(Common::IInputStream& source, CryptoContext& cryptoContext);
|
void loadTransactions(Common::IInputStream& source, CryptoContext& cryptoContext);
|
||||||
void loadTransfers(Common::IInputStream& source, CryptoContext& cryptoContext);
|
void loadTransfers(Common::IInputStream& source, CryptoContext& cryptoContext, uint32_t version);
|
||||||
|
|
||||||
void loadWalletV1Keys(CryptoNote::BinaryInputStreamSerializer& serializer);
|
void loadWalletV1Keys(CryptoNote::BinaryInputStreamSerializer& serializer);
|
||||||
void loadWalletV1Details(CryptoNote::BinaryInputStreamSerializer& serializer);
|
void loadWalletV1Details(CryptoNote::BinaryInputStreamSerializer& serializer);
|
||||||
|
|
|
@ -53,37 +53,37 @@ public:
|
||||||
WalletLegacy(const CryptoNote::Currency& currency, INode& node);
|
WalletLegacy(const CryptoNote::Currency& currency, INode& node);
|
||||||
virtual ~WalletLegacy();
|
virtual ~WalletLegacy();
|
||||||
|
|
||||||
virtual void addObserver(IWalletLegacyObserver* observer);
|
virtual void addObserver(IWalletLegacyObserver* observer) override;
|
||||||
virtual void removeObserver(IWalletLegacyObserver* observer);
|
virtual void removeObserver(IWalletLegacyObserver* observer) override;
|
||||||
|
|
||||||
virtual void initAndGenerate(const std::string& password);
|
virtual void initAndGenerate(const std::string& password) override;
|
||||||
virtual void initAndLoad(std::istream& source, const std::string& password);
|
virtual void initAndLoad(std::istream& source, const std::string& password) override;
|
||||||
virtual void initWithKeys(const AccountKeys& accountKeys, const std::string& password);
|
virtual void initWithKeys(const AccountKeys& accountKeys, const std::string& password) override;
|
||||||
virtual void shutdown();
|
virtual void shutdown() override;
|
||||||
virtual void reset();
|
virtual void reset() override;
|
||||||
|
|
||||||
virtual void save(std::ostream& destination, bool saveDetailed = true, bool saveCache = true);
|
virtual void save(std::ostream& destination, bool saveDetailed = true, bool saveCache = true) override;
|
||||||
|
|
||||||
virtual std::error_code changePassword(const std::string& oldPassword, const std::string& newPassword);
|
virtual std::error_code changePassword(const std::string& oldPassword, const std::string& newPassword) override;
|
||||||
|
|
||||||
virtual std::string getAddress();
|
virtual std::string getAddress() override;
|
||||||
|
|
||||||
virtual uint64_t actualBalance();
|
virtual uint64_t actualBalance() override;
|
||||||
virtual uint64_t pendingBalance();
|
virtual uint64_t pendingBalance() override;
|
||||||
|
|
||||||
virtual size_t getTransactionCount();
|
virtual size_t getTransactionCount() override;
|
||||||
virtual size_t getTransferCount();
|
virtual size_t getTransferCount() override;
|
||||||
|
|
||||||
virtual TransactionId findTransactionByTransferId(TransferId transferId);
|
virtual TransactionId findTransactionByTransferId(TransferId transferId) override;
|
||||||
|
|
||||||
virtual bool getTransaction(TransactionId transactionId, WalletLegacyTransaction& transaction);
|
virtual bool getTransaction(TransactionId transactionId, WalletLegacyTransaction& transaction) override;
|
||||||
virtual bool getTransfer(TransferId transferId, WalletLegacyTransfer& transfer);
|
virtual bool getTransfer(TransferId transferId, WalletLegacyTransfer& transfer) override;
|
||||||
|
|
||||||
virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0);
|
virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override;
|
||||||
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0);
|
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override;
|
||||||
virtual std::error_code cancelTransaction(size_t transactionId);
|
virtual std::error_code cancelTransaction(size_t transactionId) override;
|
||||||
|
|
||||||
virtual void getAccountKeys(AccountKeys& keys);
|
virtual void getAccountKeys(AccountKeys& keys) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,11 @@ static const char _NR[] = {
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/timeb.h>
|
#include <sys/timeb.h>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <malloc/malloc.h>
|
||||||
|
#else
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
|
@ -24,7 +24,7 @@ cn_slow_hash_noaesni
|
||||||
(void *restrict context, const void *restrict data, size_t length, void *restrict hash)
|
(void *restrict context, const void *restrict data, size_t length, void *restrict hash)
|
||||||
{
|
{
|
||||||
#define ctx ((struct cn_ctx *) context)
|
#define ctx ((struct cn_ctx *) context)
|
||||||
uint8_t ExpandedKey[256];
|
ALIGNED_DECL(uint8_t ExpandedKey[256], 16);
|
||||||
size_t i;
|
size_t i;
|
||||||
__m128i *longoutput, *expkey, *xmminput, b_x;
|
__m128i *longoutput, *expkey, *xmminput, b_x;
|
||||||
ALIGNED_DECL(uint64_t a[2], 16);
|
ALIGNED_DECL(uint64_t a[2], 16);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#define BUILD_COMMIT_ID "@VERSION@"
|
#define BUILD_COMMIT_ID "@VERSION@"
|
||||||
#define PROJECT_VERSION "1.0.8.1"
|
#define PROJECT_VERSION "1.0.8.2"
|
||||||
#define PROJECT_VERSION_BUILD_NO "614"
|
#define PROJECT_VERSION_BUILD_NO "625"
|
||||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
|
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~NodeObserver() {
|
virtual ~NodeObserver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void peerCountUpdated(size_t count) {
|
virtual void peerCountUpdated(size_t count) override {
|
||||||
logger(INFO) << '[' << m_name << "] peerCountUpdated " << count << " = " << m_nodeProxy.getPeerCount();
|
logger(INFO) << '[' << m_name << "] peerCountUpdated " << count << " = " << m_nodeProxy.getPeerCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,16 +31,16 @@ public:
|
||||||
ICoreStub();
|
ICoreStub();
|
||||||
ICoreStub(const CryptoNote::Block& genesisBlock);
|
ICoreStub(const CryptoNote::Block& genesisBlock);
|
||||||
|
|
||||||
virtual bool addObserver(CryptoNote::ICoreObserver* observer);
|
virtual bool addObserver(CryptoNote::ICoreObserver* observer) override;
|
||||||
virtual bool removeObserver(CryptoNote::ICoreObserver* observer);
|
virtual bool removeObserver(CryptoNote::ICoreObserver* observer) override;
|
||||||
virtual void get_blockchain_top(uint32_t& height, Crypto::Hash& top_id);
|
virtual void get_blockchain_top(uint32_t& height, Crypto::Hash& top_id) override;
|
||||||
virtual std::vector<Crypto::Hash> findBlockchainSupplement(const std::vector<Crypto::Hash>& remoteBlockIds, size_t maxCount,
|
virtual std::vector<Crypto::Hash> findBlockchainSupplement(const std::vector<Crypto::Hash>& remoteBlockIds, size_t maxCount,
|
||||||
uint32_t& totalBlockCount, uint32_t& startBlockIndex) override;
|
uint32_t& totalBlockCount, uint32_t& startBlockIndex) override;
|
||||||
virtual bool get_random_outs_for_amounts(const CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request& req,
|
virtual bool get_random_outs_for_amounts(const CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request& req,
|
||||||
CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& res);
|
CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& res) override;
|
||||||
virtual bool get_tx_outputs_gindexs(const Crypto::Hash& tx_id, std::vector<uint32_t>& indexs);
|
virtual bool get_tx_outputs_gindexs(const Crypto::Hash& tx_id, std::vector<uint32_t>& indexs) override;
|
||||||
virtual CryptoNote::i_cryptonote_protocol* get_protocol();
|
virtual CryptoNote::i_cryptonote_protocol* get_protocol() override;
|
||||||
virtual bool handle_incoming_tx(CryptoNote::BinaryArray const& tx_blob, CryptoNote::tx_verification_context& tvc, bool keeped_by_block);
|
virtual bool handle_incoming_tx(CryptoNote::BinaryArray const& tx_blob, CryptoNote::tx_verification_context& tvc, bool keeped_by_block) override;
|
||||||
virtual std::vector<CryptoNote::Transaction> getPoolTransactions() override;
|
virtual std::vector<CryptoNote::Transaction> getPoolTransactions() override;
|
||||||
virtual bool getPoolChanges(const Crypto::Hash& tailBlockId, const std::vector<Crypto::Hash>& knownTxsIds,
|
virtual bool getPoolChanges(const Crypto::Hash& tailBlockId, const std::vector<Crypto::Hash>& knownTxsIds,
|
||||||
std::vector<CryptoNote::Transaction>& addedTxs, std::vector<Crypto::Hash>& deletedTxsIds) override;
|
std::vector<CryptoNote::Transaction>& addedTxs, std::vector<Crypto::Hash>& deletedTxsIds) override;
|
||||||
|
|
|
@ -34,10 +34,10 @@ public:
|
||||||
virtual bool addObserver(CryptoNote::INodeObserver* observer) override;
|
virtual bool addObserver(CryptoNote::INodeObserver* observer) override;
|
||||||
virtual bool removeObserver(CryptoNote::INodeObserver* observer) override;
|
virtual bool removeObserver(CryptoNote::INodeObserver* observer) override;
|
||||||
|
|
||||||
virtual void init(const CryptoNote::INode::Callback& callback) {callback(std::error_code());};
|
virtual void init(const CryptoNote::INode::Callback& callback) override {callback(std::error_code());};
|
||||||
virtual bool shutdown() { return true; };
|
virtual bool shutdown() override { return true; };
|
||||||
|
|
||||||
virtual size_t getPeerCount() const { return 0; };
|
virtual size_t getPeerCount() const override { return 0; };
|
||||||
virtual uint32_t getLastLocalBlockHeight() const override { return 0; };
|
virtual uint32_t getLastLocalBlockHeight() const override { return 0; };
|
||||||
virtual uint32_t getLastKnownBlockHeight() const override { return 0; };
|
virtual uint32_t getLastKnownBlockHeight() const override { return 0; };
|
||||||
virtual uint32_t getLocalBlockCount() const override { return 0; };
|
virtual uint32_t getLocalBlockCount() const override { return 0; };
|
||||||
|
@ -56,13 +56,13 @@ public:
|
||||||
virtual void queryBlocks(std::vector<Crypto::Hash>&& knownBlockIds, uint64_t timestamp, std::vector<CryptoNote::BlockShortEntry>& newBlocks,
|
virtual void queryBlocks(std::vector<Crypto::Hash>&& knownBlockIds, uint64_t timestamp, std::vector<CryptoNote::BlockShortEntry>& newBlocks,
|
||||||
uint32_t& startHeight, const Callback& callback) override { callback(std::error_code()); };
|
uint32_t& startHeight, const Callback& callback) override { callback(std::error_code()); };
|
||||||
|
|
||||||
virtual void getBlocks(const std::vector<uint32_t>& blockHeights, std::vector<std::vector<CryptoNote::BlockDetails>>& blocks, const Callback& callback) { callback(std::error_code()); };
|
virtual void getBlocks(const std::vector<uint32_t>& blockHeights, std::vector<std::vector<CryptoNote::BlockDetails>>& blocks, const Callback& callback) override { callback(std::error_code()); };
|
||||||
virtual void getBlocks(const std::vector<Crypto::Hash>& blockHashes, std::vector<CryptoNote::BlockDetails>& blocks, const Callback& callback) { callback(std::error_code()); };
|
virtual void getBlocks(const std::vector<Crypto::Hash>& blockHashes, std::vector<CryptoNote::BlockDetails>& blocks, const Callback& callback) override { callback(std::error_code()); };
|
||||||
virtual void getBlocks(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t blocksNumberLimit, std::vector<CryptoNote::BlockDetails>& blocks, uint32_t& blocksNumberWithinTimestamps, const Callback& callback) { callback(std::error_code()); };
|
virtual void getBlocks(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t blocksNumberLimit, std::vector<CryptoNote::BlockDetails>& blocks, uint32_t& blocksNumberWithinTimestamps, const Callback& callback) override { callback(std::error_code()); };
|
||||||
virtual void getTransactions(const std::vector<Crypto::Hash>& transactionHashes, std::vector<CryptoNote::TransactionDetails>& transactions, const Callback& callback) { callback(std::error_code()); };
|
virtual void getTransactions(const std::vector<Crypto::Hash>& transactionHashes, std::vector<CryptoNote::TransactionDetails>& transactions, const Callback& callback) override { callback(std::error_code()); };
|
||||||
virtual void getTransactionsByPaymentId(const Crypto::Hash& paymentId, std::vector<CryptoNote::TransactionDetails>& transactions, const Callback& callback) { callback(std::error_code()); };
|
virtual void getTransactionsByPaymentId(const Crypto::Hash& paymentId, std::vector<CryptoNote::TransactionDetails>& transactions, const Callback& callback) override { callback(std::error_code()); };
|
||||||
virtual void getPoolTransactions(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t transactionsNumberLimit, std::vector<CryptoNote::TransactionDetails>& transactions, uint64_t& transactionsNumberWithinTimestamps, const Callback& callback) { callback(std::error_code()); };
|
virtual void getPoolTransactions(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t transactionsNumberLimit, std::vector<CryptoNote::TransactionDetails>& transactions, uint64_t& transactionsNumberWithinTimestamps, const Callback& callback) override { callback(std::error_code()); };
|
||||||
virtual void isSynchronized(bool& syncStatus, const Callback& callback) { callback(std::error_code()); };
|
virtual void isSynchronized(bool& syncStatus, const Callback& callback) override { callback(std::error_code()); };
|
||||||
virtual void getMultisignatureOutputByGlobalIndex(uint64_t amount, uint32_t gindex, CryptoNote::MultisignatureOutput& out, const Callback& callback) override { callback(std::error_code()); }
|
virtual void getMultisignatureOutputByGlobalIndex(uint64_t amount, uint32_t gindex, CryptoNote::MultisignatureOutput& out, const Callback& callback) override { callback(std::error_code()); }
|
||||||
|
|
||||||
void updateObservers();
|
void updateObservers();
|
||||||
|
@ -79,16 +79,16 @@ public:
|
||||||
|
|
||||||
void setGetNewBlocksLimit(size_t maxBlocks) { m_getMaxBlocks = maxBlocks; }
|
void setGetNewBlocksLimit(size_t maxBlocks) { m_getMaxBlocks = maxBlocks; }
|
||||||
|
|
||||||
virtual uint32_t getLastLocalBlockHeight() const { return static_cast<uint32_t>(m_blockchainGenerator.getBlockchain().size() - 1); }
|
virtual uint32_t getLastLocalBlockHeight() const override { return static_cast<uint32_t>(m_blockchainGenerator.getBlockchain().size() - 1); }
|
||||||
virtual uint32_t getLastKnownBlockHeight() const { return static_cast<uint32_t>(m_blockchainGenerator.getBlockchain().size() - 1); }
|
virtual uint32_t getLastKnownBlockHeight() const override { return static_cast<uint32_t>(m_blockchainGenerator.getBlockchain().size() - 1); }
|
||||||
|
|
||||||
virtual uint32_t getLocalBlockCount() const override { return static_cast<uint32_t>(m_blockchainGenerator.getBlockchain().size()); }
|
virtual uint32_t getLocalBlockCount() const override { return static_cast<uint32_t>(m_blockchainGenerator.getBlockchain().size()); }
|
||||||
virtual uint32_t getKnownBlockCount() const override { return static_cast<uint32_t>(m_blockchainGenerator.getBlockchain().size()); }
|
virtual uint32_t getKnownBlockCount() const override { return static_cast<uint32_t>(m_blockchainGenerator.getBlockchain().size()); }
|
||||||
|
|
||||||
virtual void getNewBlocks(std::vector<Crypto::Hash>&& knownBlockIds, std::vector<CryptoNote::block_complete_entry>& newBlocks, uint32_t& startHeight, const Callback& callback);
|
virtual void getNewBlocks(std::vector<Crypto::Hash>&& knownBlockIds, std::vector<CryptoNote::block_complete_entry>& newBlocks, uint32_t& startHeight, const Callback& callback) override;
|
||||||
|
|
||||||
virtual void relayTransaction(const CryptoNote::Transaction& transaction, const Callback& callback);
|
virtual void relayTransaction(const CryptoNote::Transaction& transaction, const Callback& callback) override;
|
||||||
virtual void getRandomOutsByAmounts(std::vector<uint64_t>&& amounts, uint64_t outsCount, std::vector<CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount>& result, const Callback& callback);
|
virtual void getRandomOutsByAmounts(std::vector<uint64_t>&& amounts, uint64_t outsCount, std::vector<CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount>& result, const Callback& callback) override;
|
||||||
virtual void getTransactionOutsGlobalIndices(const Crypto::Hash& transactionHash, std::vector<uint32_t>& outsGlobalIndices, const Callback& callback) override;
|
virtual void getTransactionOutsGlobalIndices(const Crypto::Hash& transactionHash, std::vector<uint32_t>& outsGlobalIndices, const Callback& callback) override;
|
||||||
virtual void queryBlocks(std::vector<Crypto::Hash>&& knownBlockIds, uint64_t timestamp, std::vector<CryptoNote::BlockShortEntry>& newBlocks, uint32_t& startHeight, const Callback& callback) override;
|
virtual void queryBlocks(std::vector<Crypto::Hash>&& knownBlockIds, uint64_t timestamp, std::vector<CryptoNote::BlockShortEntry>& newBlocks, uint32_t& startHeight, const Callback& callback) override;
|
||||||
virtual void getPoolSymmetricDifference(std::vector<Crypto::Hash>&& known_pool_tx_ids, Crypto::Hash known_block_id, bool& is_bc_actual,
|
virtual void getPoolSymmetricDifference(std::vector<Crypto::Hash>&& known_pool_tx_ids, Crypto::Hash known_block_id, bool& is_bc_actual,
|
||||||
|
|
|
@ -1049,7 +1049,7 @@ TEST_F(BcSTest, checkBlocksRequesting) {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
uint32_t blocksExpected = 20;
|
size_t blocksExpected = 20;
|
||||||
|
|
||||||
generator.generateEmptyBlocks(blocksExpected - 1); //-1 for genesis
|
generator.generateEmptyBlocks(blocksExpected - 1); //-1 for genesis
|
||||||
m_node.setGetNewBlocksLimit(3);
|
m_node.setGetNewBlocksLimit(3);
|
||||||
|
@ -1085,7 +1085,7 @@ TEST_F(BcSTest, checkConsumerHeightReceived) {
|
||||||
|
|
||||||
uint32_t firstlySnchronizedHeight = 20;
|
uint32_t firstlySnchronizedHeight = 20;
|
||||||
|
|
||||||
generator.generateEmptyBlocks(firstlySnchronizedHeight - 1);//-1 for genesis
|
generator.generateEmptyBlocks(static_cast<size_t>(firstlySnchronizedHeight - 1));//-1 for genesis
|
||||||
m_node.setGetNewBlocksLimit(50);
|
m_node.setGetNewBlocksLimit(50);
|
||||||
|
|
||||||
c.onNewBlocksFunctor = [&](const CompleteBlock*, uint32_t startHeight, size_t) -> bool {
|
c.onNewBlocksFunctor = [&](const CompleteBlock*, uint32_t startHeight, size_t) -> bool {
|
||||||
|
|
|
@ -1103,7 +1103,7 @@ TEST_F(BlockchainExplorerTests, getBlocksByTimestampNotInited) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlockchainExplorerTests, generatedTransactions) {
|
TEST_F(BlockchainExplorerTests, generatedTransactions) {
|
||||||
const uint32_t NUMBER_OF_BLOCKS = 10;
|
const size_t NUMBER_OF_BLOCKS = 10;
|
||||||
const size_t POOL_TX_NUMBER = 10;
|
const size_t POOL_TX_NUMBER = 10;
|
||||||
std::vector<uint32_t> blockHeights;
|
std::vector<uint32_t> blockHeights;
|
||||||
for (uint32_t i = 0; i < NUMBER_OF_BLOCKS + 3; ++i) {
|
for (uint32_t i = 0; i < NUMBER_OF_BLOCKS + 3; ++i) {
|
||||||
|
|
|
@ -134,11 +134,11 @@ void TestBlockchainGenerator::addMiningBlock() {
|
||||||
m_generatedTransactionsIndex.add(block);
|
m_generatedTransactionsIndex.add(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestBlockchainGenerator::generateEmptyBlocks(uint32_t count)
|
void TestBlockchainGenerator::generateEmptyBlocks(size_t count)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < count; ++i)
|
for (size_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
CryptoNote::Block& prev_block = m_blockchain.back();
|
CryptoNote::Block& prev_block = m_blockchain.back();
|
||||||
CryptoNote::Block block;
|
CryptoNote::Block block;
|
||||||
|
@ -359,11 +359,11 @@ void TestBlockchainGenerator::addTx(const CryptoNote::Transaction& tx) {
|
||||||
const auto& out = tx.outputs[outIndex];
|
const auto& out = tx.outputs[outIndex];
|
||||||
if (out.target.type() == typeid(KeyOutput)) {
|
if (out.target.type() == typeid(KeyOutput)) {
|
||||||
auto& keyOutsContainer = keyOutsIndex[out.amount];
|
auto& keyOutsContainer = keyOutsIndex[out.amount];
|
||||||
globalIndexes.push_back(keyOutsContainer.size());
|
globalIndexes.push_back(static_cast<uint32_t>(keyOutsContainer.size()));
|
||||||
keyOutsContainer.push_back({ txHash, outIndex });
|
keyOutsContainer.push_back({ txHash, outIndex });
|
||||||
} else if (out.target.type() == typeid(MultisignatureOutput)) {
|
} else if (out.target.type() == typeid(MultisignatureOutput)) {
|
||||||
auto& msigOutsContainer = multisignatureOutsIndex[out.amount];
|
auto& msigOutsContainer = multisignatureOutsIndex[out.amount];
|
||||||
globalIndexes.push_back(msigOutsContainer.size());
|
globalIndexes.push_back(static_cast<uint32_t>(msigOutsContainer.size()));
|
||||||
msigOutsContainer.push_back({ txHash, outIndex });
|
msigOutsContainer.push_back({ txHash, outIndex });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ public:
|
||||||
//TODO: get rid of this method
|
//TODO: get rid of this method
|
||||||
std::vector<CryptoNote::Block>& getBlockchain();
|
std::vector<CryptoNote::Block>& getBlockchain();
|
||||||
std::vector<CryptoNote::Block> getBlockchainCopy();
|
std::vector<CryptoNote::Block> getBlockchainCopy();
|
||||||
void generateEmptyBlocks(uint32_t count);
|
void generateEmptyBlocks(size_t count);
|
||||||
bool getBlockRewardForAddress(const CryptoNote::AccountPublicAddress& address);
|
bool getBlockRewardForAddress(const CryptoNote::AccountPublicAddress& address);
|
||||||
bool generateTransactionsInOneBlock(const CryptoNote::AccountPublicAddress& address, size_t n);
|
bool generateTransactionsInOneBlock(const CryptoNote::AccountPublicAddress& address, size_t n);
|
||||||
bool getSingleOutputTransaction(const CryptoNote::AccountPublicAddress& address, uint64_t amount);
|
bool getSingleOutputTransaction(const CryptoNote::AccountPublicAddress& address, uint64_t amount);
|
||||||
|
|
|
@ -267,7 +267,7 @@ TEST_F(InProcessNodeTests, getBlocksByHeightEmpty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InProcessNodeTests, getBlocksByHeightMany) {
|
TEST_F(InProcessNodeTests, getBlocksByHeightMany) {
|
||||||
const uint32_t NUMBER_OF_BLOCKS = 10;
|
const size_t NUMBER_OF_BLOCKS = 10;
|
||||||
|
|
||||||
std::vector<uint32_t> blockHeights;
|
std::vector<uint32_t> blockHeights;
|
||||||
std::vector<std::vector<CryptoNote::BlockDetails>> actualBlocks;
|
std::vector<std::vector<CryptoNote::BlockDetails>> actualBlocks;
|
||||||
|
@ -311,7 +311,7 @@ TEST_F(InProcessNodeTests, getBlocksByHeightMany) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InProcessNodeTests, getBlocksByHeightFail) {
|
TEST_F(InProcessNodeTests, getBlocksByHeightFail) {
|
||||||
const uint32_t NUMBER_OF_BLOCKS = 10;
|
const size_t NUMBER_OF_BLOCKS = 10;
|
||||||
|
|
||||||
std::vector<uint32_t> blockHeights;
|
std::vector<uint32_t> blockHeights;
|
||||||
std::vector<std::vector<CryptoNote::BlockDetails>> actualBlocks;
|
std::vector<std::vector<CryptoNote::BlockDetails>> actualBlocks;
|
||||||
|
@ -366,7 +366,7 @@ TEST_F(InProcessNodeTests, getBlocksByHashEmpty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InProcessNodeTests, getBlocksByHashMany) {
|
TEST_F(InProcessNodeTests, getBlocksByHashMany) {
|
||||||
const uint32_t NUMBER_OF_BLOCKS = 10;
|
const size_t NUMBER_OF_BLOCKS = 10;
|
||||||
|
|
||||||
std::vector<Crypto::Hash> blockHashes;
|
std::vector<Crypto::Hash> blockHashes;
|
||||||
std::vector<CryptoNote::BlockDetails> actualBlocks;
|
std::vector<CryptoNote::BlockDetails> actualBlocks;
|
||||||
|
@ -407,7 +407,7 @@ TEST_F(InProcessNodeTests, getBlocksByHashMany) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InProcessNodeTests, getBlocksByHashFail) {
|
TEST_F(InProcessNodeTests, getBlocksByHashFail) {
|
||||||
const uint32_t NUMBER_OF_BLOCKS = 10;
|
const size_t NUMBER_OF_BLOCKS = 10;
|
||||||
|
|
||||||
std::vector<Crypto::Hash> blockHashes;
|
std::vector<Crypto::Hash> blockHashes;
|
||||||
std::vector<CryptoNote::BlockDetails> actualBlocks;
|
std::vector<CryptoNote::BlockDetails> actualBlocks;
|
||||||
|
|
|
@ -437,7 +437,7 @@ TEST_F(TransfersConsumerTest, onNewBlocks_getTransactionOutsGlobalIndicesError)
|
||||||
block.transactions.push_back(tx);
|
block.transactions.push_back(tx);
|
||||||
|
|
||||||
consumer.addSubscription(subscription);
|
consumer.addSubscription(subscription);
|
||||||
ASSERT_FALSE(consumer.onNewBlocks(&block, subscription.syncStart.height, 1));
|
ASSERT_FALSE(consumer.onNewBlocks(&block, static_cast<uint32_t>(subscription.syncStart.height), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TransfersConsumerTest, onNewBlocks_updateHeight) {
|
TEST_F(TransfersConsumerTest, onNewBlocks_updateHeight) {
|
||||||
|
@ -457,7 +457,7 @@ TEST_F(TransfersConsumerTest, onNewBlocks_updateHeight) {
|
||||||
block.block->timestamp = subscription.syncStart.timestamp;
|
block.block->timestamp = subscription.syncStart.timestamp;
|
||||||
block.transactions.push_back(tx);
|
block.transactions.push_back(tx);
|
||||||
|
|
||||||
ASSERT_TRUE(m_consumer.onNewBlocks(&block, subscription.syncStart.height, 1));
|
ASSERT_TRUE(m_consumer.onNewBlocks(&block, static_cast<uint32_t>(subscription.syncStart.height), 1));
|
||||||
ASSERT_EQ(900, container.balance(ITransfersContainer::IncludeAllLocked));
|
ASSERT_EQ(900, container.balance(ITransfersContainer::IncludeAllLocked));
|
||||||
|
|
||||||
std::unique_ptr<CompleteBlock[]> blocks(new CompleteBlock[subscription.transactionSpendableAge]);
|
std::unique_ptr<CompleteBlock[]> blocks(new CompleteBlock[subscription.transactionSpendableAge]);
|
||||||
|
@ -468,7 +468,7 @@ TEST_F(TransfersConsumerTest, onNewBlocks_updateHeight) {
|
||||||
addTestKeyOutput(*tr, 100, i + 1, generateAccountKeys());
|
addTestKeyOutput(*tr, 100, i + 1, generateAccountKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_TRUE(m_consumer.onNewBlocks(blocks.get(), subscription.syncStart.height + 1, subscription.transactionSpendableAge));
|
ASSERT_TRUE(m_consumer.onNewBlocks(blocks.get(), static_cast<uint32_t>(subscription.syncStart.height + 1), static_cast<uint32_t>(subscription.transactionSpendableAge)));
|
||||||
ASSERT_EQ(0, container.balance(ITransfersContainer::IncludeAllLocked));
|
ASSERT_EQ(0, container.balance(ITransfersContainer::IncludeAllLocked));
|
||||||
ASSERT_EQ(900, container.balance(ITransfersContainer::IncludeAllUnlocked));
|
ASSERT_EQ(900, container.balance(ITransfersContainer::IncludeAllUnlocked));
|
||||||
}
|
}
|
||||||
|
@ -792,7 +792,7 @@ TEST_F(TransfersConsumerTest, onNewBlocks_manyBlocks) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_TRUE(m_consumer.onNewBlocks(&blocks[0], 0, blocks.size()));
|
ASSERT_TRUE(m_consumer.onNewBlocks(&blocks[0], 0, static_cast<uint32_t>(blocks.size())));
|
||||||
|
|
||||||
ASSERT_EQ(expectedTransactions, container.transactionsCount());
|
ASSERT_EQ(expectedTransactions, container.transactionsCount());
|
||||||
ASSERT_EQ(expectedAmount, container.balance(ITransfersContainer::IncludeAll));
|
ASSERT_EQ(expectedAmount, container.balance(ITransfersContainer::IncludeAll));
|
||||||
|
@ -1031,7 +1031,7 @@ TEST_F(TransfersConsumerPerformanceTest, DISABLED_memory) {
|
||||||
|
|
||||||
{
|
{
|
||||||
AutoPrintTimer t;
|
AutoPrintTimer t;
|
||||||
ASSERT_TRUE(m_consumer.onNewBlocks(&blocks[0], 0, blocks.size()));
|
ASSERT_TRUE(m_consumer.onNewBlocks(&blocks[0], 0, static_cast<uint32_t>(blocks.size())));
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks.clear();
|
blocks.clear();
|
||||||
|
@ -1056,7 +1056,7 @@ TEST_F(TransfersConsumerPerformanceTest, DISABLED_performanceTest) {
|
||||||
|
|
||||||
std::cout << "Calling onNewBlocks" << std::endl;
|
std::cout << "Calling onNewBlocks" << std::endl;
|
||||||
|
|
||||||
ASSERT_TRUE(m_consumer.onNewBlocks(&blocks[0], 0, blocks.size()));
|
ASSERT_TRUE(m_consumer.onNewBlocks(&blocks[0], 0, static_cast<uint32_t>(blocks.size())));
|
||||||
|
|
||||||
auto end = std::chrono::steady_clock::now();
|
auto end = std::chrono::steady_clock::now();
|
||||||
std::chrono::duration<double> dur = end - start;
|
std::chrono::duration<double> dur = end - start;
|
||||||
|
|
|
@ -54,9 +54,13 @@ namespace CryptoNote {
|
||||||
case WalletTransactionState::SUCCEEDED:
|
case WalletTransactionState::SUCCEEDED:
|
||||||
o << "SUCCEEDED";
|
o << "SUCCEEDED";
|
||||||
break;
|
break;
|
||||||
|
case WalletTransactionState::CREATED:
|
||||||
|
o << "CREATED";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, const WalletTransaction& tx) {
|
std::ostream& operator<<(std::ostream& o, const WalletTransaction& tx) {
|
||||||
o << "WalletTransaction{state=" << tx.state << ", timestamp=" << tx.timestamp
|
o << "WalletTransaction{state=" << tx.state << ", timestamp=" << tx.timestamp
|
||||||
<< ", blockHeight=" << tx.blockHeight << ", hash=" << tx.hash
|
<< ", blockHeight=" << tx.blockHeight << ", hash=" << tx.hash
|
||||||
|
@ -123,6 +127,10 @@ namespace CryptoNote {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lhs.type != rhs.type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,8 +193,10 @@ protected:
|
||||||
size_t sendMoneyToRandomAddressFrom(const std::string& address, uint64_t amount, uint64_t fee);
|
size_t sendMoneyToRandomAddressFrom(const std::string& address, uint64_t amount, uint64_t fee);
|
||||||
size_t sendMoneyToRandomAddressFrom(const std::string& address);
|
size_t sendMoneyToRandomAddressFrom(const std::string& address);
|
||||||
|
|
||||||
size_t sendMoney(CryptoNote::WalletGreen& wallet, const std::string& to, int64_t amount, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0);
|
size_t sendMoney(CryptoNote::WalletGreen& wallet, const std::string& to, uint64_t amount, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0);
|
||||||
size_t sendMoney(const std::string& to, int64_t amount, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0);
|
size_t sendMoney(const std::string& to, uint64_t amount, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0);
|
||||||
|
size_t sendMoneyWithDonation(const std::string& to, uint64_t amount, uint64_t fee,
|
||||||
|
const std::string& donationAddress, uint64_t donationAmount, uint64_t mixIn = 0, const std::string& extra = "", uint64_t unlockTimestamp = 0);
|
||||||
|
|
||||||
void fillWalletWithDetailsCache();
|
void fillWalletWithDetailsCache();
|
||||||
|
|
||||||
|
@ -401,11 +411,11 @@ void WalletApi::generateAddressesWithPendingMoney(size_t count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletApi::sendMoneyToRandomAddressFrom(const std::string& address, uint64_t amount, uint64_t fee) {
|
size_t WalletApi::sendMoneyToRandomAddressFrom(const std::string& address, uint64_t amount, uint64_t fee) {
|
||||||
CryptoNote::WalletTransfer transfer;
|
CryptoNote::WalletOrder order;
|
||||||
transfer.address = RANDOM_ADDRESS;
|
order.address = RANDOM_ADDRESS;
|
||||||
transfer.amount = amount;
|
order.amount = amount;
|
||||||
|
|
||||||
return alice.transfer(address, transfer, fee, 0);
|
return alice.transfer(address, order, fee, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletApi::sendMoneyToRandomAddressFrom(const std::string& address) {
|
size_t WalletApi::sendMoneyToRandomAddressFrom(const std::string& address) {
|
||||||
|
@ -429,18 +439,33 @@ void WalletApi::fillWalletWithDetailsCache() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletApi::sendMoney(CryptoNote::WalletGreen& wallet, const std::string& to, int64_t amount, uint64_t fee, uint64_t mixIn, const std::string& extra, uint64_t unlockTimestamp) {
|
size_t WalletApi::sendMoney(CryptoNote::WalletGreen& wallet, const std::string& to, uint64_t amount, uint64_t fee, uint64_t mixIn, const std::string& extra, uint64_t unlockTimestamp) {
|
||||||
CryptoNote::WalletTransfer transfer;
|
CryptoNote::WalletOrder order;
|
||||||
transfer.address = to;
|
order.address = to;
|
||||||
transfer.amount = amount;
|
order.amount = amount;
|
||||||
|
|
||||||
return wallet.transfer(transfer, fee, mixIn, extra, unlockTimestamp);
|
return wallet.transfer(order, fee, mixIn, extra, unlockTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WalletApi::sendMoney(const std::string& to, int64_t amount, uint64_t fee, uint64_t mixIn, const std::string& extra, uint64_t unlockTimestamp) {
|
size_t WalletApi::sendMoney(const std::string& to, uint64_t amount, uint64_t fee, uint64_t mixIn, const std::string& extra, uint64_t unlockTimestamp) {
|
||||||
return sendMoney(alice, to, amount, fee, mixIn, extra, unlockTimestamp);
|
return sendMoney(alice, to, amount, fee, mixIn, extra, unlockTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t WalletApi::sendMoneyWithDonation(const std::string& to, uint64_t amount, uint64_t fee,
|
||||||
|
const std::string& donationAddress, uint64_t donationAmount, uint64_t mixIn, const std::string& extra, uint64_t unlockTimestamp) {
|
||||||
|
|
||||||
|
TransactionParameters params;
|
||||||
|
params.destinations.push_back({to, amount});
|
||||||
|
params.fee = fee;
|
||||||
|
params.donation.address = donationAddress;
|
||||||
|
params.donation.threshold = donationAmount;
|
||||||
|
params.mixIn = mixIn;
|
||||||
|
params.extra = extra;
|
||||||
|
params.unlockTimestamp = unlockTimestamp;
|
||||||
|
|
||||||
|
return alice.transfer(params);
|
||||||
|
}
|
||||||
|
|
||||||
void WalletApi::wait(uint64_t milliseconds) {
|
void WalletApi::wait(uint64_t milliseconds) {
|
||||||
System::Timer timer(dispatcher);
|
System::Timer timer(dispatcher);
|
||||||
timer.sleep(std::chrono::nanoseconds(milliseconds * 1000000));
|
timer.sleep(std::chrono::nanoseconds(milliseconds * 1000000));
|
||||||
|
@ -510,7 +535,7 @@ TEST_F(WalletApi, pendingBalanceUpdatedAfterTransactionGotInBlock) {
|
||||||
|
|
||||||
auto prevPending = alice.getPendingBalance();
|
auto prevPending = alice.getPendingBalance();
|
||||||
|
|
||||||
generator.generateEmptyBlocks(TRANSACTION_SOFTLOCK_TIME);
|
generator.generateEmptyBlocks(static_cast<size_t>(TRANSACTION_SOFTLOCK_TIME));
|
||||||
node.updateObservers();
|
node.updateObservers();
|
||||||
|
|
||||||
waitPendingBalanceUpdated(prevPending);
|
waitPendingBalanceUpdated(prevPending);
|
||||||
|
@ -524,7 +549,7 @@ TEST_F(WalletApi, moneyLockedIfTransactionIsSoftLocked) {
|
||||||
bob.initialize("pass2");
|
bob.initialize("pass2");
|
||||||
|
|
||||||
sendMoney(bob.createAddress(), SENT, FEE);
|
sendMoney(bob.createAddress(), SENT, FEE);
|
||||||
generator.generateEmptyBlocks(TRANSACTION_SOFTLOCK_TIME - 1);
|
generator.generateEmptyBlocks(static_cast<size_t>(TRANSACTION_SOFTLOCK_TIME - 1));
|
||||||
node.updateObservers();
|
node.updateObservers();
|
||||||
|
|
||||||
waitPendingBalanceUpdated(bob, 0);
|
waitPendingBalanceUpdated(bob, 0);
|
||||||
|
@ -598,7 +623,11 @@ TEST_F(WalletApi, transferFromTwoAddresses) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WalletApi, transferTooBigTransaction) {
|
TEST_F(WalletApi, transferTooBigTransaction) {
|
||||||
CryptoNote::Currency cur = CryptoNote::CurrencyBuilder(logger).blockGrantedFullRewardZone(5).minerTxBlobReservedSize(2).currency();
|
const size_t testBlockGrantedFullRewardZone = 2000;
|
||||||
|
const size_t outputSize = 32 + 1;
|
||||||
|
const size_t bigTxOutputCount = 2 * testBlockGrantedFullRewardZone / outputSize;
|
||||||
|
|
||||||
|
CryptoNote::Currency cur = CryptoNote::CurrencyBuilder(logger).blockGrantedFullRewardZone(testBlockGrantedFullRewardZone).currency();
|
||||||
TestBlockchainGenerator gen(cur);
|
TestBlockchainGenerator gen(cur);
|
||||||
INodeTrivialRefreshStub n(gen);
|
INodeTrivialRefreshStub n(gen);
|
||||||
|
|
||||||
|
@ -613,11 +642,12 @@ TEST_F(WalletApi, transferTooBigTransaction) {
|
||||||
n.updateObservers();
|
n.updateObservers();
|
||||||
waitActualBalanceUpdated(wallet, prev);
|
waitActualBalanceUpdated(wallet, prev);
|
||||||
|
|
||||||
CryptoNote::WalletTransfer transfer;
|
std::vector<CryptoNote::WalletOrder> destinations;
|
||||||
transfer.address = RANDOM_ADDRESS;
|
for (size_t i = 0; i < bigTxOutputCount; ++i) {
|
||||||
transfer.amount = SENT;
|
destinations.push_back({ RANDOM_ADDRESS, 1 });
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_ANY_THROW(wallet.transfer(transfer, FEE));
|
ASSERT_ANY_THROW(wallet.transfer(destinations, FEE));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WalletApi, balanceAfterTransfer) {
|
TEST_F(WalletApi, balanceAfterTransfer) {
|
||||||
|
@ -1272,26 +1302,91 @@ TEST_F(WalletApi, incomingTxTransfer) {
|
||||||
wait(100);
|
wait(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, walletSendsTransactionUpdatedEventAfterAddingTransfer) {
|
||||||
|
generateAndUnlockMoney();
|
||||||
|
|
||||||
|
CryptoNote::WalletGreen bob(dispatcher, currency, node, TRANSACTION_SOFTLOCK_TIME);
|
||||||
|
bob.initialize("pass2");
|
||||||
|
bob.createAddress();
|
||||||
|
bob.createAddress();
|
||||||
|
bob.createAddress();
|
||||||
|
|
||||||
|
std::vector<CryptoNote::WalletOrder> orders;
|
||||||
|
orders.emplace_back(CryptoNote::WalletOrder{ bob.getAddress(0), SENT });
|
||||||
|
orders.emplace_back(CryptoNote::WalletOrder{ bob.getAddress(1), SENT });
|
||||||
|
orders.emplace_back(CryptoNote::WalletOrder{ bob.getAddress(2), SENT });
|
||||||
|
alice.transfer(orders, FEE, 0, "", 0);
|
||||||
|
|
||||||
|
node.updateObservers();
|
||||||
|
ASSERT_TRUE(waitForWalletEvent(bob, CryptoNote::WalletEventType::TRANSACTION_CREATED, std::chrono::seconds(5)));
|
||||||
|
ASSERT_TRUE(waitForWalletEvent(bob, CryptoNote::WalletEventType::TRANSACTION_UPDATED, std::chrono::seconds(5)));
|
||||||
|
ASSERT_TRUE(waitForWalletEvent(bob, CryptoNote::WalletEventType::TRANSACTION_UPDATED, std::chrono::seconds(5)));
|
||||||
|
|
||||||
|
bob.shutdown();
|
||||||
|
wait(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, walletCreatesTransferForEachTransactionFunding) {
|
||||||
|
generateAndUnlockMoney();
|
||||||
|
|
||||||
|
CryptoNote::WalletGreen bob(dispatcher, currency, node, TRANSACTION_SOFTLOCK_TIME);
|
||||||
|
bob.initialize("pass2");
|
||||||
|
bob.createAddress();
|
||||||
|
bob.createAddress();
|
||||||
|
|
||||||
|
std::vector<CryptoNote::WalletOrder> orders;
|
||||||
|
orders.emplace_back(CryptoNote::WalletOrder{ bob.getAddress(0), SENT });
|
||||||
|
orders.emplace_back(CryptoNote::WalletOrder{ bob.getAddress(1), 2 * SENT });
|
||||||
|
alice.transfer(orders, FEE, 0, "", 0);
|
||||||
|
|
||||||
|
node.updateObservers();
|
||||||
|
ASSERT_TRUE(waitForWalletEvent(bob, CryptoNote::WalletEventType::TRANSACTION_UPDATED, std::chrono::seconds(5)));
|
||||||
|
|
||||||
|
ASSERT_EQ(2, bob.getTransactionTransferCount(0));
|
||||||
|
auto tr1 = bob.getTransactionTransfer(0, 0);
|
||||||
|
auto tr2 = bob.getTransactionTransfer(0, 1);
|
||||||
|
ASSERT_TRUE(tr1.address == bob.getAddress(0) || tr1.address == bob.getAddress(1));
|
||||||
|
ASSERT_TRUE(tr2.address == bob.getAddress(0) || tr2.address == bob.getAddress(1));
|
||||||
|
ASSERT_NE(tr1.address, tr2.address);
|
||||||
|
|
||||||
|
bob.shutdown();
|
||||||
|
wait(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getTransactionUsualTransferCount(WalletGreen& wallet, size_t transactionIndex) {
|
||||||
|
size_t transfersCount = wallet.getTransactionTransferCount(transactionIndex);
|
||||||
|
size_t usualTransfersCount = 0;
|
||||||
|
for (size_t i = 0; i < transfersCount; ++i) {
|
||||||
|
if (wallet.getTransactionTransfer(transactionIndex, i).type == WalletTransferType::USUAL) {
|
||||||
|
++usualTransfersCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return usualTransfersCount;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WalletApi, hybridTxTransfer) {
|
TEST_F(WalletApi, hybridTxTransfer) {
|
||||||
generateAndUnlockMoney();
|
generateAndUnlockMoney();
|
||||||
|
|
||||||
alice.createAddress();
|
alice.createAddress();
|
||||||
alice.createAddress();
|
alice.createAddress();
|
||||||
|
|
||||||
CryptoNote::WalletTransfer tr1 { alice.getAddress(1), static_cast<int64_t>(SENT) };
|
CryptoNote::WalletOrder tr1 { alice.getAddress(1), SENT };
|
||||||
CryptoNote::WalletTransfer tr2 { alice.getAddress(2), static_cast<int64_t>(2 * SENT) };
|
CryptoNote::WalletOrder tr2 { alice.getAddress(2), 2 * SENT };
|
||||||
|
|
||||||
alice.transfer({tr1, tr2}, FEE);
|
alice.transfer({tr1, tr2}, FEE);
|
||||||
node.updateObservers();
|
node.updateObservers();
|
||||||
dispatcher.yield();
|
dispatcher.yield();
|
||||||
|
|
||||||
ASSERT_EQ(2, alice.getTransactionTransferCount(1));
|
ASSERT_EQ(2, getTransactionUsualTransferCount(alice, 1));
|
||||||
|
|
||||||
EXPECT_EQ(tr1.address, alice.getTransactionTransfer(1, 0).address);
|
EXPECT_EQ(tr1.address, alice.getTransactionTransfer(1, 0).address);
|
||||||
EXPECT_EQ(-tr1.amount, alice.getTransactionTransfer(1, 0).amount);
|
EXPECT_EQ(-static_cast<int64_t>(tr1.amount), alice.getTransactionTransfer(1, 0).amount);
|
||||||
|
EXPECT_EQ(WalletTransferType::USUAL, alice.getTransactionTransfer(1, 0).type);
|
||||||
|
|
||||||
EXPECT_EQ(tr2.address, alice.getTransactionTransfer(1, 1).address);
|
EXPECT_EQ(tr2.address, alice.getTransactionTransfer(1, 1).address);
|
||||||
EXPECT_EQ(-tr2.amount, alice.getTransactionTransfer(1, 1).amount);
|
EXPECT_EQ(-static_cast<int64_t>(tr2.amount), alice.getTransactionTransfer(1, 1).amount);
|
||||||
|
EXPECT_EQ(WalletTransferType::USUAL, alice.getTransactionTransfer(1, 1).type);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WalletApi, doubleSpendJustSentOut) {
|
TEST_F(WalletApi, doubleSpendJustSentOut) {
|
||||||
|
@ -1384,7 +1479,7 @@ TEST_F(WalletApi, DISABLED_loadTest) {
|
||||||
|
|
||||||
steady_clock::time_point transferStart = steady_clock::now();
|
steady_clock::time_point transferStart = steady_clock::now();
|
||||||
for (size_t i = 0; i < TRANSACTIONS_COUNT; ++i) {
|
for (size_t i = 0; i < TRANSACTIONS_COUNT; ++i) {
|
||||||
CryptoNote::WalletTransfer tr;
|
CryptoNote::WalletOrder tr;
|
||||||
tr.amount = SENT;
|
tr.amount = SENT;
|
||||||
tr.address = RANDOM_ADDRESS;
|
tr.address = RANDOM_ADDRESS;
|
||||||
wallet.transfer(tr, FEE);
|
wallet.transfer(tr, FEE);
|
||||||
|
@ -1839,10 +1934,10 @@ TEST_F(WalletApi, fusionManagerIsFusionTransactionSpent) {
|
||||||
ASSERT_NE(WALLET_INVALID_TRANSACTION_ID, id);
|
ASSERT_NE(WALLET_INVALID_TRANSACTION_ID, id);
|
||||||
|
|
||||||
unlockMoney();
|
unlockMoney();
|
||||||
CryptoNote::WalletTransfer transfer;
|
CryptoNote::WalletOrder order;
|
||||||
transfer.address = wallet.getAddress(0);
|
order.address = wallet.getAddress(0);
|
||||||
transfer.amount = alice.getActualBalance() - currency.minimumFee();
|
order.amount = alice.getActualBalance() - currency.minimumFee();
|
||||||
alice.transfer(aliceAddress, transfer, currency.minimumFee(), 0);
|
alice.transfer(aliceAddress, order, currency.minimumFee(), 0);
|
||||||
|
|
||||||
auto pending = wallet.getPendingBalance();
|
auto pending = wallet.getPendingBalance();
|
||||||
node.updateObservers();
|
node.updateObservers();
|
||||||
|
@ -1851,3 +1946,123 @@ TEST_F(WalletApi, fusionManagerIsFusionTransactionSpent) {
|
||||||
ASSERT_TRUE(alice.isFusionTransaction(id));
|
ASSERT_TRUE(alice.isFusionTransaction(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t findDonationTransferId(const WalletGreen& wallet, size_t transactionId) {
|
||||||
|
for (size_t i = 0; i < wallet.getTransactionTransferCount(transactionId); ++i) {
|
||||||
|
if (wallet.getTransactionTransfer(transactionId, i).type == WalletTransferType::DONATION) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WALLET_INVALID_TRANSFER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, donationTransferPresents) {
|
||||||
|
const uint64_t DONATION_THRESHOLD = 1000000;
|
||||||
|
|
||||||
|
generator.getSingleOutputTransaction(parseAddress(aliceAddress), SENT + FEE + DONATION_THRESHOLD);
|
||||||
|
unlockMoney();
|
||||||
|
|
||||||
|
auto transactionId = sendMoneyWithDonation(RANDOM_ADDRESS, SENT, FEE, RANDOM_ADDRESS, DONATION_THRESHOLD);
|
||||||
|
|
||||||
|
ASSERT_NE(WALLET_INVALID_TRANSACTION_ID, transactionId);
|
||||||
|
|
||||||
|
auto donationTransferId = findDonationTransferId(alice, transactionId);
|
||||||
|
ASSERT_NE(WALLET_INVALID_TRANSFER_ID, donationTransferId);
|
||||||
|
|
||||||
|
auto donationTransfer = alice.getTransactionTransfer(transactionId, donationTransferId);
|
||||||
|
ASSERT_EQ(WalletTransferType::DONATION, donationTransfer.type);
|
||||||
|
ASSERT_EQ(-static_cast<int64_t>(DONATION_THRESHOLD), donationTransfer.amount);
|
||||||
|
ASSERT_EQ(RANDOM_ADDRESS, donationTransfer.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, donationDidntHappenIfNotEnoughMoney) {
|
||||||
|
const uint64_t DONATION_THRESHOLD = 1000000;
|
||||||
|
|
||||||
|
generator.getSingleOutputTransaction(parseAddress(aliceAddress), SENT + FEE);
|
||||||
|
unlockMoney();
|
||||||
|
|
||||||
|
auto transactionId = sendMoneyWithDonation(RANDOM_ADDRESS, SENT, FEE, RANDOM_ADDRESS, DONATION_THRESHOLD);
|
||||||
|
ASSERT_NE(WALLET_INVALID_TRANSACTION_ID, transactionId);
|
||||||
|
ASSERT_EQ(WALLET_INVALID_TRANSFER_ID, findDonationTransferId(alice, transactionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, donationThrowsIfAddressEmpty) {
|
||||||
|
const uint64_t DONATION_THRESHOLD = 1000000;
|
||||||
|
|
||||||
|
generator.getSingleOutputTransaction(parseAddress(aliceAddress), SENT + FEE + DONATION_THRESHOLD);
|
||||||
|
unlockMoney();
|
||||||
|
|
||||||
|
TransactionParameters params;
|
||||||
|
params.destinations.push_back({RANDOM_ADDRESS, SENT});
|
||||||
|
params.fee = FEE;
|
||||||
|
params.donation.threshold = DONATION_THRESHOLD;
|
||||||
|
|
||||||
|
ASSERT_ANY_THROW(alice.transfer(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, donationThrowsIfThresholdZero) {
|
||||||
|
const uint64_t DONATION_THRESHOLD = 1000000;
|
||||||
|
|
||||||
|
generator.getSingleOutputTransaction(parseAddress(aliceAddress), SENT + FEE + DONATION_THRESHOLD);
|
||||||
|
unlockMoney();
|
||||||
|
|
||||||
|
TransactionParameters params;
|
||||||
|
params.destinations.push_back({RANDOM_ADDRESS, SENT});
|
||||||
|
params.fee = FEE;
|
||||||
|
params.donation.address = RANDOM_ADDRESS;
|
||||||
|
params.donation.threshold = 0;
|
||||||
|
|
||||||
|
ASSERT_ANY_THROW(alice.transfer(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, donationTransactionHaveCorrectFee) {
|
||||||
|
CatchTransactionNodeStub catchNode(generator);
|
||||||
|
CryptoNote::WalletGreen wallet(dispatcher, currency, catchNode);
|
||||||
|
wallet.initialize("pass");
|
||||||
|
wallet.createAddress();
|
||||||
|
|
||||||
|
const uint64_t DONATION_THRESHOLD = 1000000;
|
||||||
|
|
||||||
|
generator.getSingleOutputTransaction(parseAddress(wallet.getAddress(0)), SENT + FEE + DONATION_THRESHOLD);
|
||||||
|
unlockMoney(wallet, catchNode);
|
||||||
|
|
||||||
|
TransactionParameters params;
|
||||||
|
params.destinations.push_back({RANDOM_ADDRESS, SENT});
|
||||||
|
params.fee = FEE;
|
||||||
|
params.donation.address = RANDOM_ADDRESS;
|
||||||
|
params.donation.threshold = DONATION_THRESHOLD;
|
||||||
|
|
||||||
|
wallet.transfer(params);
|
||||||
|
|
||||||
|
ASSERT_TRUE(catchNode.caught);
|
||||||
|
ASSERT_EQ(FEE, getInputAmount(catchNode.transaction) - getOutputAmount(catchNode.transaction));
|
||||||
|
|
||||||
|
wallet.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, donationSerialization) {
|
||||||
|
const uint64_t DONATION_THRESHOLD = 1000000;
|
||||||
|
|
||||||
|
generator.getSingleOutputTransaction(parseAddress(aliceAddress), SENT + FEE + DONATION_THRESHOLD);
|
||||||
|
unlockMoney();
|
||||||
|
|
||||||
|
sendMoneyWithDonation(RANDOM_ADDRESS, SENT, FEE, RANDOM_ADDRESS, DONATION_THRESHOLD);
|
||||||
|
|
||||||
|
std::stringstream data;
|
||||||
|
alice.save(data, true, true);
|
||||||
|
|
||||||
|
WalletGreen bob(dispatcher, currency, node, TRANSACTION_SOFTLOCK_TIME);
|
||||||
|
bob.load(data, "pass");
|
||||||
|
|
||||||
|
compareWalletsTransactionTransfers(alice, bob);
|
||||||
|
bob.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WalletApi, transferThrowsIfDonationThresholdTooBig) {
|
||||||
|
const uint64_t DONATION_THRESHOLD = static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1;
|
||||||
|
|
||||||
|
generator.getSingleOutputTransaction(parseAddress(aliceAddress), SENT + FEE);
|
||||||
|
unlockMoney();
|
||||||
|
|
||||||
|
ASSERT_ANY_THROW(sendMoneyWithDonation(RANDOM_ADDRESS, SENT, FEE, RANDOM_ADDRESS, DONATION_THRESHOLD));
|
||||||
|
}
|
||||||
|
|
|
@ -1392,7 +1392,7 @@ TEST_F(WalletLegacyApi, outcommingExternalTransactionTotalAmount) {
|
||||||
wallet.initAndLoad(walletData, "pass");
|
wallet.initAndLoad(walletData, "pass");
|
||||||
WaitWalletSync(&walletObserver);
|
WaitWalletSync(&walletObserver);
|
||||||
|
|
||||||
ASSERT_EQ(-(sent + fee), externalTransactionObserver.totalAmount);
|
ASSERT_EQ(-static_cast<int64_t>(sent + fee), externalTransactionObserver.totalAmount);
|
||||||
wallet.shutdown();
|
wallet.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -701,7 +701,8 @@ const size_t TEST_TX_COUNT_UP_TO_MEDIAN = 10;
|
||||||
const size_t TEST_MAX_TX_COUNT_PER_BLOCK = TEST_TX_COUNT_UP_TO_MEDIAN * 125 / 100;
|
const size_t TEST_MAX_TX_COUNT_PER_BLOCK = TEST_TX_COUNT_UP_TO_MEDIAN * 125 / 100;
|
||||||
const size_t TEST_TRANSACTION_SIZE = 2000;
|
const size_t TEST_TRANSACTION_SIZE = 2000;
|
||||||
const size_t TEST_FUSION_TX_MAX_SIZE = TEST_FUSION_TX_COUNT_PER_BLOCK * TEST_TRANSACTION_SIZE;
|
const size_t TEST_FUSION_TX_MAX_SIZE = TEST_FUSION_TX_COUNT_PER_BLOCK * TEST_TRANSACTION_SIZE;
|
||||||
const size_t TEST_MEDIAN_SIZE = TEST_TX_COUNT_UP_TO_MEDIAN * TEST_TRANSACTION_SIZE;
|
const size_t TEST_MINER_TX_BLOB_RESERVED_SIZE = 600;
|
||||||
|
const size_t TEST_MEDIAN_SIZE = TEST_TX_COUNT_UP_TO_MEDIAN * TEST_TRANSACTION_SIZE + TEST_MINER_TX_BLOB_RESERVED_SIZE;
|
||||||
|
|
||||||
Transaction createTestFusionTransaction(const Currency& currency) {
|
Transaction createTestFusionTransaction(const Currency& currency) {
|
||||||
FusionTransactionBuilder builder(currency, 30 * currency.defaultDustThreshold());
|
FusionTransactionBuilder builder(currency, 30 * currency.defaultDustThreshold());
|
||||||
|
|
Loading…
Reference in a new issue