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 {
|
||||
SUCCEEDED = 0,
|
||||
FAILED,
|
||||
CANCELLED
|
||||
CANCELLED,
|
||||
CREATED
|
||||
};
|
||||
|
||||
enum WalletEventType {
|
||||
|
@ -77,11 +78,37 @@ struct WalletTransaction {
|
|||
bool isBase;
|
||||
};
|
||||
|
||||
enum class WalletTransferType : uint8_t {
|
||||
USUAL = 0,
|
||||
DONATION
|
||||
};
|
||||
|
||||
struct WalletOrder {
|
||||
std::string address;
|
||||
uint64_t amount;
|
||||
};
|
||||
|
||||
struct WalletTransfer {
|
||||
WalletTransferType type;
|
||||
std::string address;
|
||||
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 {
|
||||
public:
|
||||
virtual ~IWallet() {}
|
||||
|
@ -113,10 +140,11 @@ public:
|
|||
virtual size_t getTransactionTransferCount(size_t transactionIndex) 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 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 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 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 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<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 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<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 stop() = 0;
|
||||
|
|
|
@ -78,12 +78,72 @@ private:
|
|||
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) :
|
||||
node(node),
|
||||
logger(logger, "BlockchainExplorer"),
|
||||
state(NOT_INITIALIZED),
|
||||
synchronized(false),
|
||||
observersCounter(0) {}
|
||||
observersCounter(0) {
|
||||
}
|
||||
|
||||
BlockchainExplorer::~BlockchainExplorer() {}
|
||||
|
||||
|
@ -432,6 +492,12 @@ void BlockchainExplorer::poolChanged() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!poolUpdateGuard.beginUpdate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScopeExitHandler poolUpdateEndGuard(std::bind(&BlockchainExplorer::poolUpdateEndHandler, this));
|
||||
|
||||
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>>>();
|
||||
|
@ -454,8 +520,11 @@ void BlockchainExplorer::poolChanged() {
|
|||
);
|
||||
}
|
||||
);
|
||||
|
||||
request.performAsync(asyncContextCounter,
|
||||
[this, rawNewTransactionsPtr, removedTransactionsPtr, isBlockchainActualPtr](std::error_code ec) {
|
||||
ScopeExitHandler poolUpdateEndGuard(std::bind(&BlockchainExplorer::poolUpdateEndHandler, this));
|
||||
|
||||
if (ec) {
|
||||
logger(ERROR) << "Can't send poolChanged notification because can't get pool symmetric difference: " << ec.message();
|
||||
return;
|
||||
|
@ -503,21 +572,34 @@ void BlockchainExplorer::poolChanged() {
|
|||
std::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
request.performAsync(asyncContextCounter,
|
||||
[this, newTransactionsHashesPtr, newTransactionsPtr, removedTransactionsHashesPtr](std::error_code ec) {
|
||||
ScopeExitHandler poolUpdateEndGuard(std::bind(&BlockchainExplorer::poolUpdateEndHandler, this));
|
||||
|
||||
if (ec) {
|
||||
logger(ERROR) << "Can't send poolChanged notification because can't get transactions: " << ec.message();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newTransactionsPtr->empty() || !removedTransactionsHashesPtr->empty()) {
|
||||
observerManager.notify(&IBlockchainObserver::poolUpdated, *newTransactionsPtr, *removedTransactionsHashesPtr);
|
||||
logger(DEBUGGING) << "poolUpdated notification was successfully sent.";
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
poolUpdateEndGuard.reset();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
poolUpdateEndGuard.reset();
|
||||
}
|
||||
|
||||
void BlockchainExplorer::poolUpdateEndHandler() {
|
||||
if (poolUpdateGuard.endUpdate()) {
|
||||
poolChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void BlockchainExplorer::blockchainSynchronized(uint32_t topHeight) {
|
||||
|
|
|
@ -74,6 +74,25 @@ public:
|
|||
typedef WalletAsyncContextCounter AsyncContextCounter;
|
||||
|
||||
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 {
|
||||
NOT_INITIALIZED,
|
||||
INITIALIZED
|
||||
|
@ -94,6 +113,6 @@ private:
|
|||
Logging::LoggerRef logger;
|
||||
|
||||
AsyncContextCounter asyncContextCounter;
|
||||
|
||||
PoolUpdateGuard poolUpdateGuard;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ void readVarint(IInputStream& in, uint64_t& value) {
|
|||
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 == 0 && shift != 0) {
|
||||
throw std::runtime_error("readVarint, invalid value representation");
|
||||
|
|
|
@ -164,7 +164,8 @@ const CheckpointData CHECKPOINTS[] = {
|
|||
{804000, "bcc8b3782499aae508c40d5587d1cc5d68281435ea9bfc6804a262047f7b934d"},
|
||||
{810500, "302b2349f221232820adc3dadafd8a61b035491e33af669c78a687949eb0a381"},
|
||||
{816000, "32b7fdd4e4d715db81f8f09f4ba5e5c78e8113f2804d61a57378baee479ce745"},
|
||||
{822000, "a3c9603c6813a0dc0efc40db288c356d1a7f02d1d2e47bee04346e73715f8984"}
|
||||
{822000, "a3c9603c6813a0dc0efc40db288c356d1a7f02d1d2e47bee04346e73715f8984"},
|
||||
{841000, "2cffb6504ee38f708a6256a63585f9382b3b426e64b4504236c70678bd160dce"}
|
||||
};
|
||||
} // CryptoNote
|
||||
|
||||
|
|
|
@ -48,18 +48,18 @@ namespace CryptoNote {
|
|||
core(const Currency& currency, i_cryptonote_protocol* pprotocol, Logging::ILogger& logger);
|
||||
~core();
|
||||
|
||||
bool on_idle();
|
||||
virtual bool handle_incoming_tx(const BinaryArray& tx_blob, tx_verification_context& tvc, bool keeped_by_block); //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);
|
||||
virtual i_cryptonote_protocol* get_protocol(){return m_pprotocol;}
|
||||
bool on_idle() override;
|
||||
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) override;
|
||||
virtual i_cryptonote_protocol* get_protocol() override {return m_pprotocol;}
|
||||
const Currency& currency() const { return m_currency; }
|
||||
|
||||
//-------------------- IMinerHandler -----------------------
|
||||
virtual bool handle_block_found(Block& b);
|
||||
virtual bool get_block_template(Block& b, const AccountPublicAddress& adr, difficulty_type& diffic, uint32_t& height, const BinaryArray& ex_nonce);
|
||||
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) override;
|
||||
|
||||
bool addObserver(ICoreObserver* observer);
|
||||
bool removeObserver(ICoreObserver* observer);
|
||||
bool addObserver(ICoreObserver* observer) override;
|
||||
bool removeObserver(ICoreObserver* observer) override;
|
||||
|
||||
miner& get_miner() { return *m_miner; }
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
|
@ -93,13 +93,13 @@ namespace CryptoNote {
|
|||
virtual bool removeMessageQueue(MessageQueue<BlockchainMessage>& messageQueue) override;
|
||||
|
||||
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(const Crypto::Hash& startBlockId) override;
|
||||
void on_synchronized();
|
||||
void on_synchronized() 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);
|
||||
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);
|
||||
virtual std::vector<Crypto::Hash> findBlockchainSupplement(const std::vector<Crypto::Hash>& remoteBlockIds, size_t maxCount,
|
||||
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();
|
||||
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);
|
||||
void pause_mining();
|
||||
void update_block_template_and_resume_mining();
|
||||
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() override;
|
||||
void update_block_template_and_resume_mining() override;
|
||||
//Blockchain& get_blockchain_storage(){return m_blockchain;}
|
||||
//debug functions
|
||||
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);
|
||||
|
||||
virtual bool addObserver(ICryptoNoteProtocolObserver* observer);
|
||||
virtual bool removeObserver(ICryptoNoteProtocolObserver* observer);
|
||||
virtual bool addObserver(ICryptoNoteProtocolObserver* observer) override;
|
||||
virtual bool removeObserver(ICryptoNoteProtocolObserver* observer) override;
|
||||
|
||||
void set_p2p_endpoint(IP2pEndpoint* p2p);
|
||||
// ICore& get_core() { return m_core; }
|
||||
|
@ -68,8 +68,8 @@ namespace CryptoNote
|
|||
bool get_payload_sync_data(CORE_SYNC_DATA& hshd);
|
||||
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);
|
||||
virtual size_t getPeerCount() const;
|
||||
virtual uint32_t getObservedHeight() const;
|
||||
virtual size_t getPeerCount() const override;
|
||||
virtual uint32_t getObservedHeight() const override;
|
||||
void requestMissingPoolTransactions(const CryptoNoteConnectionContext& context);
|
||||
|
||||
private:
|
||||
|
|
|
@ -41,7 +41,7 @@ const char* getErrorBody(CryptoNote::HttpResponse::HTTP_STATUS status) {
|
|||
case CryptoNote::HttpResponse::STATUS_404:
|
||||
return "Requested url is not found\n";
|
||||
case CryptoNote::HttpResponse::STATUS_500:
|
||||
return "Internal server error is occured\n";
|
||||
return "Internal server error is occurred\n";
|
||||
default:
|
||||
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 removeObserver(INodeObserver* observer) override;
|
||||
|
||||
virtual size_t getPeerCount() const;
|
||||
virtual uint32_t getLastLocalBlockHeight() const;
|
||||
virtual uint32_t getLastKnownBlockHeight() const;
|
||||
virtual size_t getPeerCount() const override;
|
||||
virtual uint32_t getLastLocalBlockHeight() const override;
|
||||
virtual uint32_t getLastKnownBlockHeight() const override;
|
||||
virtual uint32_t getLocalBlockCount() const override;
|
||||
virtual uint32_t getKnownBlockCount() const override;
|
||||
virtual uint64_t getLastLocalBlockTimestamp() const override;
|
||||
|
|
|
@ -48,25 +48,25 @@ public:
|
|||
NodeRpcProxy(const std::string& nodeHost, unsigned short nodePort);
|
||||
virtual ~NodeRpcProxy();
|
||||
|
||||
virtual bool addObserver(CryptoNote::INodeObserver* observer);
|
||||
virtual bool removeObserver(CryptoNote::INodeObserver* observer);
|
||||
virtual bool addObserver(CryptoNote::INodeObserver* observer) override;
|
||||
virtual bool removeObserver(CryptoNote::INodeObserver* observer) override;
|
||||
|
||||
virtual bool addObserver(CryptoNote::INodeRpcProxyObserver* observer);
|
||||
virtual bool removeObserver(CryptoNote::INodeRpcProxyObserver* observer);
|
||||
|
||||
virtual void init(const Callback& callback);
|
||||
virtual bool shutdown();
|
||||
virtual void init(const Callback& callback) override;
|
||||
virtual bool shutdown() override;
|
||||
|
||||
virtual size_t getPeerCount() const;
|
||||
virtual uint32_t getLastLocalBlockHeight() const;
|
||||
virtual uint32_t getLastKnownBlockHeight() const;
|
||||
virtual size_t getPeerCount() const override;
|
||||
virtual uint32_t getLastLocalBlockHeight() const override;
|
||||
virtual uint32_t getLastKnownBlockHeight() const override;
|
||||
virtual uint32_t getLocalBlockCount() const override;
|
||||
virtual uint32_t getKnownBlockCount() const override;
|
||||
virtual uint64_t getLastLocalBlockTimestamp() const override;
|
||||
|
||||
virtual void relayTransaction(const CryptoNote::Transaction& transaction, 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);
|
||||
virtual void getNewBlocks(std::vector<Crypto::Hash>&& knownBlockIds, std::vector<CryptoNote::block_complete_entry>& newBlocks, uint32_t& startHeight, 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) override;
|
||||
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 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,
|
||||
|
|
|
@ -80,6 +80,7 @@ NetNodeConfig::NetNodeConfig() {
|
|||
allowLocalIp = false;
|
||||
hideMyPort = false;
|
||||
configFolder = Tools::getDefaultDataDirectory();
|
||||
testnet = false;
|
||||
}
|
||||
|
||||
bool NetNodeConfig::init(const boost::program_options::variables_map& vm)
|
||||
|
|
|
@ -70,7 +70,7 @@ private:
|
|||
bool hideMyPort;
|
||||
std::string configFolder;
|
||||
std::string p2pStateFilename;
|
||||
bool testnet = false;
|
||||
bool testnet;
|
||||
};
|
||||
|
||||
} //namespace nodetool
|
||||
|
|
|
@ -26,13 +26,13 @@ namespace PaymentService {
|
|||
class NodeRpcStub: public CryptoNote::INode {
|
||||
public:
|
||||
virtual ~NodeRpcStub() {}
|
||||
virtual bool addObserver(CryptoNote::INodeObserver* observer) { return true; }
|
||||
virtual bool removeObserver(CryptoNote::INodeObserver* observer) { return true; }
|
||||
virtual bool addObserver(CryptoNote::INodeObserver* observer) override { return true; }
|
||||
virtual bool removeObserver(CryptoNote::INodeObserver* observer) override { return true; }
|
||||
|
||||
virtual void init(const Callback& callback) { }
|
||||
virtual bool shutdown() { return true; }
|
||||
virtual void init(const Callback& callback) override { }
|
||||
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 getLastKnownBlockHeight() 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,
|
||||
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;
|
||||
callback(std::error_code());
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ void TransactionRpcInfo::serialize(CryptoNote::ISerializer& serializer) {
|
|||
serializer(fee, "fee");
|
||||
serializer(hash, "hash");
|
||||
serializer(blockHeight, "block_height");
|
||||
serializer(state, "state");
|
||||
serializer(timestamp, "timestamp");
|
||||
serializer(extra, "extra");
|
||||
serializer(transfers, "transfers");
|
||||
|
@ -154,6 +155,7 @@ void ListTransactionsResponse::serialize(CryptoNote::ISerializer& serializer) {
|
|||
}
|
||||
|
||||
void TransferRpcInfo::serialize(CryptoNote::ISerializer& serializer) {
|
||||
serializer(type, "type");
|
||||
serializer(address, "address");
|
||||
serializer(amount, "amount");
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ struct GetTransactionRequest {
|
|||
};
|
||||
|
||||
struct TransferRpcInfo {
|
||||
uint8_t type;
|
||||
std::string address;
|
||||
int64_t amount;
|
||||
|
||||
|
@ -152,6 +153,7 @@ struct TransactionRpcInfo {
|
|||
uint64_t blockHeight;
|
||||
uint64_t timestamp;
|
||||
std::string extra;
|
||||
uint8_t state;
|
||||
std::vector<TransferRpcInfo> transfers;
|
||||
|
||||
void serialize(CryptoNote::ISerializer& serializer);
|
||||
|
|
|
@ -240,8 +240,8 @@ void WalletService::loadWallet() {
|
|||
|
||||
void WalletService::loadPaymentsCacheAndTransferIndices() {
|
||||
size_t txCount = wallet->getTransactionCount();
|
||||
transfersIndices.resize(1);
|
||||
transfersIndices[0] = 0;
|
||||
transfersIndices.reserve(txCount + 1);
|
||||
transfersIndices.push_back(0);
|
||||
|
||||
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";
|
||||
|
||||
try {
|
||||
std::vector<CryptoNote::WalletTransfer> transfers;
|
||||
makeTransfers(req.destinations, transfers);
|
||||
std::vector<CryptoNote::WalletOrder> orders;
|
||||
makeOrders(req.destinations, orders);
|
||||
|
||||
std::string extra;
|
||||
if (!req.paymentId.empty()) {
|
||||
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) {
|
||||
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;
|
||||
|
@ -296,11 +296,11 @@ std::error_code WalletService::sendTransaction(const SendTransactionRequest& req
|
|||
return std::error_code();
|
||||
}
|
||||
|
||||
void WalletService::makeTransfers(const std::vector<PaymentService::TransferDestination>& destinations, std::vector<CryptoNote::WalletTransfer>& transfers) {
|
||||
transfers.reserve(destinations.size());
|
||||
void WalletService::makeOrders(const std::vector<PaymentService::TransferDestination>& destinations, std::vector<CryptoNote::WalletOrder>& orders) {
|
||||
orders.reserve(destinations.size());
|
||||
|
||||
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);
|
||||
transactionId = (nextTxId - transfersIndices.begin()) - 1;
|
||||
assert(nextTxId != transfersIndices.begin());
|
||||
transactionId = std::distance(transfersIndices.begin(), nextTxId) - 1;
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
@ -443,9 +444,10 @@ void WalletService::fillTransactionRpcInfo(size_t txId, const CryptoNote::Wallet
|
|||
rpcInfo.timestamp = tx.timestamp;
|
||||
rpcInfo.extra = Common::toHex(tx.extra.data(), tx.extra.size());
|
||||
rpcInfo.hash = Common::podToHex(tx.hash);
|
||||
rpcInfo.state = static_cast<uint8_t>(tx.state);
|
||||
for (size_t transferId = 0; transferId < rpcInfo.transferCount; ++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);
|
||||
}
|
||||
}
|
||||
|
@ -510,7 +512,9 @@ std::error_code WalletService::getTransfer(size_t globalTransferId, bool& found,
|
|||
logger(Logging::DEBUGGING) << "getTransfer request came";
|
||||
found = false;
|
||||
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;
|
||||
|
||||
if (txId == fakeTxId) {
|
||||
|
@ -520,6 +524,7 @@ std::error_code WalletService::getTransfer(size_t globalTransferId, bool& found,
|
|||
auto transferId = globalTransferId - transfersIndices[txId];
|
||||
auto transfer = wallet->getTransactionTransfer(txId, transferId);
|
||||
|
||||
rpcInfo.type = static_cast<uint8_t>(transfer.type);
|
||||
rpcInfo.address = transfer.address;
|
||||
rpcInfo.amount = transfer.amount;
|
||||
found = true;
|
||||
|
@ -572,12 +577,22 @@ void WalletService::refresh() {
|
|||
for (;;) {
|
||||
auto event = wallet->getEvent();
|
||||
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) {
|
||||
transactionId = event.transactionCreated.transactionIndex;
|
||||
transfersIndices.push_back(transfersIndices[transactionId] + wallet->getTransactionTransferCount(transactionId));
|
||||
assert(transactionId == transfersIndices.size() - 1);
|
||||
transfersIndices.push_back(transfersIndices[transactionId] + transferCount);
|
||||
} 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);
|
||||
|
|
|
@ -83,7 +83,7 @@ private:
|
|||
void insertTransaction(size_t id, const Crypto::Hash& paymentIdBin, bool confirmed);
|
||||
|
||||
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 {
|
||||
std::string paymentId;
|
||||
|
|
|
@ -39,13 +39,13 @@ bool ConfigurationManager::init(int argc, char** argv) {
|
|||
|
||||
po::options_description confGeneralOptions;
|
||||
confGeneralOptions.add(cmdGeneralOptions).add_options()
|
||||
("testnet", po::value<bool>(), "")
|
||||
("local", po::value<bool>(), "");
|
||||
("testnet", po::bool_switch(), "")
|
||||
("local", po::bool_switch(), "");
|
||||
|
||||
cmdGeneralOptions.add_options()
|
||||
("help,h", "produce this help message and exit")
|
||||
("local", "start with local node (remote is default)")
|
||||
("testnet", "testnet mode");
|
||||
("local", po::bool_switch(), "start with local node (remote is default)")
|
||||
("testnet", po::bool_switch(), "testnet mode");
|
||||
|
||||
command_line::add_arg(cmdGeneralOptions, 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);
|
||||
remoteNodeConfig.init(confOptions);
|
||||
|
||||
if (confOptions.count("local")) {
|
||||
startInprocess = confOptions["local"].as<bool>();
|
||||
}
|
||||
netNodeConfig.setTestnet(confOptions["testnet"].as<bool>());
|
||||
startInprocess = confOptions["local"].as<bool>();
|
||||
}
|
||||
|
||||
//command line options should override options from config file
|
||||
|
@ -101,7 +100,11 @@ bool ConfigurationManager::init(int argc, char** argv) {
|
|||
coreConfig.init(cmdOptions);
|
||||
remoteNodeConfig.init(cmdOptions);
|
||||
|
||||
if (cmdOptions.count("local")) {
|
||||
if (cmdOptions["testnet"].as<bool>()) {
|
||||
netNodeConfig.setTestnet(true);
|
||||
}
|
||||
|
||||
if (cmdOptions["local"].as<bool>()) {
|
||||
startInprocess = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ void PaymentGateService::runInProcess(Logging::LoggerRef& log) {
|
|||
|
||||
node->init([&initPromise, &log](std::error_code ec) {
|
||||
if (ec) {
|
||||
log(Logging::INFO) << "Failed to init node: " << ec.message();
|
||||
log(Logging::WARNING, Logging::YELLOW) << "Failed to init node: " << ec.message();
|
||||
} else {
|
||||
log(Logging::INFO) << "node is inited successfully";
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ void PaymentGateService::runWalletService(const CryptoNote::Currency& currency,
|
|||
try {
|
||||
service->init();
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ void PaymentGateService::runWalletService(const CryptoNote::Currency& currency,
|
|||
try {
|
||||
service->saveWallet();
|
||||
} 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");
|
||||
}
|
||||
|
||||
if (options.count("testnet") != 0) {
|
||||
if (options["testnet"].as<bool>()) {
|
||||
testnet = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ std::string GetLastErrorMessage(DWORD errorMessageID)
|
|||
void __stdcall serviceHandler(DWORD fdwControl) {
|
||||
if (fdwControl == SERVICE_CONTROL_STOP) {
|
||||
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 };
|
||||
SetServiceStatus(serviceStatusHandle, &serviceStatus);
|
||||
|
@ -73,26 +73,26 @@ void __stdcall serviceMain(DWORD dwArgc, char **lpszArgv) {
|
|||
|
||||
serviceStatusHandle = RegisterServiceCtrlHandler("PaymentGate", serviceHandler);
|
||||
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;
|
||||
}
|
||||
|
||||
SERVICE_STATUS serviceStatus{ SERVICE_WIN32_OWN_PROCESS, SERVICE_START_PENDING, 0, NO_ERROR, 0, 1, 3000 };
|
||||
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;
|
||||
}
|
||||
|
||||
serviceStatus = { SERVICE_WIN32_OWN_PROCESS, SERVICE_RUNNING, SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0 };
|
||||
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;
|
||||
}
|
||||
|
||||
try {
|
||||
ppg->run();
|
||||
} 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 };
|
||||
|
@ -138,10 +138,14 @@ int runDaemon() {
|
|||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
Logging::LoggerRef logRef(ppg->getLogger(), "RunService");
|
||||
|
||||
if (StartServiceCtrlDispatcher(serviceTable) != TRUE) {
|
||||
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "Couldn't start service: " << GetLastErrorMessage(GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
logRef(Logging::INFO) << "Service stopped";
|
||||
return 0;
|
||||
|
||||
#else
|
||||
|
@ -151,7 +155,7 @@ int runDaemon() {
|
|||
//parent
|
||||
return 0;
|
||||
} else if (daemonResult < 0) {
|
||||
//error occured
|
||||
//error occurred
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -174,7 +178,7 @@ int registerService() {
|
|||
|
||||
for (;;) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -186,7 +190,7 @@ int registerService() {
|
|||
|
||||
scManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -195,7 +199,7 @@ int registerService() {
|
|||
SERVICE_ERROR_NORMAL, modulePath.c_str(), NULL, NULL, NULL, NULL, 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;
|
||||
break;
|
||||
}
|
||||
|
@ -231,14 +235,14 @@ int unregisterService() {
|
|||
for (;;) {
|
||||
scManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
scService = OpenService(scManager, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -260,12 +264,12 @@ int unregisterService() {
|
|||
if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED) {
|
||||
logRef(Logging::INFO) << SERVICE_NAME << " is stopped";
|
||||
} 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)) {
|
||||
logRef(Logging::FATAL) << "DeleteService failed with error: " << GetLastErrorMessage(GetLastError());
|
||||
logRef(Logging::FATAL, Logging::BRIGHT_RED) << "DeleteService failed with error: " << GetLastErrorMessage(GetLastError());
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
BinaryInputStreamSerializer(Common::IInputStream& strm) : stream(strm) {}
|
||||
virtual ~BinaryInputStreamSerializer() {}
|
||||
|
||||
virtual ISerializer::SerializerType type() const;
|
||||
virtual ISerializer::SerializerType type() const override;
|
||||
|
||||
virtual bool beginObject(Common::StringView name) override;
|
||||
virtual void endObject() override;
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
BinaryOutputStreamSerializer(Common::IOutputStream& strm) : stream(strm) {}
|
||||
virtual ~BinaryOutputStreamSerializer() {}
|
||||
|
||||
virtual ISerializer::SerializerType type() const;
|
||||
virtual ISerializer::SerializerType type() const override;
|
||||
|
||||
virtual bool beginObject(Common::StringView name) override;
|
||||
virtual void endObject() override;
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
JsonInputValueSerializer(Common::JsonValue&& value);
|
||||
virtual ~JsonInputValueSerializer();
|
||||
|
||||
SerializerType type() const;
|
||||
SerializerType type() const override;
|
||||
|
||||
virtual bool beginObject(Common::StringView name) override;
|
||||
virtual void endObject() override;
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
JsonOutputStreamSerializer();
|
||||
virtual ~JsonOutputStreamSerializer();
|
||||
|
||||
SerializerType type() const;
|
||||
SerializerType type() const override;
|
||||
|
||||
virtual bool beginObject(Common::StringView name) override;
|
||||
virtual void endObject() override;
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
|
||||
void dump(Common::IOutputStream& target);
|
||||
|
||||
virtual ISerializer::SerializerType type() const;
|
||||
virtual ISerializer::SerializerType type() const override;
|
||||
|
||||
virtual bool beginObject(Common::StringView name) override;
|
||||
virtual void endObject() override;
|
||||
|
|
|
@ -464,7 +464,8 @@ simple_wallet::simple_wallet(System::Dispatcher& dispatcher, const CryptoNote::C
|
|||
logManager(log),
|
||||
logger(log, "simplewallet"),
|
||||
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("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");
|
||||
|
@ -734,8 +735,21 @@ bool simple_wallet::save(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();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
if (connected) {
|
||||
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>()*/) {
|
||||
success_msg_writer() << "available balance: " << m_currency.formatAmount(m_wallet->actualBalance()) <<
|
||||
", 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() {
|
||||
{
|
||||
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);
|
||||
m_consoleHandler.start(false, "[wallet " + addr_start + "]: ", Common::Console::Color::BrightYellow);
|
||||
return true;
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
|
@ -95,13 +97,11 @@ namespace CryptoNote
|
|||
|
||||
void printConnectionError() const;
|
||||
|
||||
//---------------- IWalletObserver -------------------------
|
||||
//---------------- IWalletLegacyObserver -------------------------
|
||||
virtual void initCompleted(std::error_code result) override;
|
||||
virtual void externalTransactionCreated(CryptoNote::TransactionId transactionId) override;
|
||||
//----------------------------------------------------------
|
||||
|
||||
//----------------- INodeObserver --------------------------
|
||||
virtual void localBlockchainUpdated(uint32_t height) override;
|
||||
virtual void synchronizationCompleted(std::error_code result) override;
|
||||
virtual void synchronizationProgressUpdated(uint32_t current, uint32_t total) override;
|
||||
//----------------------------------------------------------
|
||||
|
||||
//----------------- INodeRpcProxyObserver --------------------------
|
||||
|
@ -130,8 +130,7 @@ namespace CryptoNote
|
|||
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';
|
||||
m_print_time = current_time;
|
||||
}
|
||||
|
@ -140,17 +139,9 @@ namespace CryptoNote
|
|||
private:
|
||||
void update_blockchain_height()
|
||||
{
|
||||
std::string err;
|
||||
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();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Failed to get current blockchain height: " << err;
|
||||
}
|
||||
m_blockchain_height = blockchain_height;
|
||||
m_blockchain_height_update_time = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -182,5 +173,9 @@ namespace CryptoNote
|
|||
std::unique_ptr<CryptoNote::NodeRpcProxy> m_node;
|
||||
std::unique_ptr<CryptoNote::IWalletLegacy> m_wallet;
|
||||
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();
|
||||
|
||||
switch (result) {
|
||||
case UpdateConsumersResult::errorOccured:
|
||||
case UpdateConsumersResult::errorOccurred:
|
||||
if (setFutureStateIf(State::idle, std::bind(
|
||||
[](State futureState) -> bool {
|
||||
return futureState != State::stopped;
|
||||
|
@ -435,7 +435,7 @@ BlockchainSynchronizer::UpdateConsumersResult BlockchainSynchronizer::updateCons
|
|||
static_cast<uint32_t>(interval.blocks.size()) - startOffset);
|
||||
smthChanged = true;
|
||||
} else {
|
||||
return UpdateConsumersResult::errorOccured;
|
||||
return UpdateConsumersResult::errorOccurred;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ private:
|
|||
enum class UpdateConsumersResult {
|
||||
nothingChanged = 0,
|
||||
addedNewBlocks = 1,
|
||||
errorOccured = 2
|
||||
errorOccurred = 2
|
||||
};
|
||||
|
||||
//void startSync();
|
||||
|
|
|
@ -45,7 +45,8 @@ enum WalletErrorCodes {
|
|||
KEY_GENERATION_ERROR,
|
||||
INDEX_OUT_OF_RANGE,
|
||||
ADDRESS_ALREADY_EXISTS,
|
||||
TRACKING_MODE
|
||||
TRACKING_MODE,
|
||||
WRONG_PARAMETERS
|
||||
};
|
||||
|
||||
// custom category:
|
||||
|
@ -66,7 +67,7 @@ public:
|
|||
case NOT_INITIALIZED: return "Object was not initialized";
|
||||
case WRONG_PASSWORD: return "The password is wrong";
|
||||
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 BAD_ADDRESS: return "Bad address";
|
||||
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 ADDRESS_ALREADY_EXISTS: return "Address already exists";
|
||||
case TRACKING_MODE: return "The wallet is in tracking mode";
|
||||
case WRONG_PARAMETERS: return "Wrong parameters passed";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -153,6 +153,64 @@ size_t getTransactionSize(const ITransactionReader& transaction) {
|
|||
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 {
|
||||
|
@ -163,7 +221,7 @@ WalletGreen::WalletGreen(System::Dispatcher& dispatcher, const Currency& currenc
|
|||
m_node(node),
|
||||
m_blockchainSynchronizer(node, currency.genesisBlockHash()),
|
||||
m_synchronizer(currency, m_blockchainSynchronizer, node),
|
||||
m_eventOccured(m_dispatcher),
|
||||
m_eventOccurred(m_dispatcher),
|
||||
m_readyEvent(m_dispatcher),
|
||||
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));
|
||||
}
|
||||
|
||||
auto it = bounds.first;
|
||||
std::advance(it, transferIndex);
|
||||
return it->second;
|
||||
return std::next(bounds.first, transferIndex)->second;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
size_t WalletGreen::transfer(const WalletTransfer& 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,
|
||||
size_t WalletGreen::transfer(const WalletOrder& destination,
|
||||
uint64_t fee,
|
||||
uint64_t mixIn,
|
||||
const std::string& extra,
|
||||
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();
|
||||
throwIfStopped();
|
||||
throwIfTrackingMode();
|
||||
return transfer(transactionParameters);
|
||||
}
|
||||
|
||||
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(
|
||||
const std::string& sourceAddress,
|
||||
const WalletTransfer& destination,
|
||||
const WalletOrder& destination,
|
||||
uint64_t fee,
|
||||
uint64_t mixIn,
|
||||
std::string const& extra,
|
||||
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(
|
||||
const std::string& sourceAddress,
|
||||
const std::vector<WalletTransfer>& destinations,
|
||||
const std::vector<WalletOrder>& destinations,
|
||||
uint64_t fee,
|
||||
uint64_t mixIn,
|
||||
const std::string& extra,
|
||||
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);
|
||||
|
||||
throwIfNotInitialized();
|
||||
throwIfStopped();
|
||||
throwIfTrackingMode();
|
||||
throwIfStopped();
|
||||
|
||||
WalletOuts wallet = pickWallet(sourceAddress);
|
||||
std::vector<WalletOuts> wallets;
|
||||
|
||||
if (!wallet.outs.empty()) {
|
||||
wallets.push_back(wallet);
|
||||
if (!transactionParameters.sourceAddress.empty()) {
|
||||
WalletOuts wallet = pickWallet(transactionParameters.sourceAddress);
|
||||
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,
|
||||
const std::vector<WalletTransfer>& destinations,
|
||||
const std::vector<WalletOrder>& orders,
|
||||
uint64_t fee,
|
||||
uint64_t mixIn,
|
||||
const std::string& extra,
|
||||
uint64_t unlockTimestamp) {
|
||||
if (destinations.empty()) {
|
||||
uint64_t unlockTimestamp,
|
||||
const DonationSettings& donation) {
|
||||
if (orders.empty()) {
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
uint64_t neededMoney = countNeededMoney(destinations, fee);
|
||||
|
@ -661,16 +760,19 @@ size_t WalletGreen::doTransfer(std::vector<WalletOuts>&& wallets,
|
|||
std::vector<InputInfo> keysInfo;
|
||||
prepareInputs(selectedTransfers, mixinResult, mixIn, keysInfo);
|
||||
|
||||
WalletTransfer changeDestination;
|
||||
changeDestination.address = m_currency.accountAddressAsString({ m_walletsContainer.get<RandomAccessIndex>()[0].spendPublicKey, m_viewPublicKey });
|
||||
changeDestination.amount = foundMoney - neededMoney;
|
||||
uint64_t donationAmount = pushDonationTransferIfPossible(donation, foundMoney - neededMoney, m_currency.defaultDustThreshold(), destinations);
|
||||
uint64_t changeAmount = foundMoney - neededMoney - donationAmount;
|
||||
|
||||
std::vector<ReceiverAmounts> decomposedOutputs;
|
||||
splitDestinations(destinations, changeDestination, m_currency.defaultDustThreshold(), m_currency, decomposedOutputs);
|
||||
std::vector<ReceiverAmounts> decomposedOutputs = splitDestinations(destinations, m_currency.defaultDustThreshold(), m_currency);
|
||||
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);
|
||||
|
||||
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);
|
||||
m_fusionTxsCache.emplace(txId, false);
|
||||
|
||||
|
@ -679,34 +781,34 @@ size_t WalletGreen::doTransfer(std::vector<WalletOuts>&& wallets,
|
|||
try {
|
||||
sendTransaction(tx.get());
|
||||
} catch (std::exception&) {
|
||||
updateTransactionStateAndPushEvent(txId, WalletTransactionState::FAILED);
|
||||
deleteSpentOutputs(tx->getTransactionHash());
|
||||
pushEvent(makeTransactionCreatedEvent(txId));
|
||||
throw;
|
||||
}
|
||||
|
||||
auto txIt = m_transactions.get<RandomAccessIndex>().begin();
|
||||
std::advance(txIt, txId);
|
||||
m_transactions.get<RandomAccessIndex>().modify(txIt,
|
||||
[] (WalletTransaction& tx) { tx.state = WalletTransactionState::SUCCEEDED; });
|
||||
|
||||
m_change[tx->getTransactionHash()] = changeDestination.amount;
|
||||
m_change[tx->getTransactionHash()] = changeAmount;
|
||||
updateTransactionStateAndPushEvent(txId, WalletTransactionState::SUCCEEDED);
|
||||
updateUsedWalletsBalances(selectedTransfers);
|
||||
|
||||
pushEvent(makeTransactionCreatedEvent(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) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
insertTx.state = WalletTransactionState::FAILED;
|
||||
insertTx.state = WalletTransactionState::CREATED;
|
||||
insertTx.creationTime = static_cast<uint64_t>(time(nullptr));
|
||||
insertTx.unlockTime = unlockTimestamp;
|
||||
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();
|
||||
m_transactions.get<RandomAccessIndex>().push_back(std::move(insertTx));
|
||||
|
||||
pushEvent(makeTransactionCreatedEvent(txId));
|
||||
|
||||
return txId;
|
||||
}
|
||||
|
||||
bool WalletGreen::transactionExists(const Hash& hash) {
|
||||
auto& hashIndex = m_transactions.get<TransactionIndex>();
|
||||
auto it = hashIndex.find(hash);
|
||||
return it != hashIndex.end();
|
||||
}
|
||||
void WalletGreen::updateTransactionStateAndPushEvent(size_t transactionId, WalletTransactionState state) {
|
||||
auto it = std::next(m_transactions.get<RandomAccessIndex>().begin(), transactionId);
|
||||
|
||||
bool WalletGreen::updateWalletTransactionInfo(const Hash& hash, const CryptoNote::TransactionInformation& info) {
|
||||
auto& hashIndex = m_transactions.get<TransactionIndex>();
|
||||
|
||||
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;
|
||||
}
|
||||
if (it->state != state) {
|
||||
m_transactions.get<RandomAccessIndex>().modify(it, [state](WalletTransaction& tx) {
|
||||
tx.state = state;
|
||||
});
|
||||
|
||||
assert(r);
|
||||
return updated;
|
||||
pushEvent(makeTransactionUpdatedEvent(transactionId));
|
||||
}
|
||||
|
||||
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>();
|
||||
|
||||
WalletTransaction tx;
|
||||
|
@ -787,8 +897,12 @@ size_t WalletGreen::insertBlockchainTransaction(const TransactionInformation& in
|
|||
tx.creationTime = info.timestamp;
|
||||
tx.isBase = info.totalAmountIn == 0;
|
||||
|
||||
size_t txId = index.size();
|
||||
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) {
|
||||
|
@ -796,7 +910,7 @@ void WalletGreen::insertIncomingTransfer(size_t txId, const std::string& address
|
|||
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)));
|
||||
}
|
||||
|
||||
|
@ -805,12 +919,23 @@ std::unique_ptr<CryptoNote::ITransaction> WalletGreen::makeTransaction(const std
|
|||
|
||||
std::unique_ptr<ITransaction> tx = createTransaction();
|
||||
|
||||
typedef std::pair<const AccountPublicAddress*, uint64_t> AmountToAddress;
|
||||
std::vector<AmountToAddress> amountsToAddresses;
|
||||
for (const auto& output: decomposedOutputs) {
|
||||
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->appendExtra(Common::asBinaryArray(extra));
|
||||
|
||||
|
@ -984,26 +1109,30 @@ WalletGreen::WalletOuts WalletGreen::pickWallet(const std::string& address) {
|
|||
return outs;
|
||||
}
|
||||
|
||||
void WalletGreen::splitDestinations(const std::vector<CryptoNote::WalletTransfer>& destinations,
|
||||
const CryptoNote::WalletTransfer& changeDestination,
|
||||
std::vector<CryptoNote::WalletGreen::ReceiverAmounts> WalletGreen::splitDestinations(const std::vector<CryptoNote::WalletTransfer>& destinations,
|
||||
uint64_t dustThreshold,
|
||||
const CryptoNote::Currency& currency,
|
||||
std::vector<ReceiverAmounts>& decomposedOutputs) {
|
||||
const CryptoNote::Currency& currency) {
|
||||
|
||||
std::vector<ReceiverAmounts> decomposedOutputs;
|
||||
for (const auto& destination: destinations) {
|
||||
ReceiverAmounts receiverAmounts;
|
||||
|
||||
parseAddressString(destination.address, currency, receiverAmounts.receiver);
|
||||
decomposeAmount(destination.amount, dustThreshold, receiverAmounts.amounts);
|
||||
|
||||
decomposedOutputs.push_back(std::move(receiverAmounts));
|
||||
AccountPublicAddress address;
|
||||
parseAddressString(destination.address, currency, address);
|
||||
decomposedOutputs.push_back(splitAmount(destination.amount, address, dustThreshold));
|
||||
}
|
||||
|
||||
ReceiverAmounts changeAmounts;
|
||||
parseAddressString(changeDestination.address, currency, changeAmounts.receiver);
|
||||
decomposeAmount(changeDestination.amount, dustThreshold, changeAmounts.amounts);
|
||||
return decomposedOutputs;
|
||||
}
|
||||
|
||||
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(
|
||||
|
@ -1067,7 +1196,7 @@ void WalletGreen::start() {
|
|||
|
||||
void WalletGreen::stop() {
|
||||
m_stopped = true;
|
||||
m_eventOccured.set();
|
||||
m_eventOccurred.set();
|
||||
}
|
||||
|
||||
WalletEvent WalletGreen::getEvent() {
|
||||
|
@ -1075,8 +1204,8 @@ WalletEvent WalletGreen::getEvent() {
|
|||
throwIfStopped();
|
||||
|
||||
while(m_events.empty()) {
|
||||
m_eventOccured.wait();
|
||||
m_eventOccured.clear();
|
||||
m_eventOccurred.wait();
|
||||
m_eventOccurred.clear();
|
||||
throwIfStopped();
|
||||
}
|
||||
|
||||
|
@ -1161,25 +1290,23 @@ void WalletGreen::transactionUpdated(ITransfersSubscription* object, const Hash&
|
|||
int64_t txBalance;
|
||||
bool found = container->getTransactionInformation(transactionHash, info, txBalance);
|
||||
assert(found);
|
||||
bool addTransfer = txBalance > 0;
|
||||
|
||||
if (transactionExists(info.transactionHash)) {
|
||||
bool updated = updateWalletTransactionInfo(info.transactionHash, info);
|
||||
auto& hashIndex = m_transactions.get<TransactionIndex>();
|
||||
auto it = hashIndex.find(info.transactionHash);
|
||||
|
||||
auto id = getTransactionId(info.transactionHash);
|
||||
|
||||
if (updated) {
|
||||
pushEvent(makeTransactionUpdatedEvent(id));
|
||||
}
|
||||
size_t transactionId;
|
||||
if (it != hashIndex.end()) {
|
||||
transactionId = std::distance(m_transactions.get<RandomAccessIndex>().begin(), m_transactions.project<RandomAccessIndex>(it));
|
||||
updateWalletTransactionInfoAndPushEvent(transactionId, info, addTransfer);
|
||||
} else {
|
||||
auto id = insertBlockchainTransaction(info, txBalance);
|
||||
if (txBalance > 0) {
|
||||
AccountPublicAddress walletAddress{ getWalletRecord(container).spendPublicKey, m_viewPublicKey };
|
||||
insertIncomingTransfer(id, m_currency.accountAddressAsString(walletAddress), txBalance);
|
||||
}
|
||||
transactionId = insertBlockchainTransactionAndPushEvent(info, txBalance);
|
||||
m_fusionTxsCache.emplace(transactionId, isFusionTransaction(m_transactions.get<RandomAccessIndex>()[transactionId]));
|
||||
}
|
||||
|
||||
m_fusionTxsCache.emplace(id, isFusionTransaction(m_transactions.get<RandomAccessIndex>()[id]));
|
||||
|
||||
pushEvent(makeTransactionCreatedEvent(id));
|
||||
if (addTransfer) {
|
||||
AccountPublicAddress walletAddress{ getWalletRecord(container).spendPublicKey, m_viewPublicKey };
|
||||
insertIncomingTransfer(transactionId, m_currency.accountAddressAsString(walletAddress), txBalance);
|
||||
}
|
||||
|
||||
m_change.erase(transactionHash);
|
||||
|
@ -1194,7 +1321,7 @@ void WalletGreen::transactionUpdated(ITransfersSubscription* object, const Hash&
|
|||
|
||||
void WalletGreen::pushEvent(const WalletEvent& event) {
|
||||
m_events.push(event);
|
||||
m_eventOccured.set();
|
||||
m_eventOccurred.set();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
throwIfNotInitialized();
|
||||
throwIfTrackingMode();
|
||||
throwIfStopped();
|
||||
|
||||
//TODO: check if wallet is not in tracking mode
|
||||
const size_t MAX_FUSION_OUTPUT_COUNT = 4;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
WalletTransfer destination = {m_currency.accountAddressAsString({m_walletsContainer.get<RandomAccessIndex>().begin()->spendPublicKey,
|
||||
m_viewPublicKey }), 0};
|
||||
std::string address = m_currency.accountAddressAsString({m_walletsContainer.get<RandomAccessIndex>().begin()->spendPublicKey, m_viewPublicKey });
|
||||
WalletTransfer destination = {WalletTransferType::USUAL, address, 0};
|
||||
pushBackOutgoingTransfers(transactionId, std::vector<WalletTransfer> {destination});
|
||||
|
||||
markOutputsSpent(fusionTransaction->getTransactionHash(), fusionInputs);
|
||||
|
@ -1467,22 +1594,15 @@ size_t WalletGreen::createFusionTransaction(uint64_t threshold, uint64_t mixin)
|
|||
try {
|
||||
sendTransaction(fusionTransaction.get());
|
||||
} catch (std::exception&) {
|
||||
updateTransactionStateAndPushEvent(transactionId, WalletTransactionState::FAILED);
|
||||
deleteSpentOutputs(fusionTransaction->getTransactionHash());
|
||||
pushEvent(makeTransactionCreatedEvent(transactionId));
|
||||
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;
|
||||
|
||||
updateTransactionStateAndPushEvent(transactionId, WalletTransactionState::SUCCEEDED);
|
||||
updateUsedWalletsBalances(fusionInputs);
|
||||
|
||||
pushEvent(makeTransactionCreatedEvent(transactionId));
|
||||
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,10 +66,11 @@ public:
|
|||
virtual size_t getTransactionTransferCount(size_t transactionIndex) 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 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 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 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 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<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 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<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 stop() override;
|
||||
|
@ -145,11 +146,12 @@ protected:
|
|||
bool isFusionTransaction(const WalletTransaction& walletTx) const;
|
||||
|
||||
size_t doTransfer(std::vector<WalletOuts>&& wallets,
|
||||
const std::vector<WalletTransfer>& destinations,
|
||||
const std::vector<WalletOrder>& orders,
|
||||
uint64_t fee,
|
||||
uint64_t mixIn,
|
||||
const std::string& extra,
|
||||
uint64_t unlockTimestamp);
|
||||
uint64_t unlockTimestamp,
|
||||
const DonationSettings& donation);
|
||||
|
||||
void requestMixinOuts(const std::vector<OutputToTransfer>& selectedTransfers,
|
||||
uint64_t mixIn,
|
||||
|
@ -166,18 +168,20 @@ protected:
|
|||
std::vector<WalletOuts>&& wallets,
|
||||
std::vector<OutputToTransfer>& selectedTransfers);
|
||||
|
||||
void splitDestinations(const std::vector<WalletTransfer>& destinations, const WalletTransfer& changeDestination,
|
||||
uint64_t dustThreshold, const Currency& currency, std::vector<ReceiverAmounts>& decomposedOutputs);
|
||||
std::vector<ReceiverAmounts> splitDestinations(const std::vector<WalletTransfer>& destinations,
|
||||
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::vector<InputInfo>& keysInfo, const std::string& extra, uint64_t unlockTimestamp);
|
||||
|
||||
void sendTransaction(ITransaction* tx);
|
||||
|
||||
size_t insertOutgoingTransaction(const Crypto::Hash& transactionHash, int64_t totalAmount, uint64_t fee, const BinaryArray& extra, uint64_t unlockTimestamp);
|
||||
bool transactionExists(const Crypto::Hash& hash);
|
||||
bool updateWalletTransactionInfo(const Crypto::Hash& hash, const CryptoNote::TransactionInformation& info);
|
||||
size_t insertBlockchainTransaction(const TransactionInformation& info, int64_t txBalance);
|
||||
size_t insertBlockchainTransactionAndPushEvent(const TransactionInformation& info, int64_t txBalance);
|
||||
size_t insertOutgoingTransactionAndPushEvent(const Crypto::Hash& transactionHash,
|
||||
int64_t totalAmount, uint64_t fee, const BinaryArray& extra, uint64_t unlockTimestamp);
|
||||
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 pushBackOutgoingTransfers(size_t txId, const std::vector<WalletTransfer> &destinations);
|
||||
void insertUnlockTransactionJob(const Crypto::Hash& transactionHash, uint32_t blockHeight, CryptoNote::ITransfersContainer* container);
|
||||
|
@ -219,7 +223,7 @@ protected:
|
|||
BlockchainSynchronizer m_blockchainSynchronizer;
|
||||
TransfersSyncronizer m_synchronizer;
|
||||
|
||||
System::Event m_eventOccured;
|
||||
System::Event m_eventOccurred;
|
||||
std::queue<WalletEvent> m_events;
|
||||
mutable System::Event m_readyEvent;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ using CryptoNote::ISerializer;
|
|||
};
|
||||
};
|
||||
|
||||
struct trnsfer_destination
|
||||
struct transfer_destination
|
||||
{
|
||||
uint64_t amount;
|
||||
std::string address;
|
||||
|
@ -63,7 +63,7 @@ using CryptoNote::ISerializer;
|
|||
{
|
||||
struct request
|
||||
{
|
||||
std::list<trnsfer_destination> destinations;
|
||||
std::list<transfer_destination> destinations;
|
||||
uint64_t fee;
|
||||
uint64_t mixin;
|
||||
uint64_t unlock_time;
|
||||
|
|
|
@ -99,14 +99,18 @@ struct WalletTransactionDto {
|
|||
|
||||
//DO NOT CHANGE IT
|
||||
struct WalletTransferDto {
|
||||
WalletTransferDto() {}
|
||||
WalletTransferDto(const CryptoNote::WalletTransfer& tr) {
|
||||
WalletTransferDto(uint32_t version) : version(version) {}
|
||||
WalletTransferDto(const CryptoNote::WalletTransfer& tr, uint32_t version) : WalletTransferDto(version) {
|
||||
address = tr.address;
|
||||
amount = tr.amount;
|
||||
type = static_cast<uint8_t>(tr.type);
|
||||
}
|
||||
|
||||
std::string address;
|
||||
uint64_t amount;
|
||||
uint8_t type;
|
||||
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
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) {
|
||||
serializer(value.address, "address");
|
||||
serializer(value.amount, "amount");
|
||||
}
|
||||
|
||||
if (value.version > 2) {
|
||||
serializer(value.type, "type");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
std::string serialize(Object& obj, const std::string& name) {
|
||||
|
@ -266,7 +273,7 @@ CryptoNote::WalletTransfer convert(const CryptoNote::WalletLegacyTransfer& tr) {
|
|||
|
||||
namespace CryptoNote {
|
||||
|
||||
const uint32_t WalletSerializer::SERIALIZATION_VERSION = 2;
|
||||
const uint32_t WalletSerializer::SERIALIZATION_VERSION = 3;
|
||||
|
||||
void CryptoContext::incIv() {
|
||||
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) {
|
||||
uint64_t txId = kv.first;
|
||||
WalletTransferDto tr(kv.second);
|
||||
WalletTransferDto tr(kv.second, SERIALIZATION_VERSION);
|
||||
|
||||
serializeEncrypted(txId, "transaction_id", cryptoContext, destination);
|
||||
cryptoContext.incIv();
|
||||
|
@ -519,18 +526,18 @@ void WalletSerializer::load(const std::string& password, Common::IInputStream& s
|
|||
|
||||
uint32_t version = loadVersion(source);
|
||||
|
||||
if (version == SERIALIZATION_VERSION) {
|
||||
loadCurrentVersion(source, password);
|
||||
} else if (version == 1) {
|
||||
loadWalletV1(source, password);
|
||||
} else {
|
||||
if (version > SERIALIZATION_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();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
bool details = false;
|
||||
|
@ -549,7 +556,7 @@ void WalletSerializer::loadCurrentVersion(Common::IInputStream& source, const st
|
|||
|
||||
if (details) {
|
||||
loadTransactions(source, cryptoContext);
|
||||
loadTransfers(source, cryptoContext);
|
||||
loadTransfers(source, cryptoContext, version);
|
||||
}
|
||||
|
||||
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;
|
||||
deserializeEncrypted(count, "transfers_count", cryptoContext, source);
|
||||
cryptoContext.incIv();
|
||||
|
@ -881,7 +888,7 @@ void WalletSerializer::loadTransfers(Common::IInputStream& source, CryptoContext
|
|||
deserializeEncrypted(txId, "transaction_id", cryptoContext, source);
|
||||
cryptoContext.incIv();
|
||||
|
||||
WalletTransferDto dto;
|
||||
WalletTransferDto dto(version);
|
||||
deserializeEncrypted(dto, "transfer", cryptoContext, source);
|
||||
cryptoContext.incIv();
|
||||
|
||||
|
@ -889,6 +896,12 @@ void WalletSerializer::loadTransfers(Common::IInputStream& source, CryptoContext
|
|||
tr.address = dto.address;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
private:
|
||||
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);
|
||||
|
||||
CryptoContext generateCryptoContext(const std::string& password);
|
||||
|
@ -95,7 +95,7 @@ private:
|
|||
void loadUnlockTransactionsJobs(Common::IInputStream& source, CryptoContext& cryptoContext);
|
||||
void loadChange(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 loadWalletV1Details(CryptoNote::BinaryInputStreamSerializer& serializer);
|
||||
|
|
|
@ -53,37 +53,37 @@ public:
|
|||
WalletLegacy(const CryptoNote::Currency& currency, INode& node);
|
||||
virtual ~WalletLegacy();
|
||||
|
||||
virtual void addObserver(IWalletLegacyObserver* observer);
|
||||
virtual void removeObserver(IWalletLegacyObserver* observer);
|
||||
virtual void addObserver(IWalletLegacyObserver* observer) override;
|
||||
virtual void removeObserver(IWalletLegacyObserver* observer) override;
|
||||
|
||||
virtual void initAndGenerate(const std::string& password);
|
||||
virtual void initAndLoad(std::istream& source, const std::string& password);
|
||||
virtual void initWithKeys(const AccountKeys& accountKeys, const std::string& password);
|
||||
virtual void shutdown();
|
||||
virtual void reset();
|
||||
virtual void initAndGenerate(const std::string& password) override;
|
||||
virtual void initAndLoad(std::istream& source, const std::string& password) override;
|
||||
virtual void initWithKeys(const AccountKeys& accountKeys, const std::string& password) override;
|
||||
virtual void shutdown() override;
|
||||
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 pendingBalance();
|
||||
virtual uint64_t actualBalance() override;
|
||||
virtual uint64_t pendingBalance() override;
|
||||
|
||||
virtual size_t getTransactionCount();
|
||||
virtual size_t getTransferCount();
|
||||
virtual size_t getTransactionCount() override;
|
||||
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 getTransfer(TransferId transferId, WalletLegacyTransfer& transfer);
|
||||
virtual bool getTransaction(TransactionId transactionId, WalletLegacyTransaction& transaction) override;
|
||||
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 std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0);
|
||||
virtual std::error_code cancelTransaction(size_t transactionId);
|
||||
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) override;
|
||||
virtual std::error_code cancelTransaction(size_t transactionId) override;
|
||||
|
||||
virtual void getAccountKeys(AccountKeys& keys);
|
||||
virtual void getAccountKeys(AccountKeys& keys) override;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -34,7 +34,11 @@ static const char _NR[] = {
|
|||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
#include <sys/timeb.h>
|
||||
#ifdef __APPLE__
|
||||
#include <malloc/malloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.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)
|
||||
{
|
||||
#define ctx ((struct cn_ctx *) context)
|
||||
uint8_t ExpandedKey[256];
|
||||
ALIGNED_DECL(uint8_t ExpandedKey[256], 16);
|
||||
size_t i;
|
||||
__m128i *longoutput, *expkey, *xmminput, b_x;
|
||||
ALIGNED_DECL(uint64_t a[2], 16);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define BUILD_COMMIT_ID "@VERSION@"
|
||||
#define PROJECT_VERSION "1.0.8.1"
|
||||
#define PROJECT_VERSION_BUILD_NO "614"
|
||||
#define PROJECT_VERSION "1.0.8.2"
|
||||
#define PROJECT_VERSION_BUILD_NO "625"
|
||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~NodeObserver() {
|
||||
}
|
||||
|
||||
virtual void peerCountUpdated(size_t count) {
|
||||
virtual void peerCountUpdated(size_t count) override {
|
||||
logger(INFO) << '[' << m_name << "] peerCountUpdated " << count << " = " << m_nodeProxy.getPeerCount();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,16 +31,16 @@ public:
|
|||
ICoreStub();
|
||||
ICoreStub(const CryptoNote::Block& genesisBlock);
|
||||
|
||||
virtual bool addObserver(CryptoNote::ICoreObserver* observer);
|
||||
virtual bool removeObserver(CryptoNote::ICoreObserver* observer);
|
||||
virtual void get_blockchain_top(uint32_t& height, Crypto::Hash& top_id);
|
||||
virtual bool addObserver(CryptoNote::ICoreObserver* observer) override;
|
||||
virtual bool removeObserver(CryptoNote::ICoreObserver* observer) override;
|
||||
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,
|
||||
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,
|
||||
CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& res);
|
||||
virtual bool get_tx_outputs_gindexs(const Crypto::Hash& tx_id, std::vector<uint32_t>& indexs);
|
||||
virtual CryptoNote::i_cryptonote_protocol* get_protocol();
|
||||
virtual bool handle_incoming_tx(CryptoNote::BinaryArray const& tx_blob, CryptoNote::tx_verification_context& tvc, bool keeped_by_block);
|
||||
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) override;
|
||||
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) override;
|
||||
virtual std::vector<CryptoNote::Transaction> getPoolTransactions() override;
|
||||
virtual bool getPoolChanges(const Crypto::Hash& tailBlockId, const std::vector<Crypto::Hash>& knownTxsIds,
|
||||
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 removeObserver(CryptoNote::INodeObserver* observer) override;
|
||||
|
||||
virtual void init(const CryptoNote::INode::Callback& callback) {callback(std::error_code());};
|
||||
virtual bool shutdown() { return true; };
|
||||
virtual void init(const CryptoNote::INode::Callback& callback) override {callback(std::error_code());};
|
||||
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 getLastKnownBlockHeight() 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,
|
||||
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<Crypto::Hash>& blockHashes, std::vector<CryptoNote::BlockDetails>& blocks, 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) { 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 getTransactionsByPaymentId(const Crypto::Hash& paymentId, std::vector<CryptoNote::TransactionDetails>& transactions, 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) { callback(std::error_code()); };
|
||||
virtual void isSynchronized(bool& syncStatus, 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) 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) override { 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) 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) override { 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()); }
|
||||
|
||||
void updateObservers();
|
||||
|
@ -79,16 +79,16 @@ public:
|
|||
|
||||
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 getLastKnownBlockHeight() 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 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 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 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 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) 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 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
|
||||
m_node.setGetNewBlocksLimit(3);
|
||||
|
@ -1085,7 +1085,7 @@ TEST_F(BcSTest, checkConsumerHeightReceived) {
|
|||
|
||||
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);
|
||||
|
||||
c.onNewBlocksFunctor = [&](const CompleteBlock*, uint32_t startHeight, size_t) -> bool {
|
||||
|
|
|
@ -1103,7 +1103,7 @@ TEST_F(BlockchainExplorerTests, getBlocksByTimestampNotInited) {
|
|||
}
|
||||
|
||||
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;
|
||||
std::vector<uint32_t> blockHeights;
|
||||
for (uint32_t i = 0; i < NUMBER_OF_BLOCKS + 3; ++i) {
|
||||
|
|
|
@ -134,11 +134,11 @@ void TestBlockchainGenerator::addMiningBlock() {
|
|||
m_generatedTransactionsIndex.add(block);
|
||||
}
|
||||
|
||||
void TestBlockchainGenerator::generateEmptyBlocks(uint32_t count)
|
||||
void TestBlockchainGenerator::generateEmptyBlocks(size_t count)
|
||||
{
|
||||
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 block;
|
||||
|
@ -359,11 +359,11 @@ void TestBlockchainGenerator::addTx(const CryptoNote::Transaction& tx) {
|
|||
const auto& out = tx.outputs[outIndex];
|
||||
if (out.target.type() == typeid(KeyOutput)) {
|
||||
auto& keyOutsContainer = keyOutsIndex[out.amount];
|
||||
globalIndexes.push_back(keyOutsContainer.size());
|
||||
globalIndexes.push_back(static_cast<uint32_t>(keyOutsContainer.size()));
|
||||
keyOutsContainer.push_back({ txHash, outIndex });
|
||||
} else if (out.target.type() == typeid(MultisignatureOutput)) {
|
||||
auto& msigOutsContainer = multisignatureOutsIndex[out.amount];
|
||||
globalIndexes.push_back(msigOutsContainer.size());
|
||||
globalIndexes.push_back(static_cast<uint32_t>(msigOutsContainer.size()));
|
||||
msigOutsContainer.push_back({ txHash, outIndex });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
//TODO: get rid of this method
|
||||
std::vector<CryptoNote::Block>& getBlockchain();
|
||||
std::vector<CryptoNote::Block> getBlockchainCopy();
|
||||
void generateEmptyBlocks(uint32_t count);
|
||||
void generateEmptyBlocks(size_t count);
|
||||
bool getBlockRewardForAddress(const CryptoNote::AccountPublicAddress& address);
|
||||
bool generateTransactionsInOneBlock(const CryptoNote::AccountPublicAddress& address, size_t n);
|
||||
bool getSingleOutputTransaction(const CryptoNote::AccountPublicAddress& address, uint64_t amount);
|
||||
|
|
|
@ -267,7 +267,7 @@ TEST_F(InProcessNodeTests, getBlocksByHeightEmpty) {
|
|||
}
|
||||
|
||||
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<std::vector<CryptoNote::BlockDetails>> actualBlocks;
|
||||
|
@ -311,7 +311,7 @@ TEST_F(InProcessNodeTests, getBlocksByHeightMany) {
|
|||
}
|
||||
|
||||
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<std::vector<CryptoNote::BlockDetails>> actualBlocks;
|
||||
|
@ -366,7 +366,7 @@ TEST_F(InProcessNodeTests, getBlocksByHashEmpty) {
|
|||
}
|
||||
|
||||
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<CryptoNote::BlockDetails> actualBlocks;
|
||||
|
@ -407,7 +407,7 @@ TEST_F(InProcessNodeTests, getBlocksByHashMany) {
|
|||
}
|
||||
|
||||
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<CryptoNote::BlockDetails> actualBlocks;
|
||||
|
|
|
@ -437,7 +437,7 @@ TEST_F(TransfersConsumerTest, onNewBlocks_getTransactionOutsGlobalIndicesError)
|
|||
block.transactions.push_back(tx);
|
||||
|
||||
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) {
|
||||
|
@ -457,7 +457,7 @@ TEST_F(TransfersConsumerTest, onNewBlocks_updateHeight) {
|
|||
block.block->timestamp = subscription.syncStart.timestamp;
|
||||
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));
|
||||
|
||||
std::unique_ptr<CompleteBlock[]> blocks(new CompleteBlock[subscription.transactionSpendableAge]);
|
||||
|
@ -468,7 +468,7 @@ TEST_F(TransfersConsumerTest, onNewBlocks_updateHeight) {
|
|||
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(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(expectedAmount, container.balance(ITransfersContainer::IncludeAll));
|
||||
|
@ -1031,7 +1031,7 @@ TEST_F(TransfersConsumerPerformanceTest, DISABLED_memory) {
|
|||
|
||||
{
|
||||
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();
|
||||
|
@ -1056,7 +1056,7 @@ TEST_F(TransfersConsumerPerformanceTest, DISABLED_performanceTest) {
|
|||
|
||||
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();
|
||||
std::chrono::duration<double> dur = end - start;
|
||||
|
|
|
@ -54,9 +54,13 @@ namespace CryptoNote {
|
|||
case WalletTransactionState::SUCCEEDED:
|
||||
o << "SUCCEEDED";
|
||||
break;
|
||||
case WalletTransactionState::CREATED:
|
||||
o << "CREATED";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const WalletTransaction& tx) {
|
||||
o << "WalletTransaction{state=" << tx.state << ", timestamp=" << tx.timestamp
|
||||
<< ", blockHeight=" << tx.blockHeight << ", hash=" << tx.hash
|
||||
|
@ -123,6 +127,10 @@ namespace CryptoNote {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (lhs.type != rhs.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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(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, 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();
|
||||
|
||||
|
@ -401,11 +411,11 @@ void WalletApi::generateAddressesWithPendingMoney(size_t count) {
|
|||
}
|
||||
|
||||
size_t WalletApi::sendMoneyToRandomAddressFrom(const std::string& address, uint64_t amount, uint64_t fee) {
|
||||
CryptoNote::WalletTransfer transfer;
|
||||
transfer.address = RANDOM_ADDRESS;
|
||||
transfer.amount = amount;
|
||||
CryptoNote::WalletOrder order;
|
||||
order.address = RANDOM_ADDRESS;
|
||||
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) {
|
||||
|
@ -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) {
|
||||
CryptoNote::WalletTransfer transfer;
|
||||
transfer.address = to;
|
||||
transfer.amount = amount;
|
||||
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::WalletOrder order;
|
||||
order.address = to;
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
System::Timer timer(dispatcher);
|
||||
timer.sleep(std::chrono::nanoseconds(milliseconds * 1000000));
|
||||
|
@ -510,7 +535,7 @@ TEST_F(WalletApi, pendingBalanceUpdatedAfterTransactionGotInBlock) {
|
|||
|
||||
auto prevPending = alice.getPendingBalance();
|
||||
|
||||
generator.generateEmptyBlocks(TRANSACTION_SOFTLOCK_TIME);
|
||||
generator.generateEmptyBlocks(static_cast<size_t>(TRANSACTION_SOFTLOCK_TIME));
|
||||
node.updateObservers();
|
||||
|
||||
waitPendingBalanceUpdated(prevPending);
|
||||
|
@ -524,7 +549,7 @@ TEST_F(WalletApi, moneyLockedIfTransactionIsSoftLocked) {
|
|||
bob.initialize("pass2");
|
||||
|
||||
sendMoney(bob.createAddress(), SENT, FEE);
|
||||
generator.generateEmptyBlocks(TRANSACTION_SOFTLOCK_TIME - 1);
|
||||
generator.generateEmptyBlocks(static_cast<size_t>(TRANSACTION_SOFTLOCK_TIME - 1));
|
||||
node.updateObservers();
|
||||
|
||||
waitPendingBalanceUpdated(bob, 0);
|
||||
|
@ -598,7 +623,11 @@ TEST_F(WalletApi, transferFromTwoAddresses) {
|
|||
}
|
||||
|
||||
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);
|
||||
INodeTrivialRefreshStub n(gen);
|
||||
|
||||
|
@ -613,11 +642,12 @@ TEST_F(WalletApi, transferTooBigTransaction) {
|
|||
n.updateObservers();
|
||||
waitActualBalanceUpdated(wallet, prev);
|
||||
|
||||
CryptoNote::WalletTransfer transfer;
|
||||
transfer.address = RANDOM_ADDRESS;
|
||||
transfer.amount = SENT;
|
||||
std::vector<CryptoNote::WalletOrder> destinations;
|
||||
for (size_t i = 0; i < bigTxOutputCount; ++i) {
|
||||
destinations.push_back({ RANDOM_ADDRESS, 1 });
|
||||
}
|
||||
|
||||
ASSERT_ANY_THROW(wallet.transfer(transfer, FEE));
|
||||
ASSERT_ANY_THROW(wallet.transfer(destinations, FEE));
|
||||
}
|
||||
|
||||
TEST_F(WalletApi, balanceAfterTransfer) {
|
||||
|
@ -1272,26 +1302,91 @@ TEST_F(WalletApi, incomingTxTransfer) {
|
|||
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) {
|
||||
generateAndUnlockMoney();
|
||||
|
||||
alice.createAddress();
|
||||
alice.createAddress();
|
||||
|
||||
CryptoNote::WalletTransfer tr1 { alice.getAddress(1), static_cast<int64_t>(SENT) };
|
||||
CryptoNote::WalletTransfer tr2 { alice.getAddress(2), static_cast<int64_t>(2 * SENT) };
|
||||
CryptoNote::WalletOrder tr1 { alice.getAddress(1), SENT };
|
||||
CryptoNote::WalletOrder tr2 { alice.getAddress(2), 2 * SENT };
|
||||
|
||||
alice.transfer({tr1, tr2}, FEE);
|
||||
node.updateObservers();
|
||||
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.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.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) {
|
||||
|
@ -1384,7 +1479,7 @@ TEST_F(WalletApi, DISABLED_loadTest) {
|
|||
|
||||
steady_clock::time_point transferStart = steady_clock::now();
|
||||
for (size_t i = 0; i < TRANSACTIONS_COUNT; ++i) {
|
||||
CryptoNote::WalletTransfer tr;
|
||||
CryptoNote::WalletOrder tr;
|
||||
tr.amount = SENT;
|
||||
tr.address = RANDOM_ADDRESS;
|
||||
wallet.transfer(tr, FEE);
|
||||
|
@ -1839,10 +1934,10 @@ TEST_F(WalletApi, fusionManagerIsFusionTransactionSpent) {
|
|||
ASSERT_NE(WALLET_INVALID_TRANSACTION_ID, id);
|
||||
|
||||
unlockMoney();
|
||||
CryptoNote::WalletTransfer transfer;
|
||||
transfer.address = wallet.getAddress(0);
|
||||
transfer.amount = alice.getActualBalance() - currency.minimumFee();
|
||||
alice.transfer(aliceAddress, transfer, currency.minimumFee(), 0);
|
||||
CryptoNote::WalletOrder order;
|
||||
order.address = wallet.getAddress(0);
|
||||
order.amount = alice.getActualBalance() - currency.minimumFee();
|
||||
alice.transfer(aliceAddress, order, currency.minimumFee(), 0);
|
||||
|
||||
auto pending = wallet.getPendingBalance();
|
||||
node.updateObservers();
|
||||
|
@ -1851,3 +1946,123 @@ TEST_F(WalletApi, fusionManagerIsFusionTransactionSpent) {
|
|||
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");
|
||||
WaitWalletSync(&walletObserver);
|
||||
|
||||
ASSERT_EQ(-(sent + fee), externalTransactionObserver.totalAmount);
|
||||
ASSERT_EQ(-static_cast<int64_t>(sent + fee), externalTransactionObserver.totalAmount);
|
||||
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_TRANSACTION_SIZE = 2000;
|
||||
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) {
|
||||
FusionTransactionBuilder builder(currency, 30 * currency.defaultDustThreshold());
|
||||
|
|
Loading…
Reference in a new issue