Merge pull request #872
beb6d92
CMake: GPL 'libutils' script removed (Ilya Kitaev)4e5521d
PendingTransactionImpl: pointer->reference (Ilya Kitaev)7b7cf21
commented regex (Ilya Kitaev)eec0f57
Typo fixed (Ilya Kitaev)f1c4a37
Wallet::createTransaction: added mixin_count param (Ilya Kitaev)3318add
double/string to monero integer convertion methods (Ilya Kitaev)3ac20a4
wallet::default_mixin exposed to public interface as Wallet::setDefaultMixin, Wallet::defaultMixin; wallet::create_transaction_2 used in Wallet::createTransaction (Ilya Kitaev)c554055
Wallet::filename, Wallet::keysFilename, tests for move wallet (Ilya Kitaev)8f9d98b
removed unused "using" (Ilya Kitaev)2facbe7
Wallet API : WalletManager::findWallets() added (Ilya Kitaev)ec949c3
scripts for faster test wallets generation (Ilya Kitaev)7f3d28f
regenerated test wallets, basic functions got broken (Ilya Kitaev)4327548
installing wallet_api header (Ilya Kitaev)7ac1342
cmake: BUILD_TESTS as option explicitly; added missed dependency (Ilya Kitaev)1f0d016
cmake libutils dependency added (Ilya Kitaev)d43ad22
all wallet dependencies merged to single static lib (Ilya Kitaev)9ae4e87
WalletListener::moneyReceived test (Ilya Kitaev)40087a7
WalletListener::moneySpent test (Ilya Kitaev)27d86b7
WalletListener::moneySpent(), WalletListener::moneyReceived() (Ilya Kitaev)ff52c67
i_wallet_callback: virtual dtor (Ilya Kitaev)5dbd2b8
started WalletListener (Ilya Kitaev)71131a8
TransactionHistory continued (Ilya Kitaev)9311934
TransactionHistory continued (Ilya Kitaev)566166a
merged with upstream (Ilya Kitaev)53a97bd
Wallet API: transaction history in progress (Ilya Kitaev)02c9df5
Wallet API : transaction history in progress (Ilya Kitaev)a213887
transaction history api in progress (Ilya Kitaev)b6aaf53
transaction history api in progress (Ilya Kitaev)f83f3cb
api implementation splitted over separate files (Ilya Kitaev)4e1c2dc
TransactionInfo / TransactionHistory APIs design (Ilya Kitaev)1774d95
TODOs for Transaction/Transfer interface (Ilya Kitaev)d97e9ef
Transaction API continued (Ilya Kitaev)079fbd3
Wallet::createTransaction API introduced (Ilya Kitaev)ee5bb17
Wallet::transfer() continued (Ilya Kitaev)c37c856
Wallet::transfer in progress (Ilya Kitaev)830c19c
Wallet::refresh + tests (Ilya Kitaev)1ae9cdc
"testnet" is default parameter (Ilya Kitaev)2157a9a
testnet option, Wallet::balance(), Wallet::unlockedBalance() (Ilya Kitaev)8790904
- testnet option added to api; (Ilya Kitaev)2cce329
wallet2::store() implemented within wallet2::store_to (Ilya Kitaev)d608647
WalletManager::findWallets: searching by "keys" files instead of "address.txt" files (Ilya Kitaev)ca61153
Wallet: payment id and integrated address (Ilya Kitaev)23cbf6f
PendingTransactionImpl: pointer->reference (Ilya Kitaev)c1d9e7c
commented regex (Ilya Kitaev)563baf1
Typo fixed (Ilya Kitaev)2efec04
Wallet::createTransaction: added mixin_count param (Ilya Kitaev)85a6322
double/string to monero integer convertion methods (Ilya Kitaev)e7d8f2a
wallet::default_mixin exposed to public interface as Wallet::setDefaultMixin, Wallet::defaultMixin; wallet::create_transaction_2 used in Wallet::createTransaction (Ilya Kitaev)a537489
Wallet::filename, Wallet::keysFilename, tests for move wallet (Ilya Kitaev)a1eddcd
removed unused "using" (Ilya Kitaev)8390bfa
Wallet API : WalletManager::findWallets() added (Ilya Kitaev)44cc0ef
scripts for faster test wallets generation (Ilya Kitaev)2060bfe
regenerated test wallets, basic functions got broken (Ilya Kitaev)dbc0b03
installing wallet_api header (Ilya Kitaev)653c7e3
cmake: BUILD_TESTS as option explicitly; added missed dependency (Ilya Kitaev)ef9a74c
cmake libutils dependency added (Ilya Kitaev)191cb59
all wallet dependencies merged to single static lib (Ilya Kitaev)91eeeb8
WalletListener::moneyReceived test (Ilya Kitaev)64348a2
WalletListener::moneySpent test (Ilya Kitaev)060bb62
WalletListener::moneySpent(), WalletListener::moneyReceived() (Ilya Kitaev)214014c
i_wallet_callback: virtual dtor (Ilya Kitaev)3745770
started WalletListener (Ilya Kitaev)e6fdd5d
TransactionHistory continued (Ilya Kitaev)3dd4b4c
merged with upstream (Ilya Kitaev)d500272
Wallet API : transaction history in progress (Ilya Kitaev)663ed04
transaction history api in progress (Ilya Kitaev)12345d3
api implementation splitted over separate files (Ilya Kitaev)60508e6
TransactionInfo / TransactionHistory APIs design (Ilya Kitaev)951f3b5
Wallet::createTransaction API introduced (Ilya Kitaev)7c51227
Wallet::transfer in progress (Ilya Kitaev)e04c67a
Wallet::refresh + tests (Ilya Kitaev)9cdf0b7
"testnet" is default parameter (Ilya Kitaev)caf0e02
testnet option, Wallet::balance(), Wallet::unlockedBalance() (Ilya Kitaev)8df820b
- testnet option added to api; (Ilya Kitaev)94eaeb5
wallet2::store() implemented within wallet2::store_to (Ilya Kitaev)
This commit is contained in:
commit
fc58069731
|
@ -455,6 +455,9 @@ include(version.cmake)
|
|||
add_subdirectory(contrib)
|
||||
add_subdirectory(src)
|
||||
|
||||
|
||||
option(BUILD_TESTS "Build tests." OFF)
|
||||
|
||||
if(BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
# Copyright (C) 2012 Modelon AB
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the BSD style license.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# FMILIB_License.txt file for more details.
|
||||
|
||||
# You should have received a copy of the FMILIB_License.txt file
|
||||
# along with this program. If not, contact Modelon AB <http://www.modelon.com>.
|
||||
|
||||
# Merge_static_libs(outlib lib1 lib2 ... libn) merges a number of static
|
||||
# libs into a single static library
|
||||
function(merge_static_libs outlib )
|
||||
set(libs ${ARGV})
|
||||
list(REMOVE_AT libs 0)
|
||||
# Create a dummy file that the target will depend on
|
||||
set(dummyfile ${CMAKE_CURRENT_BINARY_DIR}/${outlib}_dummy.c)
|
||||
file(WRITE ${dummyfile} "const char * dummy = \"${dummyfile}\";")
|
||||
|
||||
add_library(${outlib} STATIC ${dummyfile})
|
||||
|
||||
if("${CMAKE_CFG_INTDIR}" STREQUAL ".")
|
||||
set(multiconfig FALSE)
|
||||
else()
|
||||
set(multiconfig TRUE)
|
||||
endif()
|
||||
|
||||
# First get the file names of the libraries to be merged
|
||||
foreach(lib ${libs})
|
||||
get_target_property(libtype ${lib} TYPE)
|
||||
if(NOT libtype STREQUAL "STATIC_LIBRARY")
|
||||
message(FATAL_ERROR "Merge_static_libs can only process static libraries")
|
||||
endif()
|
||||
if(multiconfig)
|
||||
foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
|
||||
get_target_property("libfile_${CONFIG_TYPE}" ${lib} "LOCATION_${CONFIG_TYPE}")
|
||||
list(APPEND libfiles_${CONFIG_TYPE} ${libfile_${CONFIG_TYPE}})
|
||||
endforeach()
|
||||
else()
|
||||
get_target_property(libfile ${lib} LOCATION)
|
||||
list(APPEND libfiles "${libfile}")
|
||||
endif(multiconfig)
|
||||
endforeach()
|
||||
message(STATUS "will be merging ${libfiles}")
|
||||
# Just to be sure: cleanup from duplicates
|
||||
if(multiconfig)
|
||||
foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
|
||||
list(REMOVE_DUPLICATES libfiles_${CONFIG_TYPE})
|
||||
set(libfiles ${libfiles} ${libfiles_${CONFIG_TYPE}})
|
||||
endforeach()
|
||||
endif()
|
||||
list(REMOVE_DUPLICATES libfiles)
|
||||
|
||||
# Now the easy part for MSVC and for MAC
|
||||
if(MSVC)
|
||||
# lib.exe does the merging of libraries just need to conver the list into string
|
||||
foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
|
||||
set(flags "")
|
||||
foreach(lib ${libfiles_${CONFIG_TYPE}})
|
||||
set(flags "${flags} ${lib}")
|
||||
endforeach()
|
||||
string(TOUPPER "STATIC_LIBRARY_FLAGS_${CONFIG_TYPE}" PROPNAME)
|
||||
set_target_properties(${outlib} PROPERTIES ${PROPNAME} "${flags}")
|
||||
endforeach()
|
||||
|
||||
elseif(APPLE)
|
||||
# Use OSX's libtool to merge archives
|
||||
if(multiconfig)
|
||||
message(FATAL_ERROR "Multiple configurations are not supported")
|
||||
endif()
|
||||
get_target_property(outfile ${outlib} LOCATION)
|
||||
add_custom_command(TARGET ${outlib} POST_BUILD
|
||||
COMMAND rm ${outfile}
|
||||
COMMAND /usr/bin/libtool -static -o ${outfile}
|
||||
${libfiles}
|
||||
)
|
||||
else()
|
||||
# general UNIX - need to "ar -x" and then "ar -ru"
|
||||
if(multiconfig)
|
||||
message(FATAL_ERROR "Multiple configurations are not supported")
|
||||
endif()
|
||||
get_target_property(outfile ${outlib} LOCATION)
|
||||
message(STATUS "outfile location is ${outfile}")
|
||||
foreach(lib ${libfiles})
|
||||
# objlistfile will contain the list of object files for the library
|
||||
set(objlistfile ${lib}.objlist)
|
||||
set(objdir ${lib}.objdir)
|
||||
set(objlistcmake ${objlistfile}.cmake)
|
||||
# we only need to extract files once
|
||||
if(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/cmake.check_cache IS_NEWER_THAN ${objlistcmake})
|
||||
#---------------------------------
|
||||
FILE(WRITE ${objlistcmake}
|
||||
"# Extract object files from the library
|
||||
message(STATUS \"Extracting object files from ${lib}\")
|
||||
EXECUTE_PROCESS(COMMAND ${CMAKE_AR} -x ${lib}
|
||||
WORKING_DIRECTORY ${objdir})
|
||||
# save the list of object files
|
||||
EXECUTE_PROCESS(COMMAND ls .
|
||||
OUTPUT_FILE ${objlistfile}
|
||||
WORKING_DIRECTORY ${objdir})")
|
||||
#---------------------------------
|
||||
file(MAKE_DIRECTORY ${objdir})
|
||||
add_custom_command(
|
||||
OUTPUT ${objlistfile}
|
||||
COMMAND ${CMAKE_COMMAND} -P ${objlistcmake}
|
||||
DEPENDS ${lib})
|
||||
endif()
|
||||
list(APPEND extrafiles "${objlistfile}")
|
||||
# relative path is needed by ar under MSYS
|
||||
file(RELATIVE_PATH objlistfilerpath ${objdir} ${objlistfile})
|
||||
add_custom_command(TARGET ${outlib} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Running: ${CMAKE_AR} ru ${outfile} @${objlistfilerpath}"
|
||||
COMMAND ${CMAKE_AR} ru "${outfile}" @"${objlistfilerpath}"
|
||||
WORKING_DIRECTORY ${objdir})
|
||||
endforeach()
|
||||
add_custom_command(TARGET ${outlib} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Running: ${CMAKE_RANLIB} ${outfile}"
|
||||
COMMAND ${CMAKE_RANLIB} ${outfile})
|
||||
endif()
|
||||
file(WRITE ${dummyfile}.base "const char* ${outlib}_sublibs=\"${libs}\";")
|
||||
add_custom_command(
|
||||
OUTPUT ${dummyfile}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${dummyfile}.base ${dummyfile}
|
||||
DEPENDS ${libs} ${extrafiles})
|
||||
|
||||
endfunction()
|
|
@ -2999,7 +2999,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
|
|||
}
|
||||
|
||||
LOCK_REFRESH_THREAD_SCOPE();
|
||||
|
||||
|
||||
// optional in/out selector
|
||||
if (local_args.size() > 0) {
|
||||
if (local_args[0] == "in" || local_args[0] == "incoming") {
|
||||
|
|
|
@ -26,15 +26,24 @@
|
|||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# include (${PROJECT_SOURCE_DIR}/cmake/libutils.cmake)
|
||||
include (${PROJECT_SOURCE_DIR}/cmake/MergeStaticLibs.cmake)
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
set(wallet_sources
|
||||
wallet2.cpp
|
||||
wallet_rpc_server.cpp
|
||||
wallet2_api.cpp)
|
||||
api/wallet.cpp
|
||||
api/wallet_manager.cpp
|
||||
api/transaction_info.cpp
|
||||
api/transaction_history.cpp
|
||||
api/pending_transaction.cpp
|
||||
api/utils.cpp)
|
||||
|
||||
set(wallet_headers)
|
||||
set(wallet_api_headers
|
||||
wallet2_api.h)
|
||||
|
||||
|
||||
set(wallet_private_headers
|
||||
wallet2.h
|
||||
|
@ -42,13 +51,18 @@ set(wallet_private_headers
|
|||
wallet_rpc_server.h
|
||||
wallet_rpc_server_commands_defs.h
|
||||
wallet_rpc_server_error_codes.h
|
||||
wallet2_api.h)
|
||||
api/wallet.h
|
||||
api/wallet_manager.h
|
||||
api/transaction_info.h
|
||||
api/transaction_history.h
|
||||
api/pending_transaction.h
|
||||
api/common_defines.h)
|
||||
|
||||
bitmonero_private_headers(wallet
|
||||
${wallet_private_headers})
|
||||
bitmonero_add_library(wallet
|
||||
${wallet_sources}
|
||||
${wallet_headers}
|
||||
${wallet_api_headers}
|
||||
${wallet_private_headers})
|
||||
target_link_libraries(wallet
|
||||
LINK_PUBLIC
|
||||
|
@ -61,3 +75,15 @@ target_link_libraries(wallet
|
|||
${Boost_REGEX_LIBRARY}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
|
||||
set(libs_to_merge wallet cryptonote_core mnemonics common crypto)
|
||||
#MERGE_STATIC_LIBS(wallet_merged wallet_merged "${libs_to_merge}")
|
||||
merge_static_libs(wallet_merged "${libs_to_merge}")
|
||||
|
||||
install(TARGETS wallet_merged
|
||||
ARCHIVE DESTINATION lib)
|
||||
|
||||
install(FILES ${wallet_api_headers}
|
||||
DESTINATION include/wallet)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef WALLET_API_COMMON_DEFINES_H__
|
||||
#define WALLET_API_COMMON_DEFINES_H__
|
||||
|
||||
#define tr(x) (x)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "pending_transaction.h"
|
||||
#include "wallet.h"
|
||||
#include "common_defines.h"
|
||||
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
PendingTransaction::~PendingTransaction() {}
|
||||
|
||||
|
||||
PendingTransactionImpl::PendingTransactionImpl(WalletImpl &wallet)
|
||||
: m_wallet(wallet)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PendingTransactionImpl::~PendingTransactionImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int PendingTransactionImpl::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
string PendingTransactionImpl::errorString() const
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
bool PendingTransactionImpl::commit()
|
||||
{
|
||||
|
||||
LOG_PRINT_L0("m_pending_tx size: " << m_pending_tx.size());
|
||||
assert(m_pending_tx.size() == 1);
|
||||
try {
|
||||
while (!m_pending_tx.empty()) {
|
||||
auto & ptx = m_pending_tx.back();
|
||||
m_wallet.m_wallet->commit_tx(ptx);
|
||||
// success_msg_writer(true) << tr("Money successfully sent, transaction ") << get_transaction_hash(ptx.tx);
|
||||
// if no exception, remove element from vector
|
||||
m_pending_tx.pop_back();
|
||||
} // TODO: extract method;
|
||||
} catch (const tools::error::daemon_busy&) {
|
||||
// TODO: make it translatable with "tr"?
|
||||
m_errorString = tr("daemon is busy. Please try again later.");
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::no_connection_to_daemon&) {
|
||||
m_errorString = tr("no connection to daemon. Please make sure daemon is running.");
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::tx_rejected& e) {
|
||||
std::ostringstream writer(m_errorString);
|
||||
writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
|
||||
m_status = Status_Error;
|
||||
} catch (std::exception &e) {
|
||||
m_errorString = string(tr("Unknown exception: ")) + e.what();
|
||||
m_status = Status_Error;
|
||||
} catch (...) {
|
||||
m_errorString = tr("Unhandled exception");
|
||||
LOG_ERROR(m_errorString);
|
||||
m_status = Status_Error;
|
||||
}
|
||||
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
uint64_t PendingTransactionImpl::amount() const
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (const auto &ptx : m_pending_tx) {
|
||||
for (const auto &dest : ptx.dests) {
|
||||
result += dest.amount;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t PendingTransactionImpl::dust() const
|
||||
{
|
||||
uint32_t result = 0;
|
||||
for (const auto & ptx : m_pending_tx) {
|
||||
result += ptx.dust;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t PendingTransactionImpl::fee() const
|
||||
{
|
||||
uint32_t result = 0;
|
||||
for (const auto ptx : m_pending_tx) {
|
||||
result += ptx.fee;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "wallet/wallet2_api.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
class WalletImpl;
|
||||
class PendingTransactionImpl : public PendingTransaction
|
||||
{
|
||||
public:
|
||||
PendingTransactionImpl(WalletImpl &wallet);
|
||||
~PendingTransactionImpl();
|
||||
int status() const;
|
||||
std::string errorString() const;
|
||||
bool commit();
|
||||
uint64_t amount() const;
|
||||
uint64_t dust() const;
|
||||
uint64_t fee() const;
|
||||
// TODO: continue with interface;
|
||||
|
||||
private:
|
||||
friend class WalletImpl;
|
||||
WalletImpl &m_wallet;
|
||||
|
||||
int m_status;
|
||||
std::string m_errorString;
|
||||
std::vector<tools::wallet2::pending_tx> m_pending_tx;
|
||||
};
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
|
||||
#include "transaction_history.h"
|
||||
#include "transaction_info.h"
|
||||
#include "wallet.h"
|
||||
|
||||
#include "crypto/hash.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
using namespace epee;
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
TransactionHistory::~TransactionHistory() {}
|
||||
|
||||
|
||||
TransactionHistoryImpl::TransactionHistoryImpl(WalletImpl *wallet)
|
||||
: m_wallet(wallet)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TransactionHistoryImpl::~TransactionHistoryImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int TransactionHistoryImpl::count() const
|
||||
{
|
||||
return m_history.size();
|
||||
}
|
||||
|
||||
TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<TransactionInfo *> TransactionHistoryImpl::getAll() const
|
||||
{
|
||||
return m_history;
|
||||
}
|
||||
|
||||
void TransactionHistoryImpl::refresh()
|
||||
{
|
||||
// TODO: configurable values;
|
||||
uint64_t min_height = 0;
|
||||
uint64_t max_height = (uint64_t)-1;
|
||||
|
||||
// delete old transactions;
|
||||
for (auto t : m_history)
|
||||
delete t;
|
||||
m_history.clear();
|
||||
|
||||
|
||||
|
||||
// transactions are stored in wallet2:
|
||||
// - confirmed_transfer_details - out transfers
|
||||
// - unconfirmed_transfer_details - pending out transfers
|
||||
// - payment_details - input transfers
|
||||
|
||||
// payments are "input transactions";
|
||||
// one input transaction contains only one transfer. e.g. <transaction_id> - <100XMR>
|
||||
|
||||
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> in_payments;
|
||||
m_wallet->m_wallet->get_payments(in_payments, min_height, max_height);
|
||||
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = in_payments.begin(); i != in_payments.end(); ++i) {
|
||||
const tools::wallet2::payment_details &pd = i->second;
|
||||
std::string payment_id = string_tools::pod_to_hex(i->first);
|
||||
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
|
||||
payment_id = payment_id.substr(0,16);
|
||||
// TODO
|
||||
TransactionInfoImpl * ti = new TransactionInfoImpl();
|
||||
ti->m_paymentid = payment_id;
|
||||
ti->m_amount = pd.m_amount;
|
||||
ti->m_direction = TransactionInfo::Direction_In;
|
||||
ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
|
||||
ti->m_blockheight = pd.m_block_height;
|
||||
// TODO:
|
||||
// ti->m_timestamp = pd.m_timestamp;
|
||||
m_history.push_back(ti);
|
||||
|
||||
/* output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%20.20s %s %s %s")
|
||||
% print_money(pd.m_amount)
|
||||
% string_tools::pod_to_hex(pd.m_tx_hash)
|
||||
% payment_id % "-").str()))); */
|
||||
}
|
||||
|
||||
// confirmed output transactions
|
||||
// one output transaction may contain more than one money transfer, e.g.
|
||||
// <transaction_id>:
|
||||
// transfer1: 100XMR to <address_1>
|
||||
// transfer2: 50XMR to <address_2>
|
||||
// fee: fee charged per transaction
|
||||
//
|
||||
|
||||
std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> out_payments;
|
||||
m_wallet->m_wallet->get_payments_out(out_payments, min_height, max_height);
|
||||
|
||||
for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = out_payments.begin();
|
||||
i != out_payments.end(); ++i) {
|
||||
|
||||
const crypto::hash &hash = i->first;
|
||||
const tools::wallet2::confirmed_transfer_details &pd = i->second;
|
||||
|
||||
uint64_t fee = pd.m_amount_in - pd.m_amount_out;
|
||||
uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
|
||||
|
||||
|
||||
std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id);
|
||||
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
|
||||
payment_id = payment_id.substr(0,16);
|
||||
|
||||
|
||||
TransactionInfoImpl * ti = new TransactionInfoImpl();
|
||||
ti->m_paymentid = payment_id;
|
||||
ti->m_amount = pd.m_amount_in - change - fee;
|
||||
ti->m_fee = fee;
|
||||
ti->m_direction = TransactionInfo::Direction_Out;
|
||||
ti->m_hash = string_tools::pod_to_hex(hash);
|
||||
ti->m_blockheight = pd.m_block_height;
|
||||
|
||||
// single output transaction might contain multiple transfers
|
||||
for (const auto &d: pd.m_dests) {
|
||||
ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->testnet(), d.addr)});
|
||||
}
|
||||
m_history.push_back(ti);
|
||||
}
|
||||
|
||||
// unconfirmed output transactions
|
||||
std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments;
|
||||
m_wallet->m_wallet->get_unconfirmed_payments_out(upayments);
|
||||
for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
|
||||
const tools::wallet2::unconfirmed_transfer_details &pd = i->second;
|
||||
const crypto::hash &hash = i->first;
|
||||
uint64_t amount = 0;
|
||||
cryptonote::get_inputs_money_amount(pd.m_tx, amount);
|
||||
uint64_t fee = amount - get_outs_money_amount(pd.m_tx);
|
||||
std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id);
|
||||
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
|
||||
payment_id = payment_id.substr(0,16);
|
||||
bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed;
|
||||
|
||||
TransactionInfoImpl * ti = new TransactionInfoImpl();
|
||||
ti->m_paymentid = payment_id;
|
||||
ti->m_amount = amount - pd.m_change;
|
||||
ti->m_fee = fee;
|
||||
ti->m_direction = TransactionInfo::Direction_Out;
|
||||
ti->m_failed = is_failed;
|
||||
ti->m_pending = true;
|
||||
ti->m_hash = string_tools::pod_to_hex(hash);
|
||||
m_history.push_back(ti);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TransactionInfo *TransactionHistoryImpl::transaction(int index) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "wallet/wallet2_api.h"
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
class TransactionInfo;
|
||||
class WalletImpl;
|
||||
|
||||
class TransactionHistoryImpl : public TransactionHistory
|
||||
{
|
||||
public:
|
||||
TransactionHistoryImpl(WalletImpl * wallet);
|
||||
~TransactionHistoryImpl();
|
||||
virtual int count() const;
|
||||
virtual TransactionInfo * transaction(int index) const;
|
||||
virtual TransactionInfo * transaction(const std::string &id) const;
|
||||
virtual std::vector<TransactionInfo*> getAll() const;
|
||||
virtual void refresh();
|
||||
|
||||
private:
|
||||
|
||||
// TransactionHistory is responsible of memory management
|
||||
std::vector<TransactionInfo*> m_history;
|
||||
WalletImpl *m_wallet;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "transaction_info.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
TransactionInfo::~TransactionInfo() {}
|
||||
|
||||
TransactionInfo::Transfer::Transfer(uint64_t _amount, const string &_address)
|
||||
: amount(_amount), address(_address) {}
|
||||
|
||||
|
||||
TransactionInfoImpl::TransactionInfoImpl()
|
||||
: m_direction(Direction_Out)
|
||||
, m_pending(false)
|
||||
, m_failed(false)
|
||||
, m_amount(0)
|
||||
, m_fee(0)
|
||||
, m_blockheight(0)
|
||||
, m_timestamp(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TransactionInfoImpl::~TransactionInfoImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int TransactionInfoImpl::direction() const
|
||||
{
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
|
||||
bool TransactionInfoImpl::isPending() const
|
||||
{
|
||||
return m_pending;
|
||||
}
|
||||
|
||||
bool TransactionInfoImpl::isFailed() const
|
||||
{
|
||||
return m_failed;
|
||||
}
|
||||
|
||||
uint64_t TransactionInfoImpl::amount() const
|
||||
{
|
||||
return m_amount;
|
||||
}
|
||||
|
||||
uint64_t TransactionInfoImpl::fee() const
|
||||
{
|
||||
return m_fee;
|
||||
}
|
||||
|
||||
uint64_t TransactionInfoImpl::blockHeight() const
|
||||
{
|
||||
return m_blockheight;
|
||||
}
|
||||
|
||||
string TransactionInfoImpl::hash() const
|
||||
{
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
std::time_t TransactionInfoImpl::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
string TransactionInfoImpl::paymentId() const
|
||||
{
|
||||
return m_paymentid;
|
||||
}
|
||||
|
||||
const std::vector<TransactionInfo::Transfer> &TransactionInfoImpl::transfers() const
|
||||
{
|
||||
return m_transfers;
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "wallet/wallet2_api.h"
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
class TransactionHistoryImpl;
|
||||
|
||||
class TransactionInfoImpl : public TransactionInfo
|
||||
{
|
||||
public:
|
||||
TransactionInfoImpl();
|
||||
~TransactionInfoImpl();
|
||||
//! in/out
|
||||
virtual int direction() const;
|
||||
//! true if hold
|
||||
virtual bool isPending() const;
|
||||
virtual bool isFailed() const;
|
||||
virtual uint64_t amount() const;
|
||||
//! always 0 for incoming txes
|
||||
virtual uint64_t fee() const;
|
||||
virtual uint64_t blockHeight() const;
|
||||
|
||||
virtual std::string hash() const;
|
||||
virtual std::time_t timestamp() const;
|
||||
virtual std::string paymentId() const;
|
||||
virtual const std::vector<Transfer> &transfers() const;
|
||||
|
||||
private:
|
||||
int m_direction;
|
||||
bool m_pending;
|
||||
bool m_failed;
|
||||
uint64_t m_amount;
|
||||
uint64_t m_fee;
|
||||
uint64_t m_blockheight;
|
||||
std::string m_hash;
|
||||
std::time_t m_timestamp;
|
||||
std::string m_paymentid;
|
||||
std::vector<Transfer> m_transfers;
|
||||
|
||||
friend class TransactionHistoryImpl;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
|
||||
|
||||
#include "include_base_utils.h" // LOG_PRINT_x
|
||||
#include "net/http_client.h" // epee::net_utils::...
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Bitmonero {
|
||||
namespace Utils {
|
||||
|
||||
|
||||
// copy-pasted from simplewallet.
|
||||
|
||||
bool isAddressLocal(const std::string &address)
|
||||
{
|
||||
// extract host
|
||||
epee::net_utils::http::url_content u_c;
|
||||
if (!epee::net_utils::parse_url(address, u_c))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not");
|
||||
return false;
|
||||
}
|
||||
if (u_c.host.empty())
|
||||
{
|
||||
LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not");
|
||||
return false;
|
||||
}
|
||||
|
||||
// resolve to IP
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::ip::tcp::resolver resolver(io_service);
|
||||
boost::asio::ip::tcp::resolver::query query(u_c.host, "");
|
||||
boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query);
|
||||
while (i != boost::asio::ip::tcp::resolver::iterator())
|
||||
{
|
||||
const boost::asio::ip::tcp::endpoint &ep = *i;
|
||||
if (ep.address().is_loopback())
|
||||
return true;
|
||||
++i;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,588 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
|
||||
#include "wallet.h"
|
||||
#include "pending_transaction.h"
|
||||
#include "transaction_history.h"
|
||||
#include "common_defines.h"
|
||||
|
||||
#include "mnemonics/electrum-words.h"
|
||||
#include <boost/format.hpp>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cryptonote;
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
namespace {
|
||||
// copy-pasted from simplewallet
|
||||
static const size_t DEFAULT_MIXIN = 4;
|
||||
}
|
||||
|
||||
struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
||||
{
|
||||
|
||||
Wallet2CallbackImpl()
|
||||
: m_listener(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~Wallet2CallbackImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void setListener(WalletListener * listener)
|
||||
{
|
||||
m_listener = listener;
|
||||
}
|
||||
|
||||
WalletListener * getListener() const
|
||||
{
|
||||
return m_listener;
|
||||
}
|
||||
|
||||
virtual void on_new_block(uint64_t height, const cryptonote::block& block)
|
||||
{
|
||||
// TODO;
|
||||
LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height);
|
||||
}
|
||||
|
||||
virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index)
|
||||
{
|
||||
|
||||
std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx));
|
||||
uint64_t amount = tx.vout[out_index].amount;
|
||||
|
||||
LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height
|
||||
<< ", tx: " << tx_hash
|
||||
<< ", amount: " << print_money(amount));
|
||||
if (m_listener) {
|
||||
m_listener->moneyReceived(tx_hash, amount);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index,
|
||||
const cryptonote::transaction& spend_tx)
|
||||
{
|
||||
// TODO;
|
||||
std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(spend_tx));
|
||||
uint64_t amount = in_tx.vout[out_index].amount;
|
||||
LOG_PRINT_L3(__FUNCTION__ << ": money spent. height: " << height
|
||||
<< ", tx: " << tx_hash
|
||||
<< ", amount: " << print_money(amount));
|
||||
if (m_listener) {
|
||||
m_listener->moneySpent(tx_hash, amount);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx)
|
||||
{
|
||||
// TODO;
|
||||
}
|
||||
|
||||
WalletListener * m_listener;
|
||||
};
|
||||
|
||||
Wallet::~Wallet() {}
|
||||
|
||||
WalletListener::~WalletListener() {}
|
||||
|
||||
string Wallet::displayAmount(uint64_t amount)
|
||||
{
|
||||
return cryptonote::print_money(amount);
|
||||
}
|
||||
|
||||
uint64_t Wallet::amountFromString(const string &amount)
|
||||
{
|
||||
uint64_t result;
|
||||
cryptonote::parse_amount(result, amount);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t Wallet::amountFromDouble(double amount)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(CRYPTONOTE_DISPLAY_DECIMAL_POINT) << amount;
|
||||
return amountFromString(ss.str());
|
||||
}
|
||||
|
||||
std::string Wallet::genPaymentId()
|
||||
{
|
||||
crypto::hash8 payment_id = crypto::rand<crypto::hash8>();
|
||||
return epee::string_tools::pod_to_hex(payment_id);
|
||||
|
||||
}
|
||||
|
||||
|
||||
///////////////////////// WalletImpl implementation ////////////////////////
|
||||
WalletImpl::WalletImpl(bool testnet)
|
||||
:m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false),
|
||||
m_wallet2Callback(nullptr)
|
||||
{
|
||||
m_wallet = new tools::wallet2(testnet);
|
||||
m_history = new TransactionHistoryImpl(this);
|
||||
m_wallet2Callback = new Wallet2CallbackImpl;
|
||||
}
|
||||
|
||||
WalletImpl::~WalletImpl()
|
||||
{
|
||||
delete m_wallet2Callback;
|
||||
delete m_history;
|
||||
delete m_wallet;
|
||||
}
|
||||
|
||||
bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language)
|
||||
{
|
||||
|
||||
clearStatus();
|
||||
|
||||
bool keys_file_exists;
|
||||
bool wallet_file_exists;
|
||||
tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists);
|
||||
// TODO: figure out how to setup logger;
|
||||
LOG_PRINT_L3("wallet_path: " << path << "");
|
||||
LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha
|
||||
<< " wallet_file_exists: " << std::boolalpha << wallet_file_exists << std::noboolalpha);
|
||||
|
||||
|
||||
// add logic to error out if new wallet requested but named wallet file exists
|
||||
if (keys_file_exists || wallet_file_exists) {
|
||||
m_errorString = "attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting.";
|
||||
LOG_ERROR(m_errorString);
|
||||
m_status = Status_Error;
|
||||
return false;
|
||||
}
|
||||
// TODO: validate language
|
||||
m_wallet->set_seed_language(language);
|
||||
crypto::secret_key recovery_val, secret_key;
|
||||
try {
|
||||
recovery_val = m_wallet->generate(path, password, secret_key, false, false);
|
||||
m_password = password;
|
||||
m_status = Status_Ok;
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR("Error creating wallet: " << e.what());
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WalletImpl::open(const std::string &path, const std::string &password)
|
||||
{
|
||||
clearStatus();
|
||||
try {
|
||||
// TODO: handle "deprecated"
|
||||
m_wallet->load(path, password);
|
||||
|
||||
m_password = password;
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR("Error opening wallet: " << e.what());
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
bool WalletImpl::recover(const std::string &path, const std::string &seed)
|
||||
{
|
||||
clearStatus();
|
||||
m_errorString.clear();
|
||||
if (seed.empty()) {
|
||||
m_errorString = "Electrum seed is empty";
|
||||
LOG_ERROR(m_errorString);
|
||||
m_status = Status_Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::secret_key recovery_key;
|
||||
std::string old_language;
|
||||
if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) {
|
||||
m_errorString = "Electrum-style word list failed verification";
|
||||
m_status = Status_Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
m_wallet->set_seed_language(old_language);
|
||||
m_wallet->generate(path, "", recovery_key, true, false);
|
||||
// TODO: wallet->init(daemon_address);
|
||||
} catch (const std::exception &e) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
bool WalletImpl::close()
|
||||
{
|
||||
clearStatus();
|
||||
bool result = false;
|
||||
try {
|
||||
m_wallet->store();
|
||||
m_wallet->stop();
|
||||
result = true;
|
||||
} catch (const std::exception &e) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
LOG_ERROR("Error closing wallet: " << e.what());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string WalletImpl::seed() const
|
||||
{
|
||||
std::string seed;
|
||||
if (m_wallet)
|
||||
m_wallet->get_seed(seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
std::string WalletImpl::getSeedLanguage() const
|
||||
{
|
||||
return m_wallet->get_seed_language();
|
||||
}
|
||||
|
||||
void WalletImpl::setSeedLanguage(const std::string &arg)
|
||||
{
|
||||
m_wallet->set_seed_language(arg);
|
||||
}
|
||||
|
||||
int WalletImpl::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
std::string WalletImpl::errorString() const
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
bool WalletImpl::setPassword(const std::string &password)
|
||||
{
|
||||
clearStatus();
|
||||
try {
|
||||
m_wallet->rewrite(m_wallet->get_wallet_file(), password);
|
||||
m_password = password;
|
||||
} catch (const std::exception &e) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
std::string WalletImpl::address() const
|
||||
{
|
||||
return m_wallet->get_account().get_public_address_str(m_wallet->testnet());
|
||||
}
|
||||
|
||||
std::string WalletImpl::integratedAddress(const std::string &payment_id) const
|
||||
{
|
||||
crypto::hash8 pid;
|
||||
if (!tools::wallet2::parse_short_payment_id(payment_id, pid)) {
|
||||
pid = crypto::rand<crypto::hash8>();
|
||||
}
|
||||
return m_wallet->get_account().get_public_integrated_address_str(pid, m_wallet->testnet());
|
||||
}
|
||||
|
||||
bool WalletImpl::store(const std::string &path)
|
||||
{
|
||||
clearStatus();
|
||||
try {
|
||||
if (path.empty()) {
|
||||
m_wallet->store();
|
||||
} else {
|
||||
m_wallet->store_to(path, m_password);
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR("Error storing wallet: " << e.what());
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
string WalletImpl::filename() const
|
||||
{
|
||||
return m_wallet->get_wallet_file();
|
||||
}
|
||||
|
||||
string WalletImpl::keysFilename() const
|
||||
{
|
||||
return m_wallet->get_keys_file();
|
||||
}
|
||||
|
||||
bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit)
|
||||
{
|
||||
clearStatus();
|
||||
try {
|
||||
m_wallet->init(daemon_address, upper_transaction_size_limit);
|
||||
if (Utils::isAddressLocal(daemon_address)) {
|
||||
this->setTrustedDaemon(true);
|
||||
}
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR("Error initializing wallet: " << e.what());
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
uint64_t WalletImpl::balance() const
|
||||
{
|
||||
return m_wallet->balance();
|
||||
}
|
||||
|
||||
uint64_t WalletImpl::unlockedBalance() const
|
||||
{
|
||||
return m_wallet->unlocked_balance();
|
||||
}
|
||||
|
||||
|
||||
bool WalletImpl::refresh()
|
||||
{
|
||||
clearStatus();
|
||||
try {
|
||||
m_wallet->refresh();
|
||||
} catch (const std::exception &e) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
|
||||
// 2 - check / design how "Transaction" can be single interface
|
||||
// (instead of few different data structures within wallet2 implementation:
|
||||
// - pending_tx;
|
||||
// - transfer_details;
|
||||
// - payment_details;
|
||||
// - unconfirmed_transfer_details;
|
||||
// - confirmed_transfer_details)
|
||||
|
||||
PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count)
|
||||
{
|
||||
clearStatus();
|
||||
vector<cryptonote::tx_destination_entry> dsts;
|
||||
cryptonote::tx_destination_entry de;
|
||||
|
||||
// indicates if dst_addr is integrated address (address + payment_id)
|
||||
bool has_payment_id;
|
||||
crypto::hash8 payment_id_short;
|
||||
// TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441)
|
||||
size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin();
|
||||
if (fake_outs_count == 0)
|
||||
fake_outs_count = DEFAULT_MIXIN;
|
||||
|
||||
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
|
||||
|
||||
do {
|
||||
if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, payment_id_short, m_wallet->testnet(), dst_addr)) {
|
||||
// TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982
|
||||
m_status = Status_Error;
|
||||
m_errorString = "Invalid destination address";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint8_t> extra;
|
||||
// if dst_addr is not an integrated address, parse payment_id
|
||||
if (!has_payment_id && !payment_id.empty()) {
|
||||
// copy-pasted from simplewallet.cpp:2212
|
||||
crypto::hash payment_id_long;
|
||||
bool r = tools::wallet2::parse_long_payment_id(payment_id, payment_id_long);
|
||||
if (r) {
|
||||
std::string extra_nonce;
|
||||
cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long);
|
||||
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
|
||||
} else {
|
||||
r = tools::wallet2::parse_short_payment_id(payment_id, payment_id_short);
|
||||
if (r) {
|
||||
std::string extra_nonce;
|
||||
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_short);
|
||||
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
|
||||
}
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = tr("payment id has invalid format, expected 16 or 64 character hex string: ") + payment_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
de.amount = amount;
|
||||
if (de.amount <= 0) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = "Invalid amount";
|
||||
break;
|
||||
}
|
||||
|
||||
dsts.push_back(de);
|
||||
//std::vector<tools::wallet2::pending_tx> ptx_vector;
|
||||
|
||||
try {
|
||||
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
|
||||
0 /* unused fee arg*/, extra, m_trustedDaemon);
|
||||
|
||||
} catch (const tools::error::daemon_busy&) {
|
||||
// TODO: make it translatable with "tr"?
|
||||
m_errorString = tr("daemon is busy. Please try again later.");
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::no_connection_to_daemon&) {
|
||||
m_errorString = tr("no connection to daemon. Please make sure daemon is running.");
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::wallet_rpc_error& e) {
|
||||
m_errorString = tr("RPC error: ") + e.to_string();
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::get_random_outs_error&) {
|
||||
m_errorString = tr("failed to get random outputs to mix");
|
||||
m_status = Status_Error;
|
||||
|
||||
} catch (const tools::error::not_enough_money& e) {
|
||||
m_status = Status_Error;
|
||||
std::ostringstream writer;
|
||||
|
||||
writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) %
|
||||
print_money(e.available()) %
|
||||
print_money(e.tx_amount() + e.fee()) %
|
||||
print_money(e.tx_amount()) %
|
||||
print_money(e.fee());
|
||||
m_errorString = writer.str();
|
||||
|
||||
} catch (const tools::error::not_enough_outs_to_mix& e) {
|
||||
std::ostringstream writer;
|
||||
writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":";
|
||||
for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) {
|
||||
writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size();
|
||||
}
|
||||
m_errorString = writer.str();
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::tx_not_constructed&) {
|
||||
m_errorString = tr("transaction was not constructed");
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::tx_rejected& e) {
|
||||
std::ostringstream writer;
|
||||
writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
|
||||
m_errorString = writer.str();
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::tx_sum_overflow& e) {
|
||||
m_errorString = e.what();
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::zero_destination&) {
|
||||
m_errorString = tr("one of destinations is zero");
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::tx_too_big& e) {
|
||||
m_errorString = tr("failed to find a suitable way to split transactions");
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::transfer_error& e) {
|
||||
m_errorString = string(tr("unknown transfer error: ")) + e.what();
|
||||
m_status = Status_Error;
|
||||
} catch (const tools::error::wallet_internal_error& e) {
|
||||
m_errorString = string(tr("internal error: ")) + e.what();
|
||||
m_status = Status_Error;
|
||||
} catch (const std::exception& e) {
|
||||
m_errorString = string(tr("unexpected error: ")) + e.what();
|
||||
m_status = Status_Error;
|
||||
} catch (...) {
|
||||
m_errorString = tr("unknown error");
|
||||
m_status = Status_Error;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
transaction->m_status = m_status;
|
||||
transaction->m_errorString = m_errorString;
|
||||
return transaction;
|
||||
}
|
||||
|
||||
void WalletImpl::disposeTransaction(PendingTransaction *t)
|
||||
{
|
||||
delete t;
|
||||
}
|
||||
|
||||
TransactionHistory *WalletImpl::history() const
|
||||
{
|
||||
return m_history;
|
||||
}
|
||||
|
||||
void WalletImpl::setListener(WalletListener *l)
|
||||
{
|
||||
// TODO thread synchronization;
|
||||
m_wallet2Callback->setListener(l);
|
||||
}
|
||||
|
||||
uint32_t WalletImpl::defaultMixin() const
|
||||
{
|
||||
return m_wallet->default_mixin();
|
||||
}
|
||||
|
||||
void WalletImpl::setDefaultMixin(uint32_t arg)
|
||||
{
|
||||
m_wallet->default_mixin(arg);
|
||||
}
|
||||
|
||||
|
||||
bool WalletImpl::connectToDaemon()
|
||||
{
|
||||
bool result = m_wallet->check_connection();
|
||||
m_status = result ? Status_Ok : Status_Error;
|
||||
if (!result) {
|
||||
m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void WalletImpl::setTrustedDaemon(bool arg)
|
||||
{
|
||||
m_trustedDaemon = arg;
|
||||
}
|
||||
|
||||
bool WalletImpl::trustedDaemon() const
|
||||
{
|
||||
return m_trustedDaemon;
|
||||
}
|
||||
|
||||
void WalletImpl::clearStatus()
|
||||
{
|
||||
m_status = Status_Ok;
|
||||
m_errorString.clear();
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#ifndef WALLET_IMPL_H
|
||||
#define WALLET_IMPL_H
|
||||
|
||||
#include "wallet/wallet2_api.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace Bitmonero {
|
||||
class TransactionHistoryImpl;
|
||||
class PendingTransactionImpl;
|
||||
struct Wallet2CallbackImpl;
|
||||
|
||||
class WalletImpl : public Wallet
|
||||
{
|
||||
public:
|
||||
WalletImpl(bool testnet = false);
|
||||
~WalletImpl();
|
||||
bool create(const std::string &path, const std::string &password,
|
||||
const std::string &language);
|
||||
bool open(const std::string &path, const std::string &password);
|
||||
bool recover(const std::string &path, const std::string &seed);
|
||||
bool close();
|
||||
std::string seed() const;
|
||||
std::string getSeedLanguage() const;
|
||||
void setSeedLanguage(const std::string &arg);
|
||||
// void setListener(Listener *) {}
|
||||
int status() const;
|
||||
std::string errorString() const;
|
||||
bool setPassword(const std::string &password);
|
||||
std::string address() const;
|
||||
std::string integratedAddress(const std::string &payment_id) const;
|
||||
bool store(const std::string &path);
|
||||
std::string filename() const;
|
||||
std::string keysFilename() const;
|
||||
bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
|
||||
bool connectToDaemon();
|
||||
void setTrustedDaemon(bool arg);
|
||||
bool trustedDaemon() const;
|
||||
uint64_t balance() const;
|
||||
uint64_t unlockedBalance() const;
|
||||
bool refresh();
|
||||
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
|
||||
uint64_t amount, uint32_t mixin_count);
|
||||
virtual void disposeTransaction(PendingTransaction * t);
|
||||
virtual TransactionHistory * history() const;
|
||||
virtual void setListener(WalletListener * l);
|
||||
virtual uint32_t defaultMixin() const;
|
||||
virtual void setDefaultMixin(uint32_t arg);
|
||||
|
||||
private:
|
||||
void clearStatus();
|
||||
|
||||
private:
|
||||
friend class PendingTransactionImpl;
|
||||
friend class TransactionHistoryImpl;
|
||||
|
||||
tools::wallet2 * m_wallet;
|
||||
int m_status;
|
||||
std::string m_errorString;
|
||||
std::string m_password;
|
||||
TransactionHistoryImpl * m_history;
|
||||
bool m_trustedDaemon;
|
||||
WalletListener * m_walletListener;
|
||||
Wallet2CallbackImpl * m_wallet2Callback;
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
|
||||
#include "wallet_manager.h"
|
||||
#include "wallet.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
|
||||
namespace epee {
|
||||
unsigned int g_test_dbg_lock_sleep = 0;
|
||||
}
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password,
|
||||
const std::string &language, bool testnet)
|
||||
{
|
||||
WalletImpl * wallet = new WalletImpl(testnet);
|
||||
wallet->create(path, password, language);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, bool testnet)
|
||||
{
|
||||
WalletImpl * wallet = new WalletImpl(testnet);
|
||||
wallet->open(path, password);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &memo, bool testnet)
|
||||
{
|
||||
WalletImpl * wallet = new WalletImpl(testnet);
|
||||
wallet->recover(path, memo);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
bool WalletManagerImpl::closeWallet(Wallet *wallet)
|
||||
{
|
||||
WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
|
||||
bool result = wallet_->close();
|
||||
if (!result) {
|
||||
m_errorString = wallet_->errorString();
|
||||
} else {
|
||||
delete wallet_;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WalletManagerImpl::walletExists(const std::string &path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
const boost::regex wallet_rx("(.*)\\.(keys)$"); // searching for <wallet_name>.keys files
|
||||
boost::filesystem::recursive_directory_iterator end_itr; // Default ctor yields past-the-end
|
||||
boost::filesystem::path work_dir(path);
|
||||
|
||||
for (boost::filesystem::recursive_directory_iterator itr(path); itr != end_itr; ++itr) {
|
||||
// Skip if not a file
|
||||
if (!boost::filesystem::is_regular_file(itr->status()))
|
||||
continue;
|
||||
boost::smatch what;
|
||||
std::string filename = itr->path().filename().string();
|
||||
|
||||
LOG_PRINT_L3("Checking filename: " << filename);
|
||||
|
||||
bool matched = boost::regex_match(filename, what, wallet_rx);
|
||||
if (matched) {
|
||||
// if keys file found, checking if there's wallet file itself
|
||||
std::string wallet_file = (itr->path().parent_path() /= what[1]).string();
|
||||
if (boost::filesystem::exists(wallet_file)) {
|
||||
LOG_PRINT_L3("Found wallet: " << wallet_file);
|
||||
result.push_back(wallet_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string WalletManagerImpl::errorString() const
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
void WalletManagerImpl::setDaemonHost(const std::string &hostname)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////// WalletManagerFactory implementation //////////////////////
|
||||
WalletManager *WalletManagerFactory::getWalletManager()
|
||||
{
|
||||
|
||||
static WalletManagerImpl * g_walletManager = nullptr;
|
||||
|
||||
if (!g_walletManager) {
|
||||
epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_MAX);
|
||||
g_walletManager = new WalletManagerImpl();
|
||||
}
|
||||
|
||||
return g_walletManager;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
|
||||
#include "wallet/wallet2_api.h"
|
||||
#include <string>
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
class WalletManagerImpl : public WalletManager
|
||||
{
|
||||
public:
|
||||
Wallet * createWallet(const std::string &path, const std::string &password,
|
||||
const std::string &language, bool testnet);
|
||||
Wallet * openWallet(const std::string &path, const std::string &password, bool testnet);
|
||||
virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet);
|
||||
virtual bool closeWallet(Wallet *wallet);
|
||||
bool walletExists(const std::string &path);
|
||||
std::vector<std::string> findWallets(const std::string &path);
|
||||
std::string errorString() const;
|
||||
void setDaemonHost(const std::string &hostname);
|
||||
|
||||
private:
|
||||
WalletManagerImpl() {}
|
||||
friend struct WalletManagerFactory;
|
||||
std::string m_errorString;
|
||||
};
|
||||
|
||||
} // namespace
|
|
@ -1545,6 +1545,42 @@ void wallet2::check_genesis(const crypto::hash& genesis_hash) const {
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::store()
|
||||
{
|
||||
store_to("", "");
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::store_to(const std::string &path, const std::string &password)
|
||||
{
|
||||
// if file is the same, we do:
|
||||
// 1. save wallet to the *.new file
|
||||
// 2. remove old wallet file
|
||||
// 3. rename *.new to wallet_name
|
||||
|
||||
// handle if we want just store wallet state to current files (ex store() replacement);
|
||||
bool same_file = true;
|
||||
if (!path.empty())
|
||||
{
|
||||
std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string();
|
||||
size_t pos = canonical_path.find(path);
|
||||
same_file = pos != std::string::npos;
|
||||
}
|
||||
|
||||
|
||||
if (!same_file)
|
||||
{
|
||||
// check if we want to store to directory which doesn't exists yet
|
||||
boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
|
||||
|
||||
// if path is not exists, try to create it
|
||||
if (!parent_path.empty() && !boost::filesystem::exists(parent_path))
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
if (!boost::filesystem::create_directories(parent_path, ec))
|
||||
{
|
||||
throw std::logic_error(ec.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
// preparing wallet data
|
||||
std::stringstream oss;
|
||||
boost::archive::binary_oarchive ar(oss);
|
||||
ar << *this;
|
||||
|
@ -1559,10 +1595,10 @@ void wallet2::store()
|
|||
crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]);
|
||||
cache_file_data.cache_data = cipher;
|
||||
|
||||
// save to new file, rename main to old, rename new to main
|
||||
// at all times, there should be a valid file on disk
|
||||
const std::string new_file = m_wallet_file + ".new";
|
||||
const std::string old_file = m_wallet_file + ".old";
|
||||
const std::string new_file = same_file ? m_wallet_file + ".new" : path;
|
||||
const std::string old_file = m_wallet_file;
|
||||
const std::string old_keys_file = m_keys_file;
|
||||
const std::string old_address_file = m_wallet_file + ".address.txt";
|
||||
|
||||
// save to new file
|
||||
std::ofstream ostr;
|
||||
|
@ -1572,87 +1608,35 @@ void wallet2::store()
|
|||
ostr.close();
|
||||
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
|
||||
|
||||
// rename
|
||||
boost::filesystem::remove(old_file); // probably does not exist
|
||||
if (boost::filesystem::exists(m_wallet_file)) {
|
||||
std::error_code e = tools::replace_file(m_wallet_file, old_file);
|
||||
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
|
||||
}
|
||||
std::error_code e = tools::replace_file(new_file, m_wallet_file);
|
||||
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
|
||||
boost::filesystem::remove(old_file);
|
||||
}
|
||||
|
||||
void wallet2::store_to(const std::string &path, const std::string &password)
|
||||
{
|
||||
// TODO: merge it with wallet2::store() function
|
||||
|
||||
// check if we want to store to directory which doesn't exists yet
|
||||
boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
|
||||
|
||||
// if path is not exists, try to create it
|
||||
if (!parent_path.empty() && !boost::filesystem::exists(parent_path)) {
|
||||
boost::system::error_code ec;
|
||||
if (!boost::filesystem::create_directories(parent_path, ec)) {
|
||||
throw std::logic_error(ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::stringstream oss;
|
||||
boost::archive::binary_oarchive ar(oss);
|
||||
ar << *this;
|
||||
|
||||
wallet2::cache_file_data cache_file_data = boost::value_initialized<wallet2::cache_file_data>();
|
||||
cache_file_data.cache_data = oss.str();
|
||||
crypto::chacha8_key key;
|
||||
generate_chacha8_key_from_secret_keys(key);
|
||||
std::string cipher;
|
||||
cipher.resize(cache_file_data.cache_data.size());
|
||||
cache_file_data.iv = crypto::rand<crypto::chacha8_iv>();
|
||||
crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]);
|
||||
cache_file_data.cache_data = cipher;
|
||||
|
||||
|
||||
const std::string new_file = path;
|
||||
const std::string old_file = m_wallet_file;
|
||||
const std::string old_keys_file = m_keys_file;
|
||||
const std::string old_address_file = m_wallet_file + ".address.txt";
|
||||
|
||||
// save to new file
|
||||
std::ofstream ostr;
|
||||
ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
|
||||
binary_archive<true> oar(ostr);
|
||||
bool success = ::serialization::serialize(oar, cache_file_data);
|
||||
ostr.close();
|
||||
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
|
||||
|
||||
// save keys to the new file
|
||||
// if we here, main wallet file is saved and we only need to save keys and address files
|
||||
// save keys to the new file
|
||||
// if we here, main wallet file is saved and we only need to save keys and address files
|
||||
if (!same_file) {
|
||||
prepare_file_names(path);
|
||||
store_keys(m_keys_file, password, false);
|
||||
|
||||
// save address to the new file
|
||||
const std::string address_file = m_wallet_file + ".address.txt";
|
||||
bool r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet));
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
|
||||
|
||||
|
||||
// remove old wallet file
|
||||
r = boost::filesystem::remove(old_file);
|
||||
if (!r) {
|
||||
LOG_ERROR("error removing file: " << old_file);
|
||||
LOG_ERROR("error removing file: " << old_file);
|
||||
}
|
||||
// remove old keys file
|
||||
r = boost::filesystem::remove(old_keys_file);
|
||||
if (!r) {
|
||||
LOG_ERROR("error removing file: " << old_keys_file);
|
||||
LOG_ERROR("error removing file: " << old_keys_file);
|
||||
}
|
||||
// remove old address file
|
||||
r = boost::filesystem::remove(old_address_file);
|
||||
if (!r) {
|
||||
LOG_ERROR("error removing file: " << old_address_file);
|
||||
LOG_ERROR("error removing file: " << old_address_file);
|
||||
}
|
||||
} else {
|
||||
// here we have "*.new" file, we need to rename it to be without ".new"
|
||||
std::error_code e = tools::replace_file(new_file, m_wallet_file);
|
||||
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::unlocked_balance() const
|
||||
|
@ -3072,12 +3056,17 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) c
|
|||
|
||||
std::string wallet2::get_wallet_file() const
|
||||
{
|
||||
return m_wallet_file;
|
||||
return m_wallet_file;
|
||||
}
|
||||
|
||||
std::string wallet2::get_keys_file() const
|
||||
{
|
||||
return m_keys_file;
|
||||
return m_keys_file;
|
||||
}
|
||||
|
||||
std::string wallet2::get_daemon_address() const
|
||||
{
|
||||
return m_daemon_address;
|
||||
}
|
||||
|
||||
void wallet2::set_tx_note(const crypto::hash &txid, const std::string ¬e)
|
||||
|
@ -3092,7 +3081,6 @@ std::string wallet2::get_tx_note(const crypto::hash &txid) const
|
|||
return std::string();
|
||||
return i->second;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::generate_genesis(cryptonote::block& b) {
|
||||
if (m_testnet)
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace tools
|
|||
virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) {}
|
||||
virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) {}
|
||||
virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) {}
|
||||
virtual ~i_wallet2_callback() {}
|
||||
};
|
||||
|
||||
struct tx_dust_policy
|
||||
|
@ -373,6 +374,7 @@ namespace tools
|
|||
|
||||
std::string get_wallet_file() const;
|
||||
std::string get_keys_file() const;
|
||||
std::string get_daemon_address() const;
|
||||
|
||||
std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon);
|
||||
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f);
|
||||
|
|
|
@ -1,346 +0,0 @@
|
|||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "wallet2_api.h"
|
||||
#include "wallet2.h"
|
||||
#include "mnemonics/electrum-words.h"
|
||||
#include <memory>
|
||||
|
||||
namespace epee {
|
||||
unsigned int g_test_dbg_lock_sleep = 0;
|
||||
}
|
||||
|
||||
namespace Bitmonero {
|
||||
|
||||
struct WalletManagerImpl;
|
||||
|
||||
namespace {
|
||||
static WalletManagerImpl * g_walletManager = nullptr;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Wallet::~Wallet() {}
|
||||
|
||||
///////////////////////// Wallet implementation ////////////////////////////////
|
||||
class WalletImpl : public Wallet
|
||||
{
|
||||
public:
|
||||
WalletImpl();
|
||||
~WalletImpl();
|
||||
bool create(const std::string &path, const std::string &password,
|
||||
const std::string &language);
|
||||
bool open(const std::string &path, const std::string &password);
|
||||
bool recover(const std::string &path, const std::string &seed);
|
||||
bool close();
|
||||
std::string seed() const;
|
||||
std::string getSeedLanguage() const;
|
||||
void setSeedLanguage(const std::string &arg);
|
||||
void setListener(Listener *) {}
|
||||
int status() const;
|
||||
std::string errorString() const;
|
||||
bool setPassword(const std::string &password);
|
||||
std::string address() const;
|
||||
bool store(const std::string &path);
|
||||
|
||||
private:
|
||||
void clearStatus();
|
||||
|
||||
private:
|
||||
//std::unique_ptr<tools::wallet2> m_wallet;
|
||||
tools::wallet2 * m_wallet;
|
||||
int m_status;
|
||||
std::string m_errorString;
|
||||
std::string m_password;
|
||||
};
|
||||
|
||||
WalletImpl::WalletImpl()
|
||||
:m_wallet(nullptr), m_status(Wallet::Status_Ok)
|
||||
{
|
||||
m_wallet = new tools::wallet2();
|
||||
}
|
||||
|
||||
WalletImpl::~WalletImpl()
|
||||
{
|
||||
delete m_wallet;
|
||||
}
|
||||
|
||||
bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language)
|
||||
{
|
||||
|
||||
clearStatus();
|
||||
|
||||
bool keys_file_exists;
|
||||
bool wallet_file_exists;
|
||||
tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists);
|
||||
// TODO: figure out how to setup logger;
|
||||
LOG_PRINT_L3("wallet_path: " << path << "");
|
||||
LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha
|
||||
<< " wallet_file_exists: " << std::boolalpha << wallet_file_exists << std::noboolalpha);
|
||||
|
||||
|
||||
// add logic to error out if new wallet requested but named wallet file exists
|
||||
if (keys_file_exists || wallet_file_exists) {
|
||||
m_errorString = "attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting.";
|
||||
LOG_ERROR(m_errorString);
|
||||
m_status = Status_Error;
|
||||
return false;
|
||||
}
|
||||
// TODO: validate language
|
||||
m_wallet->set_seed_language(language);
|
||||
crypto::secret_key recovery_val, secret_key;
|
||||
try {
|
||||
recovery_val = m_wallet->generate(path, password, secret_key, false, false);
|
||||
m_password = password;
|
||||
m_status = Status_Ok;
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR("Error creating wallet: " << e.what());
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WalletImpl::open(const std::string &path, const std::string &password)
|
||||
{
|
||||
clearStatus();
|
||||
try {
|
||||
// TODO: handle "deprecated"
|
||||
m_wallet->load(path, password);
|
||||
|
||||
m_password = password;
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR("Error opening wallet: " << e.what());
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
bool WalletImpl::recover(const std::string &path, const std::string &seed)
|
||||
{
|
||||
clearStatus();
|
||||
m_errorString.clear();
|
||||
if (seed.empty()) {
|
||||
m_errorString = "Electrum seed is empty";
|
||||
LOG_ERROR(m_errorString);
|
||||
m_status = Status_Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::secret_key recovery_key;
|
||||
std::string old_language;
|
||||
if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) {
|
||||
m_errorString = "Electrum-style word list failed verification";
|
||||
m_status = Status_Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
m_wallet->set_seed_language(old_language);
|
||||
m_wallet->generate(path, "", recovery_key, true, false);
|
||||
// TODO: wallet->init(daemon_address);
|
||||
} catch (const std::exception &e) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
bool WalletImpl::close()
|
||||
{
|
||||
clearStatus();
|
||||
bool result = false;
|
||||
try {
|
||||
m_wallet->store();
|
||||
m_wallet->stop();
|
||||
result = true;
|
||||
} catch (const std::exception &e) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
LOG_ERROR("Error closing wallet: " << e.what());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string WalletImpl::seed() const
|
||||
{
|
||||
std::string seed;
|
||||
if (m_wallet)
|
||||
m_wallet->get_seed(seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
std::string WalletImpl::getSeedLanguage() const
|
||||
{
|
||||
return m_wallet->get_seed_language();
|
||||
}
|
||||
|
||||
void WalletImpl::setSeedLanguage(const std::string &arg)
|
||||
{
|
||||
m_wallet->set_seed_language(arg);
|
||||
}
|
||||
|
||||
int WalletImpl::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
std::string WalletImpl::errorString() const
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
bool WalletImpl::setPassword(const std::string &password)
|
||||
{
|
||||
clearStatus();
|
||||
try {
|
||||
m_wallet->rewrite(m_wallet->get_wallet_file(), password);
|
||||
m_password = password;
|
||||
} catch (const std::exception &e) {
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
std::string WalletImpl::address() const
|
||||
{
|
||||
return m_wallet->get_account().get_public_address_str(m_wallet->testnet());
|
||||
}
|
||||
|
||||
bool WalletImpl::store(const std::string &path)
|
||||
{
|
||||
clearStatus();
|
||||
try {
|
||||
if (path.empty()) {
|
||||
m_wallet->store();
|
||||
} else {
|
||||
m_wallet->store_to(path, m_password);
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR("Error storing wallet: " << e.what());
|
||||
m_status = Status_Error;
|
||||
m_errorString = e.what();
|
||||
}
|
||||
|
||||
return m_status == Status_Ok;
|
||||
}
|
||||
|
||||
void WalletImpl::clearStatus()
|
||||
{
|
||||
m_status = Status_Ok;
|
||||
m_errorString.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////// WalletManager implementation /////////////////////////
|
||||
class WalletManagerImpl : public WalletManager
|
||||
{
|
||||
public:
|
||||
Wallet * createWallet(const std::string &path, const std::string &password,
|
||||
const std::string &language);
|
||||
Wallet * openWallet(const std::string &path, const std::string &password);
|
||||
virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo);
|
||||
virtual bool closeWallet(Wallet *wallet);
|
||||
bool walletExists(const std::string &path);
|
||||
std::string errorString() const;
|
||||
|
||||
|
||||
private:
|
||||
WalletManagerImpl() {}
|
||||
friend struct WalletManagerFactory;
|
||||
|
||||
std::string m_errorString;
|
||||
};
|
||||
|
||||
Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password,
|
||||
const std::string &language)
|
||||
{
|
||||
WalletImpl * wallet = new WalletImpl();
|
||||
wallet->create(path, password, language);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password)
|
||||
{
|
||||
WalletImpl * wallet = new WalletImpl();
|
||||
wallet->open(path, password);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &memo)
|
||||
{
|
||||
WalletImpl * wallet = new WalletImpl();
|
||||
wallet->recover(path, memo);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
bool WalletManagerImpl::closeWallet(Wallet *wallet)
|
||||
{
|
||||
WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
|
||||
bool result = wallet_->close();
|
||||
if (!result) {
|
||||
m_errorString = wallet_->errorString();
|
||||
} else {
|
||||
delete wallet_;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WalletManagerImpl::walletExists(const std::string &path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string WalletManagerImpl::errorString() const
|
||||
{
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////// WalletManagerFactory implementation //////////////////////
|
||||
WalletManager *WalletManagerFactory::getWalletManager()
|
||||
{
|
||||
|
||||
if (!g_walletManager) {
|
||||
epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0);
|
||||
g_walletManager = new WalletManagerImpl();
|
||||
}
|
||||
|
||||
return g_walletManager;
|
||||
}
|
||||
|
||||
}
|
|
@ -32,10 +32,85 @@
|
|||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
|
||||
// Public interface for libwallet library
|
||||
namespace Bitmonero {
|
||||
|
||||
namespace Utils {
|
||||
bool isAddressLocal(const std::string &hostaddr);
|
||||
}
|
||||
/**
|
||||
* @brief Transaction-like interface for sending money
|
||||
*/
|
||||
struct PendingTransaction
|
||||
{
|
||||
enum Status {
|
||||
Status_Ok,
|
||||
Status_Error
|
||||
};
|
||||
virtual ~PendingTransaction() = 0;
|
||||
virtual int status() const = 0;
|
||||
virtual std::string errorString() const = 0;
|
||||
virtual bool commit() = 0;
|
||||
virtual uint64_t amount() const = 0;
|
||||
virtual uint64_t dust() const = 0;
|
||||
virtual uint64_t fee() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The TransactionInfo - interface for displaying transaction information
|
||||
*/
|
||||
struct TransactionInfo
|
||||
{
|
||||
enum Direction {
|
||||
Direction_In,
|
||||
Direction_Out
|
||||
};
|
||||
|
||||
struct Transfer {
|
||||
Transfer(uint64_t _amount, const std::string &address);
|
||||
const uint64_t amount;
|
||||
const std::string address;
|
||||
};
|
||||
|
||||
virtual ~TransactionInfo() = 0;
|
||||
virtual int direction() const = 0;
|
||||
virtual bool isPending() const = 0;
|
||||
virtual bool isFailed() const = 0;
|
||||
virtual uint64_t amount() const = 0;
|
||||
virtual uint64_t fee() const = 0;
|
||||
virtual uint64_t blockHeight() const = 0;
|
||||
//! transaction_id
|
||||
virtual std::string hash() const = 0;
|
||||
virtual std::time_t timestamp() const = 0;
|
||||
virtual std::string paymentId() const = 0;
|
||||
//! only applicable for output transactions
|
||||
virtual const std::vector<Transfer> & transfers() const = 0;
|
||||
};
|
||||
/**
|
||||
* @brief The TransactionHistory - interface for displaying transaction history
|
||||
*/
|
||||
struct TransactionHistory
|
||||
{
|
||||
virtual ~TransactionHistory() = 0;
|
||||
virtual int count() const = 0;
|
||||
virtual TransactionInfo * transaction(int index) const = 0;
|
||||
virtual TransactionInfo * transaction(const std::string &id) const = 0;
|
||||
virtual std::vector<TransactionInfo*> getAll() const = 0;
|
||||
virtual void refresh() = 0;
|
||||
};
|
||||
|
||||
|
||||
struct WalletListener
|
||||
{
|
||||
virtual ~WalletListener() = 0;
|
||||
virtual void moneySpent(const std::string &txId, uint64_t amount) = 0;
|
||||
virtual void moneyReceived(const std::string &txId, uint64_t amount) = 0;
|
||||
// TODO: on_skip_transaction;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Interface for wallet operations.
|
||||
|
@ -43,30 +118,93 @@ namespace Bitmonero {
|
|||
*/
|
||||
struct Wallet
|
||||
{
|
||||
// TODO define wallet interface (decide what needed from wallet2)
|
||||
|
||||
enum Status {
|
||||
Status_Ok,
|
||||
Status_Error
|
||||
};
|
||||
|
||||
struct Listener
|
||||
{
|
||||
// TODO
|
||||
};
|
||||
|
||||
virtual ~Wallet() = 0;
|
||||
virtual std::string seed() const = 0;
|
||||
virtual std::string getSeedLanguage() const = 0;
|
||||
virtual void setSeedLanguage(const std::string &arg) = 0;
|
||||
virtual void setListener(Listener * listener) = 0;
|
||||
//! returns wallet status (Status_Ok | Status_Error)
|
||||
virtual int status() const = 0;
|
||||
//! in case error status, returns error string
|
||||
virtual std::string errorString() const = 0;
|
||||
virtual bool setPassword(const std::string &password) = 0;
|
||||
virtual std::string address() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief integratedAddress - returns integrated address for current wallet address and given payment_id.
|
||||
* if passed "payment_id" param is an empty string or not-valid payment id string
|
||||
* (16 characters hexadecimal string) - random payment_id will be generated
|
||||
*
|
||||
* \param payment_id - 16 characters hexadecimal string or empty string if new random payment id needs to be
|
||||
* generated
|
||||
* \return - 106 characters string representing integrated address
|
||||
*/
|
||||
virtual std::string integratedAddress(const std::string &payment_id) const = 0;
|
||||
|
||||
/*!
|
||||
* \brief store - stores wallet to file.
|
||||
* \param path - main filename to store wallet to. additionally stores address file and keys file.
|
||||
* to store to the same file - just pass empty string;
|
||||
* \return
|
||||
*/
|
||||
virtual bool store(const std::string &path) = 0;
|
||||
/*!
|
||||
* \brief filename - returns wallet filename
|
||||
* \return
|
||||
*/
|
||||
virtual std::string filename() const = 0;
|
||||
/*!
|
||||
* \brief keysFilename - returns keys filename. usually this formed as "wallet_filename".keys
|
||||
* \return
|
||||
*/
|
||||
virtual std::string keysFilename() const = 0;
|
||||
|
||||
virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0;
|
||||
virtual bool connectToDaemon() = 0;
|
||||
virtual void setTrustedDaemon(bool arg) = 0;
|
||||
virtual bool trustedDaemon() const = 0;
|
||||
virtual uint64_t balance() const = 0;
|
||||
virtual uint64_t unlockedBalance() const = 0;
|
||||
|
||||
static std::string displayAmount(uint64_t amount);
|
||||
static uint64_t amountFromString(const std::string &amount);
|
||||
static uint64_t amountFromDouble(double amount);
|
||||
static std::string genPaymentId();
|
||||
|
||||
// TODO?
|
||||
// virtual uint64_t unlockedDustBalance() const = 0;
|
||||
virtual bool refresh() = 0;
|
||||
/*!
|
||||
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
|
||||
* \param dst_addr destination address as string
|
||||
* \param payment_id optional payment_id, can be empty string
|
||||
* \param amount amount
|
||||
* \param mixin_count mixin count. if 0 passed, wallet will use default value
|
||||
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
|
||||
* after object returned
|
||||
*/
|
||||
|
||||
virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
|
||||
uint64_t amount, uint32_t mixin_count) = 0;
|
||||
|
||||
virtual void disposeTransaction(PendingTransaction * t) = 0;
|
||||
virtual TransactionHistory * history() const = 0;
|
||||
virtual void setListener(WalletListener *) = 0;
|
||||
/*!
|
||||
* \brief defaultMixin - returns number of mixins used in transactions
|
||||
* \return
|
||||
*/
|
||||
virtual uint32_t defaultMixin() const = 0;
|
||||
/*!
|
||||
* \brief setDefaultMixin - setum number of mixins to be used for new transactions
|
||||
* \param arg
|
||||
*/
|
||||
virtual void setDefaultMixin(uint32_t arg) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -82,7 +220,7 @@ struct WalletManager
|
|||
* \param language Language to be used to generate electrum seed memo
|
||||
* \return Wallet instance (Wallet::status() needs to be called to check if created successfully)
|
||||
*/
|
||||
virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language) = 0;
|
||||
virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Opens existing wallet
|
||||
|
@ -90,7 +228,7 @@ struct WalletManager
|
|||
* \param password Password of wallet file
|
||||
* \return Wallet instance (Wallet::status() needs to be called to check if opened successfully)
|
||||
*/
|
||||
virtual Wallet * openWallet(const std::string &path, const std::string &password) = 0;
|
||||
virtual Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) = 0;
|
||||
|
||||
/*!
|
||||
* \brief recovers existing wallet using memo (electrum seed)
|
||||
|
@ -98,7 +236,7 @@ struct WalletManager
|
|||
* \param memo memo (25 words electrum seed)
|
||||
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
|
||||
*/
|
||||
virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo) = 0;
|
||||
virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet = false) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Closes wallet. In case operation succeded, wallet object deleted. in case operation failed, wallet object not deleted
|
||||
|
@ -107,9 +245,25 @@ struct WalletManager
|
|||
*/
|
||||
virtual bool closeWallet(Wallet *wallet) = 0;
|
||||
|
||||
//! checks if wallet with the given name already exists
|
||||
/*
|
||||
* ! checks if wallet with the given name already exists
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief TODO: delme walletExists - check if the given filename is the wallet
|
||||
* @param path - filename
|
||||
* @return
|
||||
*/
|
||||
virtual bool walletExists(const std::string &path) = 0;
|
||||
|
||||
/*!
|
||||
* \brief findWallets - searches for the wallet files by given path name recursively
|
||||
* \param path - starting point to search
|
||||
* \return - list of strings with found wallets (absolute paths);
|
||||
*/
|
||||
virtual std::vector<std::string> findWallets(const std::string &path) = 0;
|
||||
|
||||
//! returns verbose error string regarding last error;
|
||||
virtual std::string errorString() const = 0;
|
||||
|
||||
};
|
||||
|
|
|
@ -29,37 +29,116 @@
|
|||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "wallet/wallet2_api.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
|
||||
using namespace std;
|
||||
//unsigned int epee::g_test_dbg_lock_sleep = 0;
|
||||
|
||||
namespace Consts
|
||||
{
|
||||
|
||||
|
||||
// TODO: get rid of hardcoded paths
|
||||
|
||||
const char * WALLET_NAME = "testwallet";
|
||||
const char * WALLET_NAME_COPY = "testwallet_copy";
|
||||
const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test";
|
||||
const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test";
|
||||
const char * WALLET_PASS = "password";
|
||||
const char * WALLET_PASS2 = "password22";
|
||||
const char * WALLET_LANG = "English";
|
||||
|
||||
// change this according your environment
|
||||
|
||||
const std::string WALLETS_ROOT_DIR = "/home/mbg033/dev/monero/testnet/";
|
||||
|
||||
const std::string TESTNET_WALLET1_NAME = WALLETS_ROOT_DIR + "wallet_01.bin";
|
||||
const std::string TESTNET_WALLET2_NAME = WALLETS_ROOT_DIR + "wallet_02.bin";
|
||||
const std::string TESTNET_WALLET3_NAME = WALLETS_ROOT_DIR + "wallet_03.bin";
|
||||
const std::string TESTNET_WALLET4_NAME = WALLETS_ROOT_DIR + "wallet_04.bin";
|
||||
const std::string TESTNET_WALLET5_NAME = WALLETS_ROOT_DIR + "wallet_05.bin";
|
||||
const std::string TESTNET_WALLET6_NAME = WALLETS_ROOT_DIR + "wallet_06.bin";
|
||||
|
||||
const char * TESTNET_WALLET_PASS = "";
|
||||
|
||||
const std::string CURRENT_SRC_WALLET = TESTNET_WALLET1_NAME;
|
||||
const std::string CURRENT_DST_WALLET = TESTNET_WALLET6_NAME;
|
||||
|
||||
const char * TESTNET_DAEMON_ADDRESS = "localhost:38081";
|
||||
const uint64_t AMOUNT_10XMR = 10000000000000L;
|
||||
const uint64_t AMOUNT_5XMR = 5000000000000L;
|
||||
const uint64_t AMOUNT_1XMR = 1000000000000L;
|
||||
|
||||
const std::string PAYMENT_ID_EMPTY = "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
using namespace Consts;
|
||||
|
||||
struct Utils
|
||||
{
|
||||
static void deleteWallet(const std::string & walletname)
|
||||
{
|
||||
std::cout << "** deleting wallet: " << walletname << std::endl;
|
||||
boost::filesystem::remove(walletname);
|
||||
boost::filesystem::remove(walletname + ".address.txt");
|
||||
boost::filesystem::remove(walletname + ".keys");
|
||||
}
|
||||
|
||||
static void deleteDir(const std::string &path)
|
||||
{
|
||||
std::cout << "** removing dir recursively: " << path << std::endl;
|
||||
boost::filesystem::remove_all(path);
|
||||
}
|
||||
|
||||
static void print_transaction(Bitmonero::TransactionInfo * t)
|
||||
{
|
||||
|
||||
std::cout << "d: "
|
||||
<< (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out")
|
||||
<< ", pe: " << (t->isPending() ? "true" : "false")
|
||||
<< ", bh: " << t->blockHeight()
|
||||
<< ", a: " << Bitmonero::Wallet::displayAmount(t->amount())
|
||||
<< ", f: " << Bitmonero::Wallet::displayAmount(t->fee())
|
||||
<< ", h: " << t->hash()
|
||||
<< ", pid: " << t->paymentId()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
static std::string get_wallet_address(const std::string &filename, const std::string &password)
|
||||
{
|
||||
Bitmonero::WalletManager *wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
|
||||
Bitmonero::Wallet * w = wmgr->openWallet(filename, password, true);
|
||||
std::string result = w->address();
|
||||
wmgr->closeWallet(w);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct WalletManagerTest : public testing::Test
|
||||
{
|
||||
Bitmonero::WalletManager * wmgr;
|
||||
|
||||
const char * WALLET_NAME = "testwallet";
|
||||
const char * WALLET_NAME_COPY = "testwallet_copy";
|
||||
const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test";
|
||||
const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test";
|
||||
const char * WALLET_PASS = "password";
|
||||
const char * WALLET_PASS2 = "password22";
|
||||
const char * WALLET_LANG = "English";
|
||||
|
||||
WalletManagerTest()
|
||||
{
|
||||
std::cout << __FUNCTION__ << std::endl;
|
||||
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
|
||||
deleteWallet(WALLET_NAME);
|
||||
deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
|
||||
Utils::deleteWallet(WALLET_NAME);
|
||||
Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,21 +148,32 @@ struct WalletManagerTest : public testing::Test
|
|||
//deleteWallet(WALLET_NAME);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void deleteWallet(const std::string & walletname)
|
||||
|
||||
struct WalletTest1 : public testing::Test
|
||||
{
|
||||
Bitmonero::WalletManager * wmgr;
|
||||
|
||||
WalletTest1()
|
||||
{
|
||||
std::cout << "** deleting wallet: " << walletname << std::endl;
|
||||
boost::filesystem::remove(walletname);
|
||||
boost::filesystem::remove(walletname + ".address.txt");
|
||||
boost::filesystem::remove(walletname + ".keys");
|
||||
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
|
||||
}
|
||||
|
||||
void deleteDir(const std::string &path)
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct WalletTest2 : public testing::Test
|
||||
{
|
||||
Bitmonero::WalletManager * wmgr;
|
||||
|
||||
WalletTest2()
|
||||
{
|
||||
std::cout << "** removing dir recursively: " << path << std::endl;
|
||||
boost::filesystem::remove_all(path);
|
||||
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -116,7 +206,36 @@ TEST_F(WalletManagerTest, WalletManagerOpensWallet)
|
|||
std::cout << "** seed: " << wallet2->seed() << std::endl;
|
||||
}
|
||||
|
||||
TEST_F(WalletManagerTest, WalletManagerStoresWallet)
|
||||
{
|
||||
|
||||
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
||||
std::string seed1 = wallet1->seed();
|
||||
wallet1->store("");
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
|
||||
ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
|
||||
ASSERT_TRUE(wallet2->seed() == seed1);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WalletManagerTest, WalletManagerMovesWallet)
|
||||
{
|
||||
|
||||
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
||||
std::string WALLET_NAME_MOVED = std::string("/tmp/") + WALLET_NAME + ".moved";
|
||||
std::string seed1 = wallet1->seed();
|
||||
ASSERT_TRUE(wallet1->store(WALLET_NAME_MOVED));
|
||||
|
||||
Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_MOVED, WALLET_PASS);
|
||||
ASSERT_TRUE(wallet2->filename() == WALLET_NAME_MOVED);
|
||||
ASSERT_TRUE(wallet2->keysFilename() == WALLET_NAME_MOVED + ".keys");
|
||||
ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
|
||||
ASSERT_TRUE(wallet2->seed() == seed1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
TEST_F(WalletManagerTest, WalletManagerChangesPassword)
|
||||
{
|
||||
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
||||
|
@ -124,7 +243,7 @@ TEST_F(WalletManagerTest, WalletManagerChangesPassword)
|
|||
ASSERT_TRUE(wallet1->setPassword(WALLET_PASS2));
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2);
|
||||
ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
|
||||
ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);quint64
|
||||
ASSERT_TRUE(wallet2->seed() == seed1);
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet2));
|
||||
Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
|
||||
|
@ -140,7 +259,7 @@ TEST_F(WalletManagerTest, WalletManagerRecoversWallet)
|
|||
std::string address1 = wallet1->address();
|
||||
ASSERT_FALSE(address1.empty());
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
deleteWallet(WALLET_NAME);
|
||||
Utils::deleteWallet(WALLET_NAME);
|
||||
Bitmonero::Wallet * wallet2 = wmgr->recoveryWallet(WALLET_NAME, seed1);
|
||||
ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
|
||||
ASSERT_TRUE(wallet2->seed() == seed1);
|
||||
|
@ -165,6 +284,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet1)
|
|||
ASSERT_TRUE(wmgr->closeWallet(wallet2));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
|
||||
{
|
||||
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
||||
|
@ -203,10 +323,363 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3)
|
|||
|
||||
}
|
||||
|
||||
TEST_F(WalletManagerTest, WalletManagerStoresWallet4)
|
||||
{
|
||||
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
||||
std::string seed1 = wallet1->seed();
|
||||
std::string address1 = wallet1->address();
|
||||
|
||||
ASSERT_TRUE(wallet1->store(""));
|
||||
ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
|
||||
|
||||
ASSERT_TRUE(wallet1->store(""));
|
||||
ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
|
||||
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
|
||||
wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
|
||||
ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
|
||||
ASSERT_TRUE(wallet1->seed() == seed1);
|
||||
ASSERT_TRUE(wallet1->address() == address1);
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
}
|
||||
*/
|
||||
|
||||
TEST_F(WalletManagerTest, WalletManagerFindsWallet)
|
||||
{
|
||||
std::vector<std::string> wallets = wmgr->findWallets(WALLETS_ROOT_DIR);
|
||||
ASSERT_FALSE(wallets.empty());
|
||||
std::cout << "Found wallets: " << std::endl;
|
||||
for (auto wallet_path: wallets) {
|
||||
std::cout << wallet_path << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WalletManagerTest, WalletGeneratesPaymentId)
|
||||
{
|
||||
std::string payment_id = Bitmonero::Wallet::genPaymentId();
|
||||
ASSERT_TRUE(payment_id.length() == 16);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WalletManagerTest, WalletGeneratesIntegratedAddress)
|
||||
{
|
||||
std::string payment_id = Bitmonero::Wallet::genPaymentId();
|
||||
|
||||
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
std::string integrated_address = wallet1->integratedAddress(payment_id);
|
||||
ASSERT_TRUE(integrated_address.length() == 106);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WalletTest1, WalletShowsBalance)
|
||||
{
|
||||
// TODO: temporary disabled;
|
||||
return;
|
||||
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
ASSERT_TRUE(wallet1->balance() > 0);
|
||||
ASSERT_TRUE(wallet1->unlockedBalance() > 0);
|
||||
|
||||
uint64_t balance1 = wallet1->balance();
|
||||
uint64_t unlockedBalance1 = wallet1->unlockedBalance();
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
Bitmonero::Wallet * wallet2 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
|
||||
ASSERT_TRUE(balance1 == wallet2->balance());
|
||||
std::cout << "wallet balance: " << wallet2->balance() << std::endl;
|
||||
ASSERT_TRUE(unlockedBalance1 == wallet2->unlockedBalance());
|
||||
std::cout << "wallet unlocked balance: " << wallet2->unlockedBalance() << std::endl;
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet2));
|
||||
}
|
||||
|
||||
TEST_F(WalletTest1, WalletRefresh)
|
||||
{
|
||||
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
// make sure testnet daemon is running
|
||||
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet1->refresh());
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WalletTest1, WalletConvertsToString)
|
||||
{
|
||||
std::string strAmount = Bitmonero::Wallet::displayAmount(AMOUNT_5XMR);
|
||||
ASSERT_TRUE(AMOUNT_5XMR == Bitmonero::Wallet::amountFromString(strAmount));
|
||||
|
||||
ASSERT_TRUE(AMOUNT_5XMR == Bitmonero::Wallet::amountFromDouble(5.0));
|
||||
ASSERT_TRUE(AMOUNT_10XMR == Bitmonero::Wallet::amountFromDouble(10.0));
|
||||
ASSERT_TRUE(AMOUNT_1XMR == Bitmonero::Wallet::amountFromDouble(1.0));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
TEST_F(WalletTest1, WalletTransaction)
|
||||
{
|
||||
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
// make sure testnet daemon is running
|
||||
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet1->refresh());
|
||||
uint64_t balance = wallet1->balance();
|
||||
ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||
|
||||
std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
|
||||
wallet1->setDefaultMixin(1);
|
||||
ASSERT_TRUE(wallet1->defaultMixin() == 1);
|
||||
|
||||
Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(
|
||||
recepient_address, AMOUNT_10XMR);
|
||||
ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||
wallet1->refresh();
|
||||
|
||||
ASSERT_TRUE(wallet1->balance() == balance);
|
||||
ASSERT_TRUE(transaction->amount() == AMOUNT_10XMR);
|
||||
ASSERT_TRUE(transaction->commit());
|
||||
ASSERT_FALSE(wallet1->balance() == balance);
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
}
|
||||
*/
|
||||
|
||||
TEST_F(WalletTest1, WalletTransactionWithMixin)
|
||||
{
|
||||
|
||||
std::vector<int> mixins;
|
||||
// 2,3,4,5,6,7,8,9,10,15,20,25 can we do it like that?
|
||||
mixins.push_back(2); mixins.push_back(3); mixins.push_back(4); mixins.push_back(5); mixins.push_back(6);
|
||||
mixins.push_back(7); mixins.push_back(8); mixins.push_back(9); mixins.push_back(10); mixins.push_back(15);
|
||||
mixins.push_back(20); mixins.push_back(25);
|
||||
|
||||
|
||||
std::string payment_id = "";
|
||||
|
||||
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
|
||||
|
||||
// make sure testnet daemon is running
|
||||
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet1->refresh());
|
||||
uint64_t balance = wallet1->balance();
|
||||
ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||
|
||||
std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
|
||||
for (auto mixin : mixins) {
|
||||
std::cerr << "Transaction mixin count: " << mixin << std::endl;
|
||||
Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(
|
||||
recepient_address, payment_id, AMOUNT_5XMR, mixin);
|
||||
|
||||
std::cerr << "Transaction status: " << transaction->status() << std::endl;
|
||||
std::cerr << "Transaction fee: " << Bitmonero::Wallet::displayAmount(transaction->fee()) << std::endl;
|
||||
std::cerr << "Transaction error: " << transaction->errorString() << std::endl;
|
||||
ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||
wallet1->disposeTransaction(transaction);
|
||||
}
|
||||
|
||||
wallet1->refresh();
|
||||
|
||||
ASSERT_TRUE(wallet1->balance() == balance);
|
||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||
}
|
||||
|
||||
TEST_F(WalletTest1, WalletHistory)
|
||||
{
|
||||
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
// make sure testnet daemon is running
|
||||
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet1->refresh());
|
||||
Bitmonero::TransactionHistory * history = wallet1->history();
|
||||
history->refresh();
|
||||
ASSERT_TRUE(history->count() > 0);
|
||||
|
||||
|
||||
for (auto t: history->getAll()) {
|
||||
ASSERT_TRUE(t != nullptr);
|
||||
Utils::print_transaction(t);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(WalletTest1, WalletTransactionAndHistory)
|
||||
{
|
||||
return;
|
||||
Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
// make sure testnet daemon is running
|
||||
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet_src->refresh());
|
||||
Bitmonero::TransactionHistory * history = wallet_src->history();
|
||||
history->refresh();
|
||||
ASSERT_TRUE(history->count() > 0);
|
||||
size_t count1 = history->count();
|
||||
|
||||
std::cout << "**** Transactions before transfer (" << count1 << ")" << std::endl;
|
||||
for (auto t: history->getAll()) {
|
||||
ASSERT_TRUE(t != nullptr);
|
||||
Utils::print_transaction(t);
|
||||
}
|
||||
|
||||
std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
|
||||
|
||||
|
||||
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr,
|
||||
PAYMENT_ID_EMPTY,
|
||||
AMOUNT_10XMR * 5, 0);
|
||||
|
||||
ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||
ASSERT_TRUE(tx->commit());
|
||||
history = wallet_src->history();
|
||||
history->refresh();
|
||||
ASSERT_TRUE(count1 != history->count());
|
||||
|
||||
std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl;
|
||||
for (auto t: history->getAll()) {
|
||||
ASSERT_TRUE(t != nullptr);
|
||||
Utils::print_transaction(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WalletTest1, WalletTransactionWithPaymentId)
|
||||
{
|
||||
|
||||
Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||
// make sure testnet daemon is running
|
||||
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet_src->refresh());
|
||||
Bitmonero::TransactionHistory * history = wallet_src->history();
|
||||
history->refresh();
|
||||
ASSERT_TRUE(history->count() > 0);
|
||||
size_t count1 = history->count();
|
||||
|
||||
std::cout << "**** Transactions before transfer (" << count1 << ")" << std::endl;
|
||||
for (auto t: history->getAll()) {
|
||||
ASSERT_TRUE(t != nullptr);
|
||||
Utils::print_transaction(t);
|
||||
}
|
||||
|
||||
std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
|
||||
|
||||
std::string payment_id = Bitmonero::Wallet::genPaymentId();
|
||||
ASSERT_TRUE(payment_id.length() == 16);
|
||||
|
||||
|
||||
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr,
|
||||
payment_id,
|
||||
AMOUNT_1XMR, 1);
|
||||
|
||||
ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||
ASSERT_TRUE(tx->commit());
|
||||
history = wallet_src->history();
|
||||
history->refresh();
|
||||
ASSERT_TRUE(count1 != history->count());
|
||||
|
||||
bool payment_id_in_history = false;
|
||||
|
||||
std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl;
|
||||
for (auto t: history->getAll()) {
|
||||
ASSERT_TRUE(t != nullptr);
|
||||
Utils::print_transaction(t);
|
||||
if (t->paymentId() == payment_id) {
|
||||
payment_id_in_history = true;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(payment_id_in_history);
|
||||
}
|
||||
|
||||
struct MyWalletListener : public Bitmonero::WalletListener
|
||||
{
|
||||
|
||||
Bitmonero::Wallet * wallet;
|
||||
uint64_t total_tx;
|
||||
uint64_t total_rx;
|
||||
std::timed_mutex guard;
|
||||
|
||||
MyWalletListener(Bitmonero::Wallet * wallet)
|
||||
: total_tx(0), total_rx(0)
|
||||
{
|
||||
this->wallet = wallet;
|
||||
this->wallet->setListener(this);
|
||||
}
|
||||
|
||||
virtual void moneySpent(const string &txId, uint64_t amount)
|
||||
{
|
||||
std::cout << "wallet: " << wallet->address() << " just spent money ("
|
||||
<< txId << ", " << wallet->displayAmount(amount) << ")" << std::endl;
|
||||
total_tx += amount;
|
||||
guard.unlock();
|
||||
}
|
||||
|
||||
virtual void moneyReceived(const string &txId, uint64_t amount)
|
||||
{
|
||||
std::cout << "wallet: " << wallet->address() << " just received money ("
|
||||
<< txId << ", " << wallet->displayAmount(amount) << ")" << std::endl;
|
||||
total_rx += amount;
|
||||
guard.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
TEST_F(WalletTest2, WalletCallbackSent)
|
||||
{
|
||||
|
||||
Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true);
|
||||
// make sure testnet daemon is running
|
||||
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet_src->refresh());
|
||||
MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
|
||||
std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl;
|
||||
|
||||
|
||||
uint64_t amount = AMOUNT_10XMR * 5;
|
||||
std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS;
|
||||
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5);
|
||||
ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||
ASSERT_TRUE(tx->commit());
|
||||
|
||||
std::chrono::seconds wait_for = std::chrono::seconds(60*3);
|
||||
|
||||
wallet_src_listener->guard.lock();
|
||||
wallet_src_listener->guard.try_lock_for(wait_for);
|
||||
|
||||
ASSERT_TRUE(wallet_src_listener->total_tx != 0);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
TEST_F(WalletTest2, WalletCallbackReceived)
|
||||
{
|
||||
|
||||
Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true);
|
||||
// make sure testnet daemon is running
|
||||
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet_src->refresh());
|
||||
std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl;
|
||||
|
||||
Bitmonero::Wallet * wallet_dst = wmgr->openWallet(TESTNET_WALLET4_NAME, TESTNET_WALLET_PASS, true);
|
||||
ASSERT_TRUE(wallet_dst->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||
ASSERT_TRUE(wallet_dst->refresh());
|
||||
MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst);
|
||||
|
||||
|
||||
uint64_t amount = AMOUNT_1XMR * 5;
|
||||
std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS;
|
||||
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5);
|
||||
ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||
ASSERT_TRUE(tx->commit());
|
||||
|
||||
std::chrono::seconds wait_for = std::chrono::seconds(60*4);
|
||||
|
||||
wallet_dst_listener->guard.lock();
|
||||
wallet_dst_listener->guard.try_lock_for(wait_for);
|
||||
|
||||
ASSERT_TRUE(wallet_dst_listener->total_tx != 0);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
//epee::debug::get_set_enable_assert(true, false);
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
|
||||
function create_wallet {
|
||||
wallet_name=$1
|
||||
echo 0 | simplewallet --testnet --trusted-daemon --daemon-address localhost:38081 --generate-new-wallet $wallet_name --password "" --restore-height=1
|
||||
}
|
||||
|
||||
|
||||
|
||||
create_wallet wallet_01.bin
|
||||
create_wallet wallet_02.bin
|
||||
create_wallet wallet_03.bin
|
||||
create_wallet wallet_04.bin
|
||||
create_wallet wallet_05.bin
|
||||
create_wallet wallet_06.bin
|
||||
|
||||
|
||||
#create_wallet wallet_m
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_m.log start_mining
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_miner.log stop_mining
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
rlwrap simplewallet --wallet-file wallet_01.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_01.log
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
rlwrap simplewallet --wallet-file wallet_02.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_01.log
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
rlwrap simplewallet --wallet-file wallet_03.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_03.log
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
rlwrap simplewallet --wallet-file wallet_04.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_04.log
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
rlwrap simplewallet --wallet-file wallet_05.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_05.log
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address 127.0.0.1:38081 --log-file wallet_m.log
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
|
||||
function send_funds {
|
||||
local amount=$1
|
||||
local dest=$(cat "$2.address.txt")
|
||||
|
||||
simplewallet --wallet-file wallet_m --password "" \
|
||||
--testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_m.log \
|
||||
--command transfer $dest $amount
|
||||
}
|
||||
|
||||
|
||||
send_funds 100 wallet_01.bin
|
||||
send_funds 100 wallet_02.bin
|
||||
send_funds 100 wallet_03.bin
|
||||
send_funds 100 wallet_04.bin
|
||||
send_funds 100 wallet_05.bin
|
||||
send_funds 100 wallet_06.bin
|
||||
|
||||
|
Loading…
Reference in New Issue