commit
a1736a9429
|
@ -86,8 +86,8 @@ namespace cryptonote
|
||||||
// whether they can talk to a given daemon without having to know in
|
// whether they can talk to a given daemon without having to know in
|
||||||
// advance which version they will stop working with
|
// advance which version they will stop working with
|
||||||
// Don't go over 32767 for any of these
|
// Don't go over 32767 for any of these
|
||||||
#define CORE_RPC_VERSION_MAJOR 2
|
#define CORE_RPC_VERSION_MAJOR 3
|
||||||
#define CORE_RPC_VERSION_MINOR 10
|
#define CORE_RPC_VERSION_MINOR 0
|
||||||
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
|
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
|
||||||
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
|
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
|
||||||
|
|
||||||
|
@ -1516,7 +1516,7 @@ namespace cryptonote
|
||||||
KV_SERIALIZE(num_10m)
|
KV_SERIALIZE(num_10m)
|
||||||
KV_SERIALIZE(num_not_relayed)
|
KV_SERIALIZE(num_not_relayed)
|
||||||
KV_SERIALIZE(histo_98pc)
|
KV_SERIALIZE(histo_98pc)
|
||||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(histo)
|
KV_SERIALIZE(histo)
|
||||||
KV_SERIALIZE(num_double_spends)
|
KV_SERIALIZE(num_double_spends)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
|
|
|
@ -3080,6 +3080,21 @@ bool wallet2::add_address_book_row(const cryptonote::account_public_address &add
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wallet2::set_address_book_row(size_t row_id, const cryptonote::account_public_address &address, const crypto::hash &payment_id, const std::string &description, bool is_subaddress)
|
||||||
|
{
|
||||||
|
wallet2::address_book_row a;
|
||||||
|
a.m_address = address;
|
||||||
|
a.m_payment_id = payment_id;
|
||||||
|
a.m_description = description;
|
||||||
|
a.m_is_subaddress = is_subaddress;
|
||||||
|
|
||||||
|
const auto size = m_address_book.size();
|
||||||
|
if (row_id >= size)
|
||||||
|
return false;
|
||||||
|
m_address_book[row_id] = a;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool wallet2::delete_address_book_row(std::size_t row_id) {
|
bool wallet2::delete_address_book_row(std::size_t row_id) {
|
||||||
if(m_address_book.size() <= row_id)
|
if(m_address_book.size() <= row_id)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1098,6 +1098,7 @@ private:
|
||||||
*/
|
*/
|
||||||
std::vector<address_book_row> get_address_book() const { return m_address_book; }
|
std::vector<address_book_row> get_address_book() const { return m_address_book; }
|
||||||
bool add_address_book_row(const cryptonote::account_public_address &address, const crypto::hash &payment_id, const std::string &description, bool is_subaddress);
|
bool add_address_book_row(const cryptonote::account_public_address &address, const crypto::hash &payment_id, const std::string &description, bool is_subaddress);
|
||||||
|
bool set_address_book_row(size_t row_id, const cryptonote::account_public_address &address, const crypto::hash &payment_id, const std::string &description, bool is_subaddress);
|
||||||
bool delete_address_book_row(std::size_t row_id);
|
bool delete_address_book_row(std::size_t row_id);
|
||||||
|
|
||||||
uint64_t get_num_rct_outputs();
|
uint64_t get_num_rct_outputs();
|
||||||
|
|
|
@ -2824,6 +2824,108 @@ namespace tools
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool wallet_rpc_server::on_edit_address_book(const wallet_rpc::COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||||
|
{
|
||||||
|
if (!m_wallet) return not_open(er);
|
||||||
|
if (m_restricted)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_DENIED;
|
||||||
|
er.message = "Command unavailable in restricted mode.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ab = m_wallet->get_address_book();
|
||||||
|
if (req.index >= ab.size())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_WRONG_INDEX;
|
||||||
|
er.message = "Index out of range: " + std::to_string(req.index);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tools::wallet2::address_book_row entry = ab[req.index];
|
||||||
|
|
||||||
|
cryptonote::address_parse_info info;
|
||||||
|
crypto::hash payment_id = crypto::null_hash;
|
||||||
|
if (req.set_address)
|
||||||
|
{
|
||||||
|
er.message = "";
|
||||||
|
if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), req.address,
|
||||||
|
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
|
||||||
|
if (!dnssec_valid)
|
||||||
|
{
|
||||||
|
er.message = std::string("Invalid DNSSEC for ") + url;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (addresses.empty())
|
||||||
|
{
|
||||||
|
er.message = std::string("No Monero address found at ") + url;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return addresses[0];
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
|
||||||
|
if (er.message.empty())
|
||||||
|
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entry.m_address = info.address;
|
||||||
|
entry.m_is_subaddress = info.is_subaddress;
|
||||||
|
if (info.has_payment_id)
|
||||||
|
{
|
||||||
|
memcpy(entry.m_payment_id.data, info.payment_id.data, 8);
|
||||||
|
memset(entry.m_payment_id.data + 8, 0, 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.set_payment_id)
|
||||||
|
{
|
||||||
|
if (req.payment_id.empty())
|
||||||
|
{
|
||||||
|
payment_id = crypto::null_hash;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (req.set_address && info.has_payment_id)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
|
||||||
|
er.message = "Separate payment ID given with integrated address";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wallet2::parse_long_payment_id(req.payment_id, payment_id))
|
||||||
|
{
|
||||||
|
crypto::hash8 spid;
|
||||||
|
if (!wallet2::parse_short_payment_id(req.payment_id, spid))
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
|
||||||
|
er.message = "Payment id has invalid format: \"" + req.payment_id + "\", expected 64 character string";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
|
||||||
|
er.message = "Payment id has invalid format: standalone short payment IDs are forbidden, they must be part of an integrated address";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.m_payment_id = payment_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.set_description)
|
||||||
|
entry.m_description = req.description;
|
||||||
|
|
||||||
|
if (!m_wallet->set_address_book_row(req.index, entry.m_address, entry.m_payment_id, entry.m_description, entry.m_is_subaddress))
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||||
|
er.message = "Failed to edit address book entry";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::on_delete_address_book(const wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
bool wallet_rpc_server::on_delete_address_book(const wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||||
{
|
{
|
||||||
if (!m_wallet) return not_open(er);
|
if (!m_wallet) return not_open(er);
|
||||||
|
|
|
@ -127,6 +127,7 @@ namespace tools
|
||||||
MAP_JON_RPC_WE("parse_uri", on_parse_uri, wallet_rpc::COMMAND_RPC_PARSE_URI)
|
MAP_JON_RPC_WE("parse_uri", on_parse_uri, wallet_rpc::COMMAND_RPC_PARSE_URI)
|
||||||
MAP_JON_RPC_WE("get_address_book", on_get_address_book, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY)
|
MAP_JON_RPC_WE("get_address_book", on_get_address_book, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY)
|
||||||
MAP_JON_RPC_WE("add_address_book", on_add_address_book, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY)
|
MAP_JON_RPC_WE("add_address_book", on_add_address_book, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY)
|
||||||
|
MAP_JON_RPC_WE("edit_address_book", on_edit_address_book, wallet_rpc::COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY)
|
||||||
MAP_JON_RPC_WE("delete_address_book",on_delete_address_book,wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY)
|
MAP_JON_RPC_WE("delete_address_book",on_delete_address_book,wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY)
|
||||||
MAP_JON_RPC_WE("refresh", on_refresh, wallet_rpc::COMMAND_RPC_REFRESH)
|
MAP_JON_RPC_WE("refresh", on_refresh, wallet_rpc::COMMAND_RPC_REFRESH)
|
||||||
MAP_JON_RPC_WE("auto_refresh", on_auto_refresh, wallet_rpc::COMMAND_RPC_AUTO_REFRESH)
|
MAP_JON_RPC_WE("auto_refresh", on_auto_refresh, wallet_rpc::COMMAND_RPC_AUTO_REFRESH)
|
||||||
|
@ -212,6 +213,7 @@ namespace tools
|
||||||
bool on_parse_uri(const wallet_rpc::COMMAND_RPC_PARSE_URI::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
bool on_parse_uri(const wallet_rpc::COMMAND_RPC_PARSE_URI::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||||
bool on_get_address_book(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
bool on_get_address_book(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||||
bool on_add_address_book(const wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
bool on_add_address_book(const wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||||
|
bool on_edit_address_book(const wallet_rpc::COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||||
bool on_delete_address_book(const wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
bool on_delete_address_book(const wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||||
bool on_refresh(const wallet_rpc::COMMAND_RPC_REFRESH::request& req, wallet_rpc::COMMAND_RPC_REFRESH::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
bool on_refresh(const wallet_rpc::COMMAND_RPC_REFRESH::request& req, wallet_rpc::COMMAND_RPC_REFRESH::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||||
bool on_auto_refresh(const wallet_rpc::COMMAND_RPC_AUTO_REFRESH::request& req, wallet_rpc::COMMAND_RPC_AUTO_REFRESH::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
bool on_auto_refresh(const wallet_rpc::COMMAND_RPC_AUTO_REFRESH::request& req, wallet_rpc::COMMAND_RPC_AUTO_REFRESH::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
// advance which version they will stop working with
|
// advance which version they will stop working with
|
||||||
// Don't go over 32767 for any of these
|
// Don't go over 32767 for any of these
|
||||||
#define WALLET_RPC_VERSION_MAJOR 1
|
#define WALLET_RPC_VERSION_MAJOR 1
|
||||||
#define WALLET_RPC_VERSION_MINOR 15
|
#define WALLET_RPC_VERSION_MINOR 16
|
||||||
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
|
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
|
||||||
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
|
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
|
||||||
namespace tools
|
namespace tools
|
||||||
|
@ -1845,6 +1845,38 @@ namespace wallet_rpc
|
||||||
typedef epee::misc_utils::struct_init<response_t> response;
|
typedef epee::misc_utils::struct_init<response_t> response;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY
|
||||||
|
{
|
||||||
|
struct request_t
|
||||||
|
{
|
||||||
|
uint64_t index;
|
||||||
|
bool set_address;
|
||||||
|
std::string address;
|
||||||
|
bool set_payment_id;
|
||||||
|
std::string payment_id;
|
||||||
|
bool set_description;
|
||||||
|
std::string description;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(index)
|
||||||
|
KV_SERIALIZE(set_address)
|
||||||
|
KV_SERIALIZE(address)
|
||||||
|
KV_SERIALIZE(set_payment_id)
|
||||||
|
KV_SERIALIZE(payment_id)
|
||||||
|
KV_SERIALIZE(set_description)
|
||||||
|
KV_SERIALIZE(description)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
typedef epee::misc_utils::struct_init<request_t> request;
|
||||||
|
|
||||||
|
struct response_t
|
||||||
|
{
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
typedef epee::misc_utils::struct_init<response_t> response;
|
||||||
|
};
|
||||||
|
|
||||||
struct COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY
|
struct COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY
|
||||||
{
|
{
|
||||||
struct request_t
|
struct request_t
|
||||||
|
|
|
@ -59,3 +59,7 @@ else()
|
||||||
message(WARNING "functional_tests_rpc skipped, needs the 'requests' python module")
|
message(WARNING "functional_tests_rpc skipped, needs the 'requests' python module")
|
||||||
set(CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} functional_tests_rpc)
|
set(CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} functional_tests_rpc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME check_missing_rpc_methods
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/check_missing_rpc_methods.py" "${CMAKE_SOURCE_DIR}")
|
||||||
|
|
|
@ -0,0 +1,304 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#encoding=utf-8
|
||||||
|
|
||||||
|
# Copyright (c) 2019 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.
|
||||||
|
|
||||||
|
"""Test wallet address book RPC
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from framework.wallet import Wallet
|
||||||
|
|
||||||
|
class AddressBookTest():
|
||||||
|
def run_test(self):
|
||||||
|
self.create()
|
||||||
|
self.test_address_book()
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
print('Creating wallet')
|
||||||
|
wallet = Wallet()
|
||||||
|
# close the wallet if any, will throw if none is loaded
|
||||||
|
try: wallet.close_wallet()
|
||||||
|
except: pass
|
||||||
|
seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted'
|
||||||
|
res = wallet.restore_deterministic_wallet(seed = seed)
|
||||||
|
assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert res.seed == seed
|
||||||
|
|
||||||
|
def test_address_book(self):
|
||||||
|
print('Testing address book')
|
||||||
|
wallet = Wallet()
|
||||||
|
|
||||||
|
# empty at start
|
||||||
|
res = wallet.get_address_book()
|
||||||
|
assert not 'entries' in res or (res.entries) == 0
|
||||||
|
ok = False
|
||||||
|
try: wallet.get_address_book([0])
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: wallet.delete_address_book(0)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: wallet.edit_address_book(0, description = '')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
# add one
|
||||||
|
res = wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', description = 'self')
|
||||||
|
assert res.index == 0
|
||||||
|
for get_all in [True, False]:
|
||||||
|
res = wallet.get_address_book() if get_all else wallet.get_address_book([0])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
e = res.entries[0]
|
||||||
|
assert e.index == 0
|
||||||
|
assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert e.payment_id == '' or e.payment_id == '0' * 16 or e.payment_id == '0' * 64
|
||||||
|
assert e.description == 'self'
|
||||||
|
|
||||||
|
# add a duplicate
|
||||||
|
res = wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', description = 'self')
|
||||||
|
assert res.index == 1
|
||||||
|
res = wallet.get_address_book()
|
||||||
|
assert len(res.entries) == 2
|
||||||
|
assert res.entries[0].index == 0
|
||||||
|
assert res.entries[1].index == 1
|
||||||
|
assert res.entries[0].address == res.entries[1].address
|
||||||
|
assert res.entries[0].payment_id == res.entries[1].payment_id
|
||||||
|
assert res.entries[0].description == res.entries[1].description
|
||||||
|
e = res.entries[1]
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert e == res.entries[0]
|
||||||
|
|
||||||
|
# request (partially) out of range
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.get_address_book[4, 2]
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.get_address_book[0, 2]
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.get_address_book[2, 0]
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
# delete first
|
||||||
|
res = wallet.delete_address_book(0)
|
||||||
|
res = wallet.get_address_book()
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert res.entries[0].index == 0
|
||||||
|
assert res.entries[0].address == e.address
|
||||||
|
assert res.entries[0].payment_id == e.payment_id
|
||||||
|
assert res.entries[0].description == e.description
|
||||||
|
|
||||||
|
# delete (new) first
|
||||||
|
res = wallet.delete_address_book(0)
|
||||||
|
res = wallet.get_address_book()
|
||||||
|
assert not 'entries' in res or (res.entries) == 0
|
||||||
|
|
||||||
|
# add non-addresses
|
||||||
|
errors = 0
|
||||||
|
try: wallet.add_address_book('', description = 'bad')
|
||||||
|
except: errors += 1
|
||||||
|
try: wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm ', description = 'bad')
|
||||||
|
except: errors += 1
|
||||||
|
try: wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDn', description = 'bad')
|
||||||
|
except: errors += 1
|
||||||
|
try: wallet.add_address_book('9ujeXrjzf7bfeK3KZdCqnYaMwZVFuXemPU8Ubw335rj2FN1CdMiWNyFV3ksEfMFvRp9L9qum5UxkP5rN9aLcPxbH1au4WAB', description = 'bad')
|
||||||
|
except: errors += 1
|
||||||
|
try: wallet.add_address_book('donate@example.com', description = 'bad')
|
||||||
|
except: errors += 1
|
||||||
|
assert errors == 5
|
||||||
|
res = wallet.get_address_book()
|
||||||
|
assert not 'entries' in res or len(res.entries) == 0
|
||||||
|
|
||||||
|
# openalias
|
||||||
|
res = wallet.add_address_book('donate@getmonero.org', description = 'dev fund')
|
||||||
|
assert res.index == 0
|
||||||
|
res = wallet.get_address_book()
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
e = res.entries[0]
|
||||||
|
assert e.address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
|
||||||
|
assert e.description == 'dev fund'
|
||||||
|
|
||||||
|
# UTF-8
|
||||||
|
res = wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', description = u'あまやかす')
|
||||||
|
assert res.index == 1
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert res.entries[0].description == u'あまやかす'
|
||||||
|
e = res.entries[0]
|
||||||
|
|
||||||
|
# duplicate request
|
||||||
|
res = wallet.get_address_book([1, 1])
|
||||||
|
assert len(res.entries) == 2
|
||||||
|
assert res.entries[0] == e
|
||||||
|
assert res.entries[1] == e
|
||||||
|
|
||||||
|
# payment IDs
|
||||||
|
res = wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', payment_id = '0' * 64)
|
||||||
|
assert res.index == 2
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', payment_id = 'x' * 64)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', payment_id = '0' * 65)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', payment_id = '0' * 63)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.add_address_book('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', payment_id = '0' * 16)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
# various address types
|
||||||
|
res = wallet.make_integrated_address()
|
||||||
|
integrated_address = res.integrated_address
|
||||||
|
integrated_address_payment_id = res.payment_id
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.add_address_book(integrated_address, payment_id = '0' * 64)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
res = wallet.add_address_book(integrated_address)
|
||||||
|
assert res.index == 3
|
||||||
|
res = wallet.add_address_book('87KfgTZ8ER5D3Frefqnrqif11TjVsTPaTcp37kqqKMrdDRUhpJRczeR7KiBmSHF32UJLP3HHhKUDmEQyJrv2mV8yFDCq8eB')
|
||||||
|
assert res.index == 4
|
||||||
|
|
||||||
|
# get them back
|
||||||
|
res = wallet.get_address_book([0])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert res.entries[0].address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
|
||||||
|
assert res.entries[0].description == 'dev fund'
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert res.entries[0].address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert res.entries[0].description == u'あまやかす'
|
||||||
|
res = wallet.get_address_book([2])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert res.entries[0].address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
res = wallet.get_address_book([3])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
if False: # for now, the address book splits integrated addresses
|
||||||
|
assert res.entries[0].address == integrated_address
|
||||||
|
else:
|
||||||
|
assert res.entries[0].address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert res.entries[0].payment_id == integrated_address_payment_id + '0' * 48
|
||||||
|
res = wallet.get_address_book([4])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert res.entries[0].address == '87KfgTZ8ER5D3Frefqnrqif11TjVsTPaTcp37kqqKMrdDRUhpJRczeR7KiBmSHF32UJLP3HHhKUDmEQyJrv2mV8yFDCq8eB'
|
||||||
|
|
||||||
|
# edit
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
e = res.entries[0]
|
||||||
|
assert e.index == 1
|
||||||
|
assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert e.payment_id == '0' * 64
|
||||||
|
assert e.description == u'あまやかす'
|
||||||
|
res = wallet.edit_address_book(1, payment_id = '1' * 64)
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
e = res.entries[0]
|
||||||
|
assert e.index == 1
|
||||||
|
assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert e.payment_id == '1' * 64
|
||||||
|
assert e.description == u'あまやかす'
|
||||||
|
res = wallet.edit_address_book(1, description = '')
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
e = res.entries[0]
|
||||||
|
assert e.index == 1
|
||||||
|
assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert e.payment_id == '1' * 64
|
||||||
|
assert e.description == ''
|
||||||
|
res = wallet.edit_address_book(1, description = 'えんしゅう')
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
e = res.entries[0]
|
||||||
|
assert e.index == 1
|
||||||
|
assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert e.payment_id == '1' * 64
|
||||||
|
assert e.description == u'えんしゅう'
|
||||||
|
res = wallet.edit_address_book(1, address = '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A')
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
e = res.entries[0]
|
||||||
|
assert e.index == 1
|
||||||
|
assert e.address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
|
||||||
|
assert e.payment_id == '1' * 64
|
||||||
|
assert e.description == u'えんしゅう'
|
||||||
|
res = wallet.edit_address_book(1, payment_id = '')
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
e = res.entries[0]
|
||||||
|
assert e.index == 1
|
||||||
|
assert e.address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
|
||||||
|
assert e.payment_id == '0' * 64
|
||||||
|
assert e.description == u'えんしゅう'
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.edit_address_book(1, address = '')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.edit_address_book(1, payment_id = 'asdnd')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.edit_address_book(1, address = 'address')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
res = wallet.edit_address_book(1)
|
||||||
|
res = wallet.get_address_book([1])
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert e == res.entries[0]
|
||||||
|
|
||||||
|
# empty
|
||||||
|
wallet.delete_address_book(4)
|
||||||
|
wallet.delete_address_book(0)
|
||||||
|
res = wallet.get_address_book([0]) # entries above the deleted one collapse one slot up
|
||||||
|
assert len(res.entries) == 1
|
||||||
|
assert res.entries[0].address == '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'
|
||||||
|
assert res.entries[0].description == u'えんしゅう'
|
||||||
|
wallet.delete_address_book(2)
|
||||||
|
wallet.delete_address_book(0)
|
||||||
|
wallet.delete_address_book(0)
|
||||||
|
res = wallet.get_address_book()
|
||||||
|
assert not 'entries' in res or len(res.entries) == 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
AddressBookTest().run_test()
|
|
@ -53,7 +53,8 @@ class BlockchainTest():
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def _test_generateblocks(self, blocks):
|
def _test_generateblocks(self, blocks):
|
||||||
|
@ -330,6 +331,9 @@ class BlockchainTest():
|
||||||
for txid in [alt_blocks[0], alt_blocks[2], alt_blocks[4]]:
|
for txid in [alt_blocks[0], alt_blocks[2], alt_blocks[4]]:
|
||||||
assert len([chain for chain in res.chains if chain.block_hash == txid]) == 1
|
assert len([chain for chain in res.chains if chain.block_hash == txid]) == 1
|
||||||
|
|
||||||
|
print('Saving blockchain explicitely')
|
||||||
|
daemon.save_bc()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
BlockchainTest().run_test()
|
BlockchainTest().run_test()
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
USAGE = 'usage: check_untested_methods.py <rootdir>'
|
||||||
|
try:
|
||||||
|
rootdir = sys.argv[1]
|
||||||
|
except:
|
||||||
|
print(USAGE)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
sys.path.insert(0, rootdir + '/utils/python-rpc')
|
||||||
|
|
||||||
|
from framework import daemon
|
||||||
|
from framework import wallet
|
||||||
|
|
||||||
|
modules = [
|
||||||
|
{
|
||||||
|
'name': 'daemon',
|
||||||
|
'object': daemon.Daemon(),
|
||||||
|
'path': rootdir + '/src/rpc/core_rpc_server.h',
|
||||||
|
'ignore': []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'wallet',
|
||||||
|
'object': wallet.Wallet(),
|
||||||
|
'path': rootdir + '/src/wallet/wallet_rpc_server.h',
|
||||||
|
'ignore': []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
error = False
|
||||||
|
for module in modules:
|
||||||
|
for line in open(module['path']).readlines():
|
||||||
|
if 'MAP_URI_AUTO_JON2' in line or 'MAP_JON_RPC' in line:
|
||||||
|
match = re.search('.*\"(.*)\".*', line)
|
||||||
|
name = match.group(1)
|
||||||
|
if name in module['ignore'] or name.endswith('.bin'):
|
||||||
|
continue
|
||||||
|
if 'MAP_URI_AUTO_JON2' in line:
|
||||||
|
if not name.startswith('/'):
|
||||||
|
print('Error: %s does not start with /' % name)
|
||||||
|
error = True
|
||||||
|
name = name[1:]
|
||||||
|
if not hasattr(module['object'], name):
|
||||||
|
print('Error: %s API method %s does not have a matching function' % (module['name'], name))
|
||||||
|
|
||||||
|
sys.exit(1 if error else 0)
|
|
@ -45,7 +45,8 @@ class ColdSigningTest():
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def create(self, idx):
|
def create(self, idx):
|
||||||
|
|
|
@ -10,7 +10,7 @@ import string
|
||||||
import os
|
import os
|
||||||
|
|
||||||
USAGE = 'usage: functional_tests_rpc.py <python> <srcdir> <builddir> [<tests-to-run> | all]'
|
USAGE = 'usage: functional_tests_rpc.py <python> <srcdir> <builddir> [<tests-to-run> | all]'
|
||||||
DEFAULT_TESTS = ['bans', 'daemon_info', 'blockchain', 'wallet_address', 'integrated_address', 'mining', 'transfer', 'txpool', 'multisig', 'cold_signing', 'sign_message', 'proofs', 'get_output_distribution']
|
DEFAULT_TESTS = ['address_book', 'bans', 'blockchain', 'cold_signing', 'daemon_info', 'get_output_distribution', 'integrated_address', 'mining', 'multisig', 'proofs', 'sign_message', 'transfer', 'txpool', 'uri', 'validate_address', 'wallet']
|
||||||
try:
|
try:
|
||||||
python = sys.argv[1]
|
python = sys.argv[1]
|
||||||
srcdir = sys.argv[2]
|
srcdir = sys.argv[2]
|
||||||
|
@ -36,9 +36,10 @@ except:
|
||||||
|
|
||||||
N_MONERODS = 1
|
N_MONERODS = 1
|
||||||
N_WALLETS = 4
|
N_WALLETS = 4
|
||||||
|
WALLET_DIRECTORY = builddir + "/functional-tests-directory"
|
||||||
|
|
||||||
monerod_base = [builddir + "/bin/monerod", "--regtest", "--fixed-difficulty", "1", "--offline", "--no-igd", "--p2p-bind-port", "monerod_p2p_port", "--rpc-bind-port", "monerod_rpc_port", "--zmq-rpc-bind-port", "monerod_zmq_port", "--non-interactive", "--disable-dns-checkpoints", "--check-updates", "disabled", "--rpc-ssl", "disabled", "--log-level", "1"]
|
monerod_base = [builddir + "/bin/monerod", "--regtest", "--fixed-difficulty", "1", "--offline", "--no-igd", "--p2p-bind-port", "monerod_p2p_port", "--rpc-bind-port", "monerod_rpc_port", "--zmq-rpc-bind-port", "monerod_zmq_port", "--non-interactive", "--disable-dns-checkpoints", "--check-updates", "disabled", "--rpc-ssl", "disabled", "--log-level", "1"]
|
||||||
wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", builddir + "/functional-tests-directory", "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--daemon-port", "18180", "--log-level", "1"]
|
wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--daemon-port", "18180", "--log-level", "1"]
|
||||||
|
|
||||||
command_lines = []
|
command_lines = []
|
||||||
processes = []
|
processes = []
|
||||||
|
@ -62,6 +63,8 @@ try:
|
||||||
PYTHONPATH += ':'
|
PYTHONPATH += ':'
|
||||||
PYTHONPATH += srcdir + '/../../utils/python-rpc'
|
PYTHONPATH += srcdir + '/../../utils/python-rpc'
|
||||||
os.environ['PYTHONPATH'] = PYTHONPATH
|
os.environ['PYTHONPATH'] = PYTHONPATH
|
||||||
|
os.environ['WALLET_DIRECTORY'] = WALLET_DIRECTORY
|
||||||
|
os.environ['PYTHONIOENCODING'] = 'utf-8'
|
||||||
for i in range(len(command_lines)):
|
for i in range(len(command_lines)):
|
||||||
#print('Running: ' + str(command_lines[i]))
|
#print('Running: ' + str(command_lines[i]))
|
||||||
processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i]))
|
processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i]))
|
||||||
|
@ -133,6 +136,6 @@ else:
|
||||||
if len(FAIL) == 0:
|
if len(FAIL) == 0:
|
||||||
print('Done, ' + str(len(PASS)) + '/' + str(len(tests)) + ' tests passed')
|
print('Done, ' + str(len(PASS)) + '/' + str(len(tests)) + ' tests passed')
|
||||||
else:
|
else:
|
||||||
print('Done, ' + str(len(FAIL)) + '/' + str(len(tests)) + ' tests failed: ' + string.join(FAIL, ', '))
|
print('Done, ' + str(len(FAIL)) + '/' + str(len(tests)) + ' tests failed: ' + ', '.join(FAIL))
|
||||||
|
|
||||||
sys.exit(0 if len(FAIL) == 0 else 1)
|
sys.exit(0 if len(FAIL) == 0 else 1)
|
||||||
|
|
|
@ -44,7 +44,8 @@ class GetOutputDistributionTest():
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
|
|
|
@ -46,12 +46,15 @@ class MiningTest():
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
self.reset()
|
self.reset()
|
||||||
self.create()
|
self.create()
|
||||||
self.mine()
|
self.mine(True)
|
||||||
|
self.mine(False)
|
||||||
|
self.submitblock()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
|
@ -62,8 +65,8 @@ class MiningTest():
|
||||||
except: pass
|
except: pass
|
||||||
res = wallet.restore_deterministic_wallet(seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted')
|
res = wallet.restore_deterministic_wallet(seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted')
|
||||||
|
|
||||||
def mine(self):
|
def mine(self, via_daemon):
|
||||||
print("Test mining")
|
print("Test mining via " + ("daemon" if via_daemon else "wallet"))
|
||||||
|
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
wallet = Wallet()
|
wallet = Wallet()
|
||||||
|
@ -76,7 +79,10 @@ class MiningTest():
|
||||||
|
|
||||||
res_status = daemon.mining_status()
|
res_status = daemon.mining_status()
|
||||||
|
|
||||||
res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1)
|
if via_daemon:
|
||||||
|
res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1)
|
||||||
|
else:
|
||||||
|
res = wallet.start_mining(threads_count = 1)
|
||||||
|
|
||||||
res_status = daemon.mining_status()
|
res_status = daemon.mining_status()
|
||||||
assert res_status.active == True
|
assert res_status.active == True
|
||||||
|
@ -101,7 +107,11 @@ class MiningTest():
|
||||||
timeout -= 1
|
timeout -= 1
|
||||||
assert timeout >= 0
|
assert timeout >= 0
|
||||||
|
|
||||||
res = daemon.stop_mining()
|
if via_daemon:
|
||||||
|
res = daemon.stop_mining()
|
||||||
|
else:
|
||||||
|
res = wallet.stop_mining()
|
||||||
|
|
||||||
res_status = daemon.mining_status()
|
res_status = daemon.mining_status()
|
||||||
assert res_status.active == False
|
assert res_status.active == False
|
||||||
|
|
||||||
|
@ -113,7 +123,10 @@ class MiningTest():
|
||||||
balance = res_getbalance.balance
|
balance = res_getbalance.balance
|
||||||
assert balance >= prev_balance + (new_height - prev_height) * 600000000000
|
assert balance >= prev_balance + (new_height - prev_height) * 600000000000
|
||||||
|
|
||||||
res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1, do_background_mining = True)
|
if via_daemon:
|
||||||
|
res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1, do_background_mining = True)
|
||||||
|
else:
|
||||||
|
res = wallet.start_mining(threads_count = 1, do_background_mining = True)
|
||||||
res_status = daemon.mining_status()
|
res_status = daemon.mining_status()
|
||||||
assert res_status.active == True
|
assert res_status.active == True
|
||||||
assert res_status.threads_count == 1
|
assert res_status.threads_count == 1
|
||||||
|
@ -122,10 +135,40 @@ class MiningTest():
|
||||||
assert res_status.block_reward >= 600000000000
|
assert res_status.block_reward >= 600000000000
|
||||||
|
|
||||||
# don't wait, might be a while if the machine is busy, which it probably is
|
# don't wait, might be a while if the machine is busy, which it probably is
|
||||||
res = daemon.stop_mining()
|
if via_daemon:
|
||||||
|
res = daemon.stop_mining()
|
||||||
|
else:
|
||||||
|
res = wallet.stop_mining()
|
||||||
res_status = daemon.mining_status()
|
res_status = daemon.mining_status()
|
||||||
assert res_status.active == False
|
assert res_status.active == False
|
||||||
|
|
||||||
|
def submitblock(self):
|
||||||
|
print("Test submitblock")
|
||||||
|
|
||||||
|
daemon = Daemon()
|
||||||
|
res = daemon.get_height()
|
||||||
|
height = res.height
|
||||||
|
res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 5)
|
||||||
|
assert len(res.blocks) == 5
|
||||||
|
hashes = res.blocks
|
||||||
|
blocks = []
|
||||||
|
for block_hash in hashes:
|
||||||
|
res = daemon.getblock(hash = block_hash)
|
||||||
|
assert len(res.blob) > 0 and len(res.blob) % 2 == 0
|
||||||
|
blocks.append(res.blob)
|
||||||
|
res = daemon.get_height()
|
||||||
|
assert res.height == height + 5
|
||||||
|
res = daemon.pop_blocks(5)
|
||||||
|
res = daemon.get_height()
|
||||||
|
assert res.height == height
|
||||||
|
for i in range(len(hashes)):
|
||||||
|
block_hash = hashes[i]
|
||||||
|
assert len(block_hash) == 64
|
||||||
|
res = daemon.submitblock(blocks[i])
|
||||||
|
res = daemon.get_height()
|
||||||
|
assert res.height == height + i + 1
|
||||||
|
assert res.hash == block_hash
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
MiningTest().run_test()
|
MiningTest().run_test()
|
||||||
|
|
|
@ -46,6 +46,8 @@ class MultisigTest():
|
||||||
self.mine('4ADHswEU3XBUee8pudBkZQd9beJainqNo1BQKkHJujAEPJyQrLj9U4dNm8HEMdHuWwKMFGzMUB3RCTvcTaW9kHpdRUDxgjW', 5)
|
self.mine('4ADHswEU3XBUee8pudBkZQd9beJainqNo1BQKkHJujAEPJyQrLj9U4dNm8HEMdHuWwKMFGzMUB3RCTvcTaW9kHpdRUDxgjW', 5)
|
||||||
self.mine('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 60)
|
self.mine('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 60)
|
||||||
|
|
||||||
|
self.test_states()
|
||||||
|
|
||||||
self.create_multisig_wallets(2, 2, '493DsrfJPqiN3Suv9RcRDoZEbQtKZX1sNcGPA3GhkKYEEmivk8kjQrTdRdVc4ZbmzWJuE157z9NNUKmF2VDfdYDR3CziGMk')
|
self.create_multisig_wallets(2, 2, '493DsrfJPqiN3Suv9RcRDoZEbQtKZX1sNcGPA3GhkKYEEmivk8kjQrTdRdVc4ZbmzWJuE157z9NNUKmF2VDfdYDR3CziGMk')
|
||||||
self.import_multisig_info([1, 0], 5)
|
self.import_multisig_info([1, 0], 5)
|
||||||
txid = self.transfer([1, 0])
|
txid = self.transfer([1, 0])
|
||||||
|
@ -79,7 +81,8 @@ class MultisigTest():
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def mine(self, address, blocks):
|
def mine(self, address, blocks):
|
||||||
|
@ -152,6 +155,72 @@ class MultisigTest():
|
||||||
assert res.threshold == M_threshold
|
assert res.threshold == M_threshold
|
||||||
assert res.total == N_total
|
assert res.total == N_total
|
||||||
|
|
||||||
|
def test_states(self):
|
||||||
|
print('Testing multisig states')
|
||||||
|
seeds = [
|
||||||
|
'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted',
|
||||||
|
'peeled mixture ionic radar utopia puddle buying illness nuns gadget river spout cavernous bounced paradise drunk looking cottage jump tequila melting went winter adjust spout',
|
||||||
|
'dilute gutter certain antics pamphlet macro enjoy left slid guarded bogeys upload nineteen bomb jubilee enhanced irritate turnip eggs swung jukebox loudly reduce sedan slid',
|
||||||
|
]
|
||||||
|
info = []
|
||||||
|
wallet = [None, None, None]
|
||||||
|
for i in range(3):
|
||||||
|
wallet[i] = Wallet(idx = i)
|
||||||
|
try: wallet[i].close_wallet()
|
||||||
|
except: pass
|
||||||
|
res = wallet[i].restore_deterministic_wallet(seed = seeds[i])
|
||||||
|
res = wallet[i].is_multisig()
|
||||||
|
assert not res.multisig
|
||||||
|
res = wallet[i].prepare_multisig()
|
||||||
|
assert len(res.multisig_info) > 0
|
||||||
|
info.append(res.multisig_info)
|
||||||
|
|
||||||
|
for i in range(3):
|
||||||
|
ok = False
|
||||||
|
try: res = wallet[i].finalize_multisig(info)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet[i].exchange_multisig_keys(info)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
res = wallet[i].is_multisig()
|
||||||
|
assert not res.multisig
|
||||||
|
|
||||||
|
res = wallet[0].make_multisig(info[0:2], 2)
|
||||||
|
res = wallet[0].is_multisig()
|
||||||
|
assert res.multisig
|
||||||
|
assert res.ready
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = wallet[0].finalize_multisig(info)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = wallet[0].prepare_multisig()
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = wallet[0].make_multisig(info[0:2], 2)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
res = wallet[1].make_multisig(info, 2)
|
||||||
|
res = wallet[1].is_multisig()
|
||||||
|
assert res.multisig
|
||||||
|
assert not res.ready
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = wallet[1].prepare_multisig()
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = wallet[1].make_multisig(info[0:2], 2)
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
def import_multisig_info(self, signers, expected_outputs):
|
def import_multisig_info(self, signers, expected_outputs):
|
||||||
assert len(signers) >= 2
|
assert len(signers) >= 2
|
||||||
|
|
|
@ -44,12 +44,14 @@ class ProofsTest():
|
||||||
txid, tx_key, amount = self.transfer()
|
txid, tx_key, amount = self.transfer()
|
||||||
self.check_tx_key(txid, tx_key, amount)
|
self.check_tx_key(txid, tx_key, amount)
|
||||||
self.check_tx_proof(txid, amount)
|
self.check_tx_proof(txid, amount)
|
||||||
|
self.check_spend_proof(txid)
|
||||||
self.check_reserve_proof()
|
self.check_reserve_proof()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def mine(self, address, blocks):
|
def mine(self, address, blocks):
|
||||||
|
@ -217,6 +219,40 @@ class ProofsTest():
|
||||||
except: ok = True
|
except: ok = True
|
||||||
assert ok or not res.good
|
assert ok or not res.good
|
||||||
|
|
||||||
|
def check_spend_proof(self, txid):
|
||||||
|
daemon = Daemon()
|
||||||
|
|
||||||
|
print('Checking spend proof')
|
||||||
|
|
||||||
|
self.wallet[0].refresh()
|
||||||
|
self.wallet[1].refresh()
|
||||||
|
|
||||||
|
res = self.wallet[0].get_spend_proof(txid, message = 'foo')
|
||||||
|
assert len(res.signature) > 0
|
||||||
|
signature = res.signature
|
||||||
|
res = self.wallet[1].check_spend_proof(txid, message = 'foo', signature = signature)
|
||||||
|
assert res.good
|
||||||
|
|
||||||
|
res = self.wallet[0].get_spend_proof(txid, message = 'foobar')
|
||||||
|
assert len(res.signature) > 0
|
||||||
|
signature2 = res.signature
|
||||||
|
res = self.wallet[1].check_spend_proof(txid, message = 'foobar', signature = signature2)
|
||||||
|
assert res.good
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = self.wallet[1].check_spend_proof('0' * 64, message = 'foo', signature = signature)
|
||||||
|
except: ok = True
|
||||||
|
assert ok or not res.good
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = self.wallet[1].check_spend_proof(txid, message = 'bar', signature = signature)
|
||||||
|
except: ok = True
|
||||||
|
assert ok or not res.good
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = self.wallet[1].check_spend_proof(txid, message = 'foo', signature = signature2)
|
||||||
|
except: ok = True
|
||||||
|
assert ok or not res.good
|
||||||
|
|
||||||
def check_reserve_proof(self):
|
def check_reserve_proof(self):
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
|
|
|
@ -47,14 +47,27 @@ from framework.wallet import Wallet
|
||||||
|
|
||||||
|
|
||||||
class SpeedTest():
|
class SpeedTest():
|
||||||
def set_test_params(self):
|
def reset(self):
|
||||||
self.num_nodes = 1
|
print('Resetting blockchain')
|
||||||
|
daemon = Daemon()
|
||||||
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
|
self.reset()
|
||||||
|
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
wallet = Wallet()
|
wallet = Wallet()
|
||||||
|
|
||||||
destinations = wallet.make_uniform_destinations('44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A',1,3)
|
# close the wallet if any, will throw if none is loaded
|
||||||
|
try: wallet.close_wallet()
|
||||||
|
except: pass
|
||||||
|
wallet.restore_deterministic_wallet('velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted')
|
||||||
|
|
||||||
|
destinations = []
|
||||||
|
for i in range(3):
|
||||||
|
destinations.append({"amount":1,"address":'44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'})
|
||||||
|
|
||||||
self._test_speed_generateblocks(daemon=daemon, blocks=70)
|
self._test_speed_generateblocks(daemon=daemon, blocks=70)
|
||||||
for i in range(1, 10):
|
for i in range(1, 10):
|
||||||
|
@ -69,7 +82,6 @@ class SpeedTest():
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', blocks)
|
res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', blocks)
|
||||||
# wallet seed: velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted
|
|
||||||
|
|
||||||
print('generating ', blocks, 'blocks took: ', time.time() - start, 'seconds')
|
print('generating ', blocks, 'blocks took: ', time.time() - start, 'seconds')
|
||||||
|
|
||||||
|
@ -77,7 +89,7 @@ class SpeedTest():
|
||||||
print('Test speed of transfer')
|
print('Test speed of transfer')
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
destinations = wallet.make_uniform_destinations('44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A',1)
|
destinations = [{"amount":1,"address":'44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A'}]
|
||||||
res = wallet.transfer_split(destinations)
|
res = wallet.transfer_split(destinations)
|
||||||
|
|
||||||
print('generating tx took: ', time.time() - start, 'seconds')
|
print('generating tx took: ', time.time() - start, 'seconds')
|
||||||
|
|
|
@ -44,14 +44,20 @@ class TransferTest():
|
||||||
self.mine()
|
self.mine()
|
||||||
self.transfer()
|
self.transfer()
|
||||||
self.check_get_bulk_payments()
|
self.check_get_bulk_payments()
|
||||||
|
self.check_get_payments()
|
||||||
self.check_double_spend_detection()
|
self.check_double_spend_detection()
|
||||||
|
self.sweep_dust()
|
||||||
self.sweep_single()
|
self.sweep_single()
|
||||||
self.check_destinations()
|
self.check_destinations()
|
||||||
|
self.check_tx_notes()
|
||||||
|
self.check_rescan()
|
||||||
|
self.check_is_key_image_spent()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
|
@ -114,7 +120,7 @@ class TransferTest():
|
||||||
except: ok = True
|
except: ok = True
|
||||||
assert ok
|
assert ok
|
||||||
|
|
||||||
res = self.wallet[0].transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = False)
|
res = self.wallet[0].transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = False, get_tx_hex = True)
|
||||||
assert len(res.tx_hash) == 32*2
|
assert len(res.tx_hash) == 32*2
|
||||||
txid = res.tx_hash
|
txid = res.tx_hash
|
||||||
assert len(res.tx_key) == 0
|
assert len(res.tx_key) == 0
|
||||||
|
@ -122,12 +128,19 @@ class TransferTest():
|
||||||
amount = res.amount
|
amount = res.amount
|
||||||
assert res.fee > 0
|
assert res.fee > 0
|
||||||
fee = res.fee
|
fee = res.fee
|
||||||
assert len(res.tx_blob) == 0
|
assert len(res.tx_blob) > 0
|
||||||
|
blob_size = len(res.tx_blob) // 2
|
||||||
assert len(res.tx_metadata) == 0
|
assert len(res.tx_metadata) == 0
|
||||||
assert len(res.multisig_txset) == 0
|
assert len(res.multisig_txset) == 0
|
||||||
assert len(res.unsigned_txset) == 0
|
assert len(res.unsigned_txset) == 0
|
||||||
unsigned_txset = res.unsigned_txset
|
unsigned_txset = res.unsigned_txset
|
||||||
|
|
||||||
|
res = daemon.get_fee_estimate(10)
|
||||||
|
assert res.fee > 0
|
||||||
|
assert res.quantization_mask > 0
|
||||||
|
expected_fee = (res.fee * 1 * blob_size + res.quantization_mask - 1) // res.quantization_mask * res.quantization_mask
|
||||||
|
assert abs(1 - fee / expected_fee) < 0.01
|
||||||
|
|
||||||
self.wallet[0].refresh()
|
self.wallet[0].refresh()
|
||||||
|
|
||||||
res = daemon.get_info()
|
res = daemon.get_info()
|
||||||
|
@ -523,6 +536,28 @@ class TransferTest():
|
||||||
res = self.wallet[1].get_bulk_payments(["1111111122222222"])
|
res = self.wallet[1].get_bulk_payments(["1111111122222222"])
|
||||||
assert len(res.payments) >= 1 # we have one of these
|
assert len(res.payments) >= 1 # we have one of these
|
||||||
|
|
||||||
|
def check_get_payments(self):
|
||||||
|
print('Checking get_payments')
|
||||||
|
|
||||||
|
daemon = Daemon()
|
||||||
|
res = daemon.get_info()
|
||||||
|
height = res.height
|
||||||
|
|
||||||
|
self.wallet[0].refresh()
|
||||||
|
self.wallet[1].refresh()
|
||||||
|
|
||||||
|
res = self.wallet[0].get_payments('1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde')
|
||||||
|
assert 'payments' not in res or len(res.payments) == 0
|
||||||
|
|
||||||
|
res = self.wallet[1].get_payments('1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde')
|
||||||
|
assert len(res.payments) >= 2
|
||||||
|
|
||||||
|
res = self.wallet[1].get_payments('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
|
||||||
|
assert 'payments' not in res or len(res.payments) == 0
|
||||||
|
|
||||||
|
res = self.wallet[1].get_payments(payment_id = '1111111122222222' + '0'*48)
|
||||||
|
assert len(res.payments) >= 1 # one tx to integrated address
|
||||||
|
|
||||||
def check_double_spend_detection(self):
|
def check_double_spend_detection(self):
|
||||||
print('Checking double spend detection')
|
print('Checking double spend detection')
|
||||||
txes = [[None, None], [None, None]]
|
txes = [[None, None], [None, None]]
|
||||||
|
@ -583,6 +618,13 @@ class TransferTest():
|
||||||
assert tx.in_pool
|
assert tx.in_pool
|
||||||
assert tx.double_spend_seen
|
assert tx.double_spend_seen
|
||||||
|
|
||||||
|
def sweep_dust(self):
|
||||||
|
print("Sweeping dust")
|
||||||
|
daemon = Daemon()
|
||||||
|
self.wallet[0].refresh()
|
||||||
|
res = self.wallet[0].sweep_dust()
|
||||||
|
assert not 'tx_hash_list' in res or len(res.tx_hash_list) == 0 # there's just one, but it cannot meet the fee
|
||||||
|
|
||||||
def sweep_single(self):
|
def sweep_single(self):
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
|
|
||||||
|
@ -603,11 +645,19 @@ class TransferTest():
|
||||||
self.wallet[0].refresh()
|
self.wallet[0].refresh()
|
||||||
res = self.wallet[0].get_balance()
|
res = self.wallet[0].get_balance()
|
||||||
balance = res.balance
|
balance = res.balance
|
||||||
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
|
res = daemon.is_key_image_spent([ki])
|
||||||
|
assert len(res.spent_status) == 1
|
||||||
|
assert res.spent_status[0] == 0
|
||||||
res = self.wallet[0].sweep_single('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', key_image = ki)
|
res = self.wallet[0].sweep_single('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', key_image = ki)
|
||||||
assert len(res.tx_hash) == 64
|
assert len(res.tx_hash) == 64
|
||||||
tx_hash = res.tx_hash
|
tx_hash = res.tx_hash
|
||||||
|
res = daemon.is_key_image_spent([ki])
|
||||||
|
assert len(res.spent_status) == 1
|
||||||
|
assert res.spent_status[0] == 2
|
||||||
daemon.generateblocks('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 1)
|
daemon.generateblocks('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 1)
|
||||||
|
res = daemon.is_key_image_spent([ki])
|
||||||
|
assert len(res.spent_status) == 1
|
||||||
|
assert res.spent_status[0] == 1
|
||||||
self.wallet[0].refresh()
|
self.wallet[0].refresh()
|
||||||
res = self.wallet[0].get_balance()
|
res = self.wallet[0].get_balance()
|
||||||
new_balance = res.balance
|
new_balance = res.balance
|
||||||
|
@ -687,7 +737,97 @@ class TransferTest():
|
||||||
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
|
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
|
||||||
self.wallet[0].refresh()
|
self.wallet[0].refresh()
|
||||||
|
|
||||||
|
def check_tx_notes(self):
|
||||||
|
daemon = Daemon()
|
||||||
|
|
||||||
|
print('Testing tx notes')
|
||||||
|
res = self.wallet[0].get_transfers()
|
||||||
|
assert len(res['in']) > 0
|
||||||
|
in_txid = res['in'][0].txid
|
||||||
|
assert len(res['out']) > 0
|
||||||
|
out_txid = res['out'][0].txid
|
||||||
|
res = self.wallet[0].get_tx_notes([in_txid, out_txid])
|
||||||
|
assert res.notes == ['', '']
|
||||||
|
res = self.wallet[0].set_tx_notes([in_txid, out_txid], ['in txid', 'out txid'])
|
||||||
|
res = self.wallet[0].get_tx_notes([in_txid, out_txid])
|
||||||
|
assert res.notes == ['in txid', 'out txid']
|
||||||
|
res = self.wallet[0].get_tx_notes([out_txid, in_txid])
|
||||||
|
assert res.notes == ['out txid', 'in txid']
|
||||||
|
|
||||||
|
def check_rescan(self):
|
||||||
|
daemon = Daemon()
|
||||||
|
|
||||||
|
print('Testing rescan_spent')
|
||||||
|
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
|
||||||
|
transfers = res.transfers
|
||||||
|
res = self.wallet[0].rescan_spent()
|
||||||
|
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
|
||||||
|
assert transfers == res.transfers
|
||||||
|
|
||||||
|
for hard in [False, True]:
|
||||||
|
print('Testing %s rescan_blockchain' % ('hard' if hard else 'soft'))
|
||||||
|
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
|
||||||
|
transfers = res.transfers
|
||||||
|
res = self.wallet[0].get_transfers()
|
||||||
|
t_in = res['in']
|
||||||
|
t_out = res.out
|
||||||
|
res = self.wallet[0].rescan_blockchain(hard = hard)
|
||||||
|
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
|
||||||
|
assert transfers == res.transfers
|
||||||
|
res = self.wallet[0].get_transfers()
|
||||||
|
assert t_in == res['in']
|
||||||
|
# some information can not be recovered for out txes
|
||||||
|
unrecoverable_fields = ['payment_id', 'destinations', 'note']
|
||||||
|
old_t_out = []
|
||||||
|
for x in t_out:
|
||||||
|
e = {}
|
||||||
|
for k in x.keys():
|
||||||
|
if not k in unrecoverable_fields:
|
||||||
|
e[k] = x[k]
|
||||||
|
old_t_out.append(e)
|
||||||
|
new_t_out = []
|
||||||
|
for x in res.out:
|
||||||
|
e = {}
|
||||||
|
for k in x.keys():
|
||||||
|
if not k in unrecoverable_fields:
|
||||||
|
e[k] = x[k]
|
||||||
|
new_t_out.append(e)
|
||||||
|
assert sorted(old_t_out, key = lambda k: k['txid']) == sorted(new_t_out, key = lambda k: k['txid'])
|
||||||
|
|
||||||
|
def check_is_key_image_spent(self):
|
||||||
|
daemon = Daemon()
|
||||||
|
|
||||||
|
print('Testing is_key_image_spent')
|
||||||
|
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
|
||||||
|
transfers = res.transfers
|
||||||
|
ki = [x.key_image for x in transfers]
|
||||||
|
expected = [1 if x.spent else 0 for x in transfers]
|
||||||
|
res = daemon.is_key_image_spent(ki)
|
||||||
|
assert res.spent_status == expected
|
||||||
|
|
||||||
|
res = self.wallet[0].incoming_transfers(transfer_type = 'available')
|
||||||
|
transfers = res.transfers
|
||||||
|
ki = [x.key_image for x in transfers]
|
||||||
|
expected = [0 for x in transfers]
|
||||||
|
res = daemon.is_key_image_spent(ki)
|
||||||
|
assert res.spent_status == expected
|
||||||
|
|
||||||
|
res = self.wallet[0].incoming_transfers(transfer_type = 'unavailable')
|
||||||
|
transfers = res.transfers
|
||||||
|
ki = [x.key_image for x in transfers]
|
||||||
|
expected = [1 for x in transfers]
|
||||||
|
res = daemon.is_key_image_spent(ki)
|
||||||
|
assert res.spent_status == expected
|
||||||
|
|
||||||
|
ki = [ki[-1]] * 5
|
||||||
|
expected = [1] * len(ki)
|
||||||
|
res = daemon.is_key_image_spent(ki)
|
||||||
|
assert res.spent_status == expected
|
||||||
|
|
||||||
|
ki = ['2'*64, '1'*64]
|
||||||
|
expected = [0, 0]
|
||||||
|
res = daemon.is_key_image_spent(ki)
|
||||||
|
assert res.spent_status == expected
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -46,7 +46,8 @@ class TransferTest():
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
|
@ -81,6 +82,26 @@ class TransferTest():
|
||||||
|
|
||||||
return txes
|
return txes
|
||||||
|
|
||||||
|
def check_empty_pool(self):
|
||||||
|
daemon = Daemon()
|
||||||
|
|
||||||
|
res = daemon.get_transaction_pool_hashes()
|
||||||
|
assert not 'tx_hashes' in res or len(res.tx_hashes) == 0
|
||||||
|
res = daemon.get_transaction_pool_stats()
|
||||||
|
assert res.pool_stats.bytes_total == 0
|
||||||
|
assert res.pool_stats.bytes_min == 0
|
||||||
|
assert res.pool_stats.bytes_max == 0
|
||||||
|
assert res.pool_stats.bytes_med == 0
|
||||||
|
assert res.pool_stats.fee_total == 0
|
||||||
|
assert res.pool_stats.oldest == 0
|
||||||
|
assert res.pool_stats.txs_total == 0
|
||||||
|
assert res.pool_stats.num_failing == 0
|
||||||
|
assert res.pool_stats.num_10m == 0
|
||||||
|
assert res.pool_stats.num_not_relayed == 0
|
||||||
|
assert res.pool_stats.histo_98pc == 0
|
||||||
|
assert not 'histo' in res.pool_stats or len(res.pool_stats.histo) == 0
|
||||||
|
assert res.pool_stats.num_double_spends == 0
|
||||||
|
|
||||||
def check_txpool(self):
|
def check_txpool(self):
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
wallet = Wallet()
|
wallet = Wallet()
|
||||||
|
@ -89,6 +110,8 @@ class TransferTest():
|
||||||
height = res.height
|
height = res.height
|
||||||
txpool_size = res.tx_pool_size
|
txpool_size = res.tx_pool_size
|
||||||
|
|
||||||
|
self.check_empty_pool()
|
||||||
|
|
||||||
txes = self.create_txes('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 5)
|
txes = self.create_txes('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 5)
|
||||||
|
|
||||||
res = daemon.get_info()
|
res = daemon.get_info()
|
||||||
|
@ -97,6 +120,10 @@ class TransferTest():
|
||||||
|
|
||||||
res = daemon.get_transaction_pool()
|
res = daemon.get_transaction_pool()
|
||||||
assert len(res.transactions) == txpool_size
|
assert len(res.transactions) == txpool_size
|
||||||
|
total_bytes = 0
|
||||||
|
total_fee = 0
|
||||||
|
min_bytes = 99999999999999
|
||||||
|
max_bytes = 0
|
||||||
for txid in txes.keys():
|
for txid in txes.keys():
|
||||||
x = [x for x in res.transactions if x.id_hash == txid]
|
x = [x for x in res.transactions if x.id_hash == txid]
|
||||||
assert len(x) == 1
|
assert len(x) == 1
|
||||||
|
@ -110,9 +137,26 @@ class TransferTest():
|
||||||
assert x.fee == txes[txid].fee
|
assert x.fee == txes[txid].fee
|
||||||
assert x.tx_blob == txes[txid].tx_blob
|
assert x.tx_blob == txes[txid].tx_blob
|
||||||
|
|
||||||
|
total_bytes += x.blob_size
|
||||||
|
total_fee += x.fee
|
||||||
|
min_bytes = min(min_bytes, x.blob_size)
|
||||||
|
max_bytes = max(max_bytes, x.blob_size)
|
||||||
|
|
||||||
res = daemon.get_transaction_pool_hashes()
|
res = daemon.get_transaction_pool_hashes()
|
||||||
assert sorted(res.tx_hashes) == sorted(txes.keys())
|
assert sorted(res.tx_hashes) == sorted(txes.keys())
|
||||||
|
|
||||||
|
res = daemon.get_transaction_pool_stats()
|
||||||
|
assert res.pool_stats.bytes_total == total_bytes
|
||||||
|
assert res.pool_stats.bytes_min == min_bytes
|
||||||
|
assert res.pool_stats.bytes_max == max_bytes
|
||||||
|
assert res.pool_stats.bytes_med >= min_bytes and res.pool_stats.bytes_med <= max_bytes
|
||||||
|
assert res.pool_stats.fee_total == total_fee
|
||||||
|
assert res.pool_stats.txs_total == len(txes)
|
||||||
|
assert res.pool_stats.num_failing == 0
|
||||||
|
assert res.pool_stats.num_10m == 0
|
||||||
|
assert res.pool_stats.num_not_relayed == 0
|
||||||
|
assert res.pool_stats.num_double_spends == 0
|
||||||
|
|
||||||
print('Flushing 2 transactions')
|
print('Flushing 2 transactions')
|
||||||
txes_keys = list(txes.keys())
|
txes_keys = list(txes.keys())
|
||||||
daemon.flush_txpool([txes_keys[1], txes_keys[3]])
|
daemon.flush_txpool([txes_keys[1], txes_keys[3]])
|
||||||
|
@ -127,6 +171,42 @@ class TransferTest():
|
||||||
res = daemon.get_transaction_pool_hashes()
|
res = daemon.get_transaction_pool_hashes()
|
||||||
assert sorted(res.tx_hashes) == sorted(new_keys)
|
assert sorted(res.tx_hashes) == sorted(new_keys)
|
||||||
|
|
||||||
|
res = daemon.get_transaction_pool()
|
||||||
|
assert len(res.transactions) == len(new_keys)
|
||||||
|
total_bytes = 0
|
||||||
|
total_fee = 0
|
||||||
|
min_bytes = 99999999999999
|
||||||
|
max_bytes = 0
|
||||||
|
for txid in new_keys:
|
||||||
|
x = [x for x in res.transactions if x.id_hash == txid]
|
||||||
|
assert len(x) == 1
|
||||||
|
x = x[0]
|
||||||
|
assert x.kept_by_block == False
|
||||||
|
assert x.last_failed_id_hash == '0'*64
|
||||||
|
assert x.double_spend_seen == False
|
||||||
|
assert x.weight >= x.blob_size
|
||||||
|
|
||||||
|
assert x.blob_size * 2 == len(txes[txid].tx_blob)
|
||||||
|
assert x.fee == txes[txid].fee
|
||||||
|
assert x.tx_blob == txes[txid].tx_blob
|
||||||
|
|
||||||
|
total_bytes += x.blob_size
|
||||||
|
total_fee += x.fee
|
||||||
|
min_bytes = min(min_bytes, x.blob_size)
|
||||||
|
max_bytes = max(max_bytes, x.blob_size)
|
||||||
|
|
||||||
|
res = daemon.get_transaction_pool_stats()
|
||||||
|
assert res.pool_stats.bytes_total == total_bytes
|
||||||
|
assert res.pool_stats.bytes_min == min_bytes
|
||||||
|
assert res.pool_stats.bytes_max == max_bytes
|
||||||
|
assert res.pool_stats.bytes_med >= min_bytes and res.pool_stats.bytes_med <= max_bytes
|
||||||
|
assert res.pool_stats.fee_total == total_fee
|
||||||
|
assert res.pool_stats.txs_total == len(new_keys)
|
||||||
|
assert res.pool_stats.num_failing == 0
|
||||||
|
assert res.pool_stats.num_10m == 0
|
||||||
|
assert res.pool_stats.num_not_relayed == 0
|
||||||
|
assert res.pool_stats.num_double_spends == 0
|
||||||
|
|
||||||
print('Flushing unknown transactions')
|
print('Flushing unknown transactions')
|
||||||
unknown_txids = ['1'*64, '2'*64, '3'*64]
|
unknown_txids = ['1'*64, '2'*64, '3'*64]
|
||||||
daemon.flush_txpool(unknown_txids)
|
daemon.flush_txpool(unknown_txids)
|
||||||
|
@ -140,6 +220,8 @@ class TransferTest():
|
||||||
res = daemon.get_transaction_pool_hashes()
|
res = daemon.get_transaction_pool_hashes()
|
||||||
assert not 'tx_hashes' in res or len(res.tx_hashes) == 0
|
assert not 'tx_hashes' in res or len(res.tx_hashes) == 0
|
||||||
|
|
||||||
|
self.check_empty_pool()
|
||||||
|
|
||||||
print('Popping block')
|
print('Popping block')
|
||||||
daemon.pop_blocks(1)
|
daemon.pop_blocks(1)
|
||||||
res = daemon.get_transaction_pool_hashes()
|
res = daemon.get_transaction_pool_hashes()
|
||||||
|
@ -159,6 +241,9 @@ class TransferTest():
|
||||||
assert x.fee == txes[txid].fee
|
assert x.fee == txes[txid].fee
|
||||||
assert x.tx_blob == txes[txid].tx_blob
|
assert x.tx_blob == txes[txid].tx_blob
|
||||||
|
|
||||||
|
daemon.flush_txpool()
|
||||||
|
self.check_empty_pool()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
TransferTest().run_test()
|
TransferTest().run_test()
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#encoding=utf-8
|
||||||
|
|
||||||
|
# Copyright (c) 2019 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.
|
||||||
|
|
||||||
|
"""Test URI RPC
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
try:
|
||||||
|
from urllib import quote as urllib_quote
|
||||||
|
except:
|
||||||
|
from urllib.parse import quote as urllib_quote
|
||||||
|
|
||||||
|
from framework.wallet import Wallet
|
||||||
|
|
||||||
|
class URITest():
|
||||||
|
def run_test(self):
|
||||||
|
self.create()
|
||||||
|
self.test_monero_uri()
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
print('Creating wallet')
|
||||||
|
wallet = Wallet()
|
||||||
|
# close the wallet if any, will throw if none is loaded
|
||||||
|
try: wallet.close_wallet()
|
||||||
|
except: pass
|
||||||
|
seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted'
|
||||||
|
res = wallet.restore_deterministic_wallet(seed = seed)
|
||||||
|
assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert res.seed == seed
|
||||||
|
|
||||||
|
def test_monero_uri(self):
|
||||||
|
print('Testing monero: URI')
|
||||||
|
wallet = Wallet()
|
||||||
|
|
||||||
|
utf8string = [u'えんしゅう', u'あまやかす']
|
||||||
|
quoted_utf8string = [urllib_quote(x.encode('utf8')) for x in utf8string]
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.make_uri()
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.make_uri(address = '')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.make_uri(address = 'kjshdkj')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
for address in [
|
||||||
|
'42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm',
|
||||||
|
'4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY',
|
||||||
|
'8AsN91rznfkBGTY8psSNkJBg9SZgxxGGRUhGwRptBhgr5XSQ1XzmA9m8QAnoxydecSh5aLJXdrgXwTDMMZ1AuXsN1EX5Mtm'
|
||||||
|
]:
|
||||||
|
res = wallet.make_uri(address = address)
|
||||||
|
assert res.uri == 'monero:' + address
|
||||||
|
res = wallet.parse_uri(res.uri)
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.payment_id == ''
|
||||||
|
assert res.uri.amount == 0
|
||||||
|
assert res.uri.tx_description == ''
|
||||||
|
assert res.uri.recipient_name == ''
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
res = wallet.make_uri(address = address, amount = 11000000000)
|
||||||
|
assert res.uri == 'monero:' + address + '?tx_amount=0.011' or res.uri == 'monero:' + address + '?tx_amount=0.011000000000'
|
||||||
|
res = wallet.parse_uri(res.uri)
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.payment_id == ''
|
||||||
|
assert res.uri.amount == 11000000000
|
||||||
|
assert res.uri.tx_description == ''
|
||||||
|
assert res.uri.recipient_name == ''
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
|
||||||
|
address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
|
||||||
|
res = wallet.make_uri(address = address, tx_description = utf8string[0])
|
||||||
|
assert res.uri == 'monero:' + address + '?tx_description=' + quoted_utf8string[0]
|
||||||
|
res = wallet.parse_uri(res.uri)
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.payment_id == ''
|
||||||
|
assert res.uri.amount == 0
|
||||||
|
assert res.uri.tx_description == utf8string[0]
|
||||||
|
assert res.uri.recipient_name == ''
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
|
||||||
|
res = wallet.make_uri(address = address, recipient_name = utf8string[0])
|
||||||
|
assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0]
|
||||||
|
res = wallet.parse_uri(res.uri)
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.payment_id == ''
|
||||||
|
assert res.uri.amount == 0
|
||||||
|
assert res.uri.tx_description == ''
|
||||||
|
assert res.uri.recipient_name == utf8string[0]
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
|
||||||
|
res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1])
|
||||||
|
assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1]
|
||||||
|
res = wallet.parse_uri(res.uri)
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.payment_id == ''
|
||||||
|
assert res.uri.amount == 0
|
||||||
|
assert res.uri.tx_description == utf8string[1]
|
||||||
|
assert res.uri.recipient_name == utf8string[0]
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
|
||||||
|
res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000)
|
||||||
|
assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1]
|
||||||
|
res = wallet.parse_uri(res.uri)
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.payment_id == ''
|
||||||
|
assert res.uri.amount == 1000000000000
|
||||||
|
assert res.uri.tx_description == utf8string[1]
|
||||||
|
assert res.uri.recipient_name == utf8string[0]
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
|
||||||
|
res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000, payment_id = '1' * 64)
|
||||||
|
assert res.uri == 'monero:' + address + '?tx_payment_id=' + '1' * 64 + '&tx_amount=1.000000000000&recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1]
|
||||||
|
res = wallet.parse_uri(res.uri)
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.payment_id == '1' * 64
|
||||||
|
assert res.uri.amount == 1000000000000
|
||||||
|
assert res.uri.tx_description == utf8string[1]
|
||||||
|
assert res.uri.recipient_name == utf8string[0]
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
|
||||||
|
# spaces must be encoded as %20
|
||||||
|
res = wallet.make_uri(address = address, tx_description = ' ' + utf8string[1] + ' ' + utf8string[0] + ' ', amount = 1000000000000)
|
||||||
|
assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&tx_description=%20' + quoted_utf8string[1] + '%20' + quoted_utf8string[0] + '%20'
|
||||||
|
res = wallet.parse_uri(res.uri)
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.payment_id == ''
|
||||||
|
assert res.uri.amount == 1000000000000
|
||||||
|
assert res.uri.tx_description == ' ' + utf8string[1] + ' ' + utf8string[0] + ' '
|
||||||
|
assert res.uri.recipient_name == ''
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
|
||||||
|
# the example from the docs
|
||||||
|
res = wallet.parse_uri('monero:46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em?tx_amount=239.39014&tx_description=donation')
|
||||||
|
assert res.uri.address == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em'
|
||||||
|
assert res.uri.amount == 239390140000000
|
||||||
|
assert res.uri.tx_description == 'donation'
|
||||||
|
assert res.uri.recipient_name == ''
|
||||||
|
assert res.uri.payment_id == ''
|
||||||
|
assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0
|
||||||
|
|
||||||
|
# malformed/invalid
|
||||||
|
for uri in [
|
||||||
|
'',
|
||||||
|
':',
|
||||||
|
'monero',
|
||||||
|
'notmonero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm',
|
||||||
|
'MONERO:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm',
|
||||||
|
'MONERO::42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm',
|
||||||
|
'monero:',
|
||||||
|
'monero:badaddress',
|
||||||
|
'monero:tx_amount=10',
|
||||||
|
'monero:?tx_amount=10',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=-1',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=1e12',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=+12',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=1+2',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=A',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=0x2',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=222222222222222222222',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDn?tx_amount=10',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm&',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm&tx_amount',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm&tx_amount=',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm&tx_amount=10=',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm&tx_amount=10=&',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm&tx_amount=10=&foo=bar',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=10&tx_amount=20',
|
||||||
|
'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_payment_id=1111111111111111',
|
||||||
|
'monero:4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY?tx_payment_id=' + '1' * 64,
|
||||||
|
'monero:9ujeXrjzf7bfeK3KZdCqnYaMwZVFuXemPU8Ubw335rj2FN1CdMiWNyFV3ksEfMFvRp9L9qum5UxkP5rN9aLcPxbH1au4WAB',
|
||||||
|
'monero:5K8mwfjumVseCcQEjNbf59Um6R9NfVUNkHTLhhPCmNvgDLVS88YW5tScnm83rw9mfgYtchtDDTW5jEfMhygi27j1QYphX38hg6m4VMtN29',
|
||||||
|
'monero:7A1Hr63MfgUa8pkWxueD5xBqhQczkusYiCMYMnJGcGmuQxa7aDBxN1G7iCuLCNB3VPeb2TW7U9FdxB27xKkWKfJ8VhUZthF',
|
||||||
|
]:
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.parse_uri(uri)
|
||||||
|
except: ok = True
|
||||||
|
assert ok, res
|
||||||
|
|
||||||
|
# unknown parameters but otherwise valid
|
||||||
|
res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar')
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.amount == 239390140000000
|
||||||
|
assert res.unknown_parameters == ['foo=bar'], res
|
||||||
|
res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar&baz=quux')
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.amount == 239390140000000
|
||||||
|
assert res.unknown_parameters == ['foo=bar', 'baz=quux'], res
|
||||||
|
res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&%20=%20')
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.amount == 239390140000000
|
||||||
|
assert res.unknown_parameters == ['%20=%20'], res
|
||||||
|
res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&unknown=' + quoted_utf8string[0])
|
||||||
|
assert res.uri.address == address
|
||||||
|
assert res.uri.amount == 239390140000000
|
||||||
|
assert res.unknown_parameters == [u'unknown=' + quoted_utf8string[0]], res
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
URITest().run_test()
|
|
@ -28,11 +28,10 @@
|
||||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
# 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.
|
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
"""Test address validation RPC calls
|
"""Test address validation RPC calls
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
from framework.wallet import Wallet
|
from framework.wallet import Wallet
|
||||||
|
|
||||||
class AddressValidationTest():
|
class AddressValidationTest():
|
||||||
|
|
|
@ -29,31 +29,54 @@
|
||||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
# 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.
|
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
"""Test transaction creation RPC calls
|
"""Test basic wallet functionality
|
||||||
|
|
||||||
Test the following RPCs:
|
|
||||||
- [TODO: many tests still need to be written]
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import errno
|
||||||
|
|
||||||
from framework.wallet import Wallet
|
from framework.wallet import Wallet
|
||||||
from framework.daemon import Daemon
|
from framework.daemon import Daemon
|
||||||
|
|
||||||
class WalletAddressTest():
|
class WalletTest():
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
self.reset()
|
self.reset()
|
||||||
self.create()
|
self.create()
|
||||||
self.check_main_address()
|
self.check_main_address()
|
||||||
self.check_keys()
|
self.check_keys()
|
||||||
self.create_subaddresses()
|
self.create_subaddresses()
|
||||||
|
self.tags()
|
||||||
|
self.attributes()
|
||||||
self.open_close()
|
self.open_close()
|
||||||
self.languages()
|
self.languages()
|
||||||
|
self.change_password()
|
||||||
|
self.store()
|
||||||
|
|
||||||
|
def remove_file(self, name):
|
||||||
|
WALLET_DIRECTORY = os.environ['WALLET_DIRECTORY']
|
||||||
|
assert WALLET_DIRECTORY != ''
|
||||||
|
try:
|
||||||
|
os.unlink(WALLET_DIRECTORY + '/' + name)
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno != errno.ENOENT:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def remove_wallet_files(self, name):
|
||||||
|
for suffix in ['', '.keys']:
|
||||||
|
self.remove_file(name + suffix)
|
||||||
|
|
||||||
|
def file_exists(self, name):
|
||||||
|
WALLET_DIRECTORY = os.environ['WALLET_DIRECTORY']
|
||||||
|
assert WALLET_DIRECTORY != ''
|
||||||
|
return os.path.isfile(WALLET_DIRECTORY + '/' + name)
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
print('Resetting blockchain')
|
print('Resetting blockchain')
|
||||||
daemon = Daemon()
|
daemon = Daemon()
|
||||||
daemon.pop_blocks(1000)
|
res = daemon.get_height()
|
||||||
|
daemon.pop_blocks(res.height - 1)
|
||||||
daemon.flush_txpool()
|
daemon.flush_txpool()
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
|
@ -158,6 +181,103 @@ class WalletAddressTest():
|
||||||
res = wallet.get_address_index('82pP87g1Vkd3LUMssBCumk3MfyEsFqLAaGDf6oxddu61EgSFzt8gCwUD4tr3kp9TUfdPs2CnpD7xLZzyC1Ei9UsW3oyCWDf')
|
res = wallet.get_address_index('82pP87g1Vkd3LUMssBCumk3MfyEsFqLAaGDf6oxddu61EgSFzt8gCwUD4tr3kp9TUfdPs2CnpD7xLZzyC1Ei9UsW3oyCWDf')
|
||||||
assert res.index == {'major': 1, 'minor': 0}
|
assert res.index == {'major': 1, 'minor': 0}
|
||||||
|
|
||||||
|
res = wallet.label_account(0, "main")
|
||||||
|
|
||||||
|
def tags(self):
|
||||||
|
print('Testing tags')
|
||||||
|
wallet = Wallet()
|
||||||
|
res = wallet.get_account_tags()
|
||||||
|
assert not 'account_tags' in res or len(res.account_tags) == 0
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.get_accounts('tag')
|
||||||
|
except: ok = True
|
||||||
|
assert ok or not 'subaddress_accounts' in res or res.subaddress_accounts == 0
|
||||||
|
wallet.tag_accounts('tag0', [1])
|
||||||
|
res = wallet.get_account_tags()
|
||||||
|
assert len(res.account_tags) == 1
|
||||||
|
assert res.account_tags[0].tag == 'tag0'
|
||||||
|
assert res.account_tags[0].label == ''
|
||||||
|
assert res.account_tags[0].accounts == [1]
|
||||||
|
res = wallet.get_accounts('tag0')
|
||||||
|
assert len(res.subaddress_accounts) == 1
|
||||||
|
assert res.subaddress_accounts[0].account_index == 1
|
||||||
|
assert res.subaddress_accounts[0].base_address == '82pP87g1Vkd3LUMssBCumk3MfyEsFqLAaGDf6oxddu61EgSFzt8gCwUD4tr3kp9TUfdPs2CnpD7xLZzyC1Ei9UsW3oyCWDf'
|
||||||
|
assert res.subaddress_accounts[0].balance == 0
|
||||||
|
assert res.subaddress_accounts[0].unlocked_balance == 0
|
||||||
|
assert res.subaddress_accounts[0].label == 'idx1_new'
|
||||||
|
assert res.subaddress_accounts[0].tag == 'tag0'
|
||||||
|
wallet.untag_accounts([0])
|
||||||
|
res = wallet.get_account_tags()
|
||||||
|
assert len(res.account_tags) == 1
|
||||||
|
assert res.account_tags[0].tag == 'tag0'
|
||||||
|
assert res.account_tags[0].label == ''
|
||||||
|
assert res.account_tags[0].accounts == [1]
|
||||||
|
wallet.untag_accounts([1])
|
||||||
|
res = wallet.get_account_tags()
|
||||||
|
assert not 'account_tags' in res or len(res.account_tags) == 0
|
||||||
|
wallet.tag_accounts('tag0', [0])
|
||||||
|
wallet.tag_accounts('tag1', [1])
|
||||||
|
res = wallet.get_account_tags()
|
||||||
|
assert len(res.account_tags) == 2
|
||||||
|
x = [x for x in res.account_tags if x.tag == 'tag0']
|
||||||
|
assert len(x) == 1
|
||||||
|
assert x[0].tag == 'tag0'
|
||||||
|
assert x[0].label == ''
|
||||||
|
assert x[0].accounts == [0]
|
||||||
|
x = [x for x in res.account_tags if x.tag == 'tag1']
|
||||||
|
assert len(x) == 1
|
||||||
|
assert x[0].tag == 'tag1'
|
||||||
|
assert x[0].label == ''
|
||||||
|
assert x[0].accounts == [1]
|
||||||
|
wallet.tag_accounts('tagA', [0, 1])
|
||||||
|
res = wallet.get_account_tags()
|
||||||
|
assert len(res.account_tags) == 1
|
||||||
|
assert res.account_tags[0].tag == 'tagA'
|
||||||
|
assert res.account_tags[0].label == ''
|
||||||
|
assert res.account_tags[0].accounts == [0, 1]
|
||||||
|
wallet.tag_accounts('tagB', [1, 0])
|
||||||
|
res = wallet.get_account_tags()
|
||||||
|
assert len(res.account_tags) == 1
|
||||||
|
assert res.account_tags[0].tag == 'tagB'
|
||||||
|
assert res.account_tags[0].label == ''
|
||||||
|
assert res.account_tags[0].accounts == [0, 1]
|
||||||
|
wallet.set_account_tag_description('tagB', 'tag B')
|
||||||
|
res = wallet.get_account_tags()
|
||||||
|
assert len(res.account_tags) == 1
|
||||||
|
assert res.account_tags[0].tag == 'tagB'
|
||||||
|
assert res.account_tags[0].label == 'tag B'
|
||||||
|
assert res.account_tags[0].accounts == [0, 1]
|
||||||
|
res = wallet.get_accounts('tagB')
|
||||||
|
assert len(res.subaddress_accounts) == 2
|
||||||
|
subaddress_accounts = []
|
||||||
|
for x in res.subaddress_accounts:
|
||||||
|
assert x.balance == 0
|
||||||
|
assert x.unlocked_balance == 0
|
||||||
|
subaddress_accounts.append((x.account_index, x.base_address, x.label))
|
||||||
|
assert sorted(subaddress_accounts) == [(0, '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'main'), (1, '82pP87g1Vkd3LUMssBCumk3MfyEsFqLAaGDf6oxddu61EgSFzt8gCwUD4tr3kp9TUfdPs2CnpD7xLZzyC1Ei9UsW3oyCWDf', 'idx1_new')]
|
||||||
|
|
||||||
|
def attributes(self):
|
||||||
|
print('Testing attributes')
|
||||||
|
wallet = Wallet()
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.get_attribute('foo')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
res = wallet.set_attribute('foo', 'bar')
|
||||||
|
res = wallet.get_attribute('foo')
|
||||||
|
assert res.value == 'bar'
|
||||||
|
res = wallet.set_attribute('foo', 'いっしゅん')
|
||||||
|
res = wallet.get_attribute('foo')
|
||||||
|
assert res.value == u'いっしゅん'
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.get_attribute('いちりゅう')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
res = wallet.set_attribute('いちりゅう', 'いっぽう')
|
||||||
|
res = wallet.get_attribute('いちりゅう')
|
||||||
|
assert res.value == u'いっぽう'
|
||||||
|
|
||||||
def open_close(self):
|
def open_close(self):
|
||||||
print('Testing open/close')
|
print('Testing open/close')
|
||||||
wallet = Wallet()
|
wallet = Wallet()
|
||||||
|
@ -200,11 +320,72 @@ class WalletAddressTest():
|
||||||
languages = res.languages
|
languages = res.languages
|
||||||
languages_local = res.languages_local
|
languages_local = res.languages_local
|
||||||
for language in languages + languages_local:
|
for language in languages + languages_local:
|
||||||
print('Creating ' + language.encode('utf8') + ' wallet')
|
sys.stdout.write('Creating ' + language + ' wallet\n')
|
||||||
wallet.create_wallet(filename = '', language = language)
|
wallet.create_wallet(filename = '', language = language)
|
||||||
res = wallet.query_key('mnemonic')
|
res = wallet.query_key('mnemonic')
|
||||||
wallet.close_wallet()
|
wallet.close_wallet()
|
||||||
|
|
||||||
|
def change_password(self):
|
||||||
|
print('Testing password change')
|
||||||
|
wallet = Wallet()
|
||||||
|
|
||||||
|
# close the wallet if any, will throw if none is loaded
|
||||||
|
try: wallet.close_wallet()
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
self.remove_wallet_files('test1')
|
||||||
|
|
||||||
|
seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted'
|
||||||
|
res = wallet.restore_deterministic_wallet(seed = seed, filename = 'test1')
|
||||||
|
assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert res.seed == seed
|
||||||
|
|
||||||
|
wallet.close_wallet()
|
||||||
|
res = wallet.open_wallet('test1', password = '')
|
||||||
|
res = wallet.get_address()
|
||||||
|
assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
|
||||||
|
res = wallet.change_wallet_password(old_password = '', new_password = 'foo')
|
||||||
|
wallet.close_wallet()
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
try: res = wallet.open_wallet('test1', password = '')
|
||||||
|
except: ok = True
|
||||||
|
assert ok
|
||||||
|
|
||||||
|
res = wallet.open_wallet('test1', password = 'foo')
|
||||||
|
res = wallet.get_address()
|
||||||
|
assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
|
||||||
|
wallet.close_wallet()
|
||||||
|
|
||||||
|
self.remove_wallet_files('test1')
|
||||||
|
|
||||||
|
def store(self):
|
||||||
|
print('Testing store')
|
||||||
|
wallet = Wallet()
|
||||||
|
|
||||||
|
# close the wallet if any, will throw if none is loaded
|
||||||
|
try: wallet.close_wallet()
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
self.remove_wallet_files('test1')
|
||||||
|
|
||||||
|
seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted'
|
||||||
|
res = wallet.restore_deterministic_wallet(seed = seed, filename = 'test1')
|
||||||
|
assert res.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
|
||||||
|
assert res.seed == seed
|
||||||
|
|
||||||
|
self.remove_file('test1')
|
||||||
|
assert self.file_exists('test1.keys')
|
||||||
|
assert not self.file_exists('test1')
|
||||||
|
wallet.store()
|
||||||
|
assert self.file_exists('test1.keys')
|
||||||
|
assert self.file_exists('test1')
|
||||||
|
|
||||||
|
wallet.close_wallet()
|
||||||
|
self.remove_wallet_files('test1')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
WalletAddressTest().run_test()
|
WalletTest().run_test()
|
|
@ -49,6 +49,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(getblocktemplate)
|
return self.rpc.send_json_rpc_request(getblocktemplate)
|
||||||
|
get_block_template = getblocktemplate
|
||||||
|
|
||||||
def send_raw_transaction(self, tx_as_hex, do_not_relay = False, do_sanity_checks = True):
|
def send_raw_transaction(self, tx_as_hex, do_not_relay = False, do_sanity_checks = True):
|
||||||
send_raw_transaction = {
|
send_raw_transaction = {
|
||||||
|
@ -57,6 +58,7 @@ class Daemon(object):
|
||||||
'do_sanity_checks': do_sanity_checks,
|
'do_sanity_checks': do_sanity_checks,
|
||||||
}
|
}
|
||||||
return self.rpc.send_request("/send_raw_transaction", send_raw_transaction)
|
return self.rpc.send_request("/send_raw_transaction", send_raw_transaction)
|
||||||
|
sendrawtransaction = send_raw_transaction
|
||||||
|
|
||||||
def submitblock(self, block):
|
def submitblock(self, block):
|
||||||
submitblock = {
|
submitblock = {
|
||||||
|
@ -66,6 +68,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(submitblock)
|
return self.rpc.send_json_rpc_request(submitblock)
|
||||||
|
submit_block = submitblock
|
||||||
|
|
||||||
def getblock(self, hash = '', height = 0, fill_pow_hash = False):
|
def getblock(self, hash = '', height = 0, fill_pow_hash = False):
|
||||||
getblock = {
|
getblock = {
|
||||||
|
@ -79,6 +82,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(getblock)
|
return self.rpc.send_json_rpc_request(getblock)
|
||||||
|
get_block = getblock
|
||||||
|
|
||||||
def getlastblockheader(self):
|
def getlastblockheader(self):
|
||||||
getlastblockheader = {
|
getlastblockheader = {
|
||||||
|
@ -89,6 +93,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(getlastblockheader)
|
return self.rpc.send_json_rpc_request(getlastblockheader)
|
||||||
|
get_last_block_header = getlastblockheader
|
||||||
|
|
||||||
def getblockheaderbyhash(self, hash = "", hashes = []):
|
def getblockheaderbyhash(self, hash = "", hashes = []):
|
||||||
getblockheaderbyhash = {
|
getblockheaderbyhash = {
|
||||||
|
@ -101,6 +106,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(getblockheaderbyhash)
|
return self.rpc.send_json_rpc_request(getblockheaderbyhash)
|
||||||
|
get_block_header_by_hash = getblockheaderbyhash
|
||||||
|
|
||||||
def getblockheaderbyheight(self, height):
|
def getblockheaderbyheight(self, height):
|
||||||
getblockheaderbyheight = {
|
getblockheaderbyheight = {
|
||||||
|
@ -112,6 +118,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(getblockheaderbyheight)
|
return self.rpc.send_json_rpc_request(getblockheaderbyheight)
|
||||||
|
get_block_header_by_height = getblockheaderbyheight
|
||||||
|
|
||||||
def getblockheadersrange(self, start_height, end_height, fill_pow_hash = False):
|
def getblockheadersrange(self, start_height, end_height, fill_pow_hash = False):
|
||||||
getblockheadersrange = {
|
getblockheadersrange = {
|
||||||
|
@ -125,6 +132,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(getblockheadersrange)
|
return self.rpc.send_json_rpc_request(getblockheadersrange)
|
||||||
|
get_block_headers_range = getblockheadersrange
|
||||||
|
|
||||||
def get_connections(self):
|
def get_connections(self):
|
||||||
get_connections = {
|
get_connections = {
|
||||||
|
@ -141,6 +149,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(get_info)
|
return self.rpc.send_json_rpc_request(get_info)
|
||||||
|
getinfo = get_info
|
||||||
|
|
||||||
def hard_fork_info(self):
|
def hard_fork_info(self):
|
||||||
hard_fork_info = {
|
hard_fork_info = {
|
||||||
|
@ -172,6 +181,7 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_request("/get_height", get_height)
|
return self.rpc.send_request("/get_height", get_height)
|
||||||
|
getheight = get_height
|
||||||
|
|
||||||
def pop_blocks(self, nblocks = 1):
|
def pop_blocks(self, nblocks = 1):
|
||||||
pop_blocks = {
|
pop_blocks = {
|
||||||
|
@ -208,6 +218,11 @@ class Daemon(object):
|
||||||
}
|
}
|
||||||
return self.rpc.send_request('/get_transaction_pool_hashes', get_transaction_pool_hashes)
|
return self.rpc.send_request('/get_transaction_pool_hashes', get_transaction_pool_hashes)
|
||||||
|
|
||||||
|
def get_transaction_pool_stats(self):
|
||||||
|
get_transaction_pool_stats = {
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/get_transaction_pool_stats', get_transaction_pool_stats)
|
||||||
|
|
||||||
def flush_txpool(self, txids = []):
|
def flush_txpool(self, txids = []):
|
||||||
flush_txpool = {
|
flush_txpool = {
|
||||||
'method': 'flush_txpool',
|
'method': 'flush_txpool',
|
||||||
|
@ -256,6 +271,7 @@ class Daemon(object):
|
||||||
'split': split,
|
'split': split,
|
||||||
}
|
}
|
||||||
return self.rpc.send_request('/get_transactions', get_transactions)
|
return self.rpc.send_request('/get_transactions', get_transactions)
|
||||||
|
gettransactions = get_transactions
|
||||||
|
|
||||||
def get_outs(self, outputs = [], get_txid = False):
|
def get_outs(self, outputs = [], get_txid = False):
|
||||||
get_outs = {
|
get_outs = {
|
||||||
|
@ -344,3 +360,141 @@ class Daemon(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(get_fee_estimate)
|
return self.rpc.send_json_rpc_request(get_fee_estimate)
|
||||||
|
|
||||||
|
def is_key_image_spent(self, key_images = []):
|
||||||
|
is_key_image_spent = {
|
||||||
|
'key_images': key_images,
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/is_key_image_spent', is_key_image_spent)
|
||||||
|
|
||||||
|
def save_bc(self):
|
||||||
|
save_bc = {
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/save_bc', save_bc)
|
||||||
|
|
||||||
|
def get_peer_list(self):
|
||||||
|
get_peer_list = {
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/get_peer_list', get_peer_list)
|
||||||
|
|
||||||
|
def set_log_hash_rate(self, visible):
|
||||||
|
set_log_hash_rate = {
|
||||||
|
'visible': visible,
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/set_log_hash_rate', set_log_hash_rate)
|
||||||
|
|
||||||
|
def stop_daemon(self):
|
||||||
|
stop_daemon = {
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/stop_daemon', stop_daemon)
|
||||||
|
|
||||||
|
def get_net_stats(self):
|
||||||
|
get_net_stats = {
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/get_net_stats', get_net_stats)
|
||||||
|
|
||||||
|
def get_limit(self):
|
||||||
|
get_limit = {
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/get_limit', get_limit)
|
||||||
|
|
||||||
|
def set_limit(self, limit_down, limit_up):
|
||||||
|
set_limit = {
|
||||||
|
'limit_down': limit_down,
|
||||||
|
'limit_up': limit_up,
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/set_limit', set_limit)
|
||||||
|
|
||||||
|
def out_peers(self, out_peers):
|
||||||
|
out_peers = {
|
||||||
|
'out_peers': out_peers,
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/out_peers', out_peers)
|
||||||
|
|
||||||
|
def in_peers(self, in_peers):
|
||||||
|
in_peers = {
|
||||||
|
'in_peers': in_peers,
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/in_peers', in_peers)
|
||||||
|
|
||||||
|
def update(self, command, path = None):
|
||||||
|
update = {
|
||||||
|
'command': command,
|
||||||
|
'path': path,
|
||||||
|
}
|
||||||
|
return self.rpc.send_request('/update', update)
|
||||||
|
|
||||||
|
def get_block_count(self):
|
||||||
|
get_block_count = {
|
||||||
|
'method': 'get_block_count',
|
||||||
|
'params': {
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_block_count)
|
||||||
|
getblockcount = get_block_count
|
||||||
|
|
||||||
|
def get_block_hash(self, height):
|
||||||
|
get_block_hash = {
|
||||||
|
'method': 'get_block_hash',
|
||||||
|
'params': [height],
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_block_hash)
|
||||||
|
on_get_block_hash = get_block_hash
|
||||||
|
on_getblockhash = get_block_hash
|
||||||
|
|
||||||
|
def relay_tx(self, txids = []):
|
||||||
|
relay_tx = {
|
||||||
|
'method': 'relay_tx',
|
||||||
|
'params': {
|
||||||
|
'txids': txids,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(relay_tx)
|
||||||
|
|
||||||
|
def sync_info(self):
|
||||||
|
sync_info = {
|
||||||
|
'method': 'sync_info',
|
||||||
|
'params': {
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(sync_info)
|
||||||
|
|
||||||
|
def get_txpool_backlog(self):
|
||||||
|
get_txpool_backlog = {
|
||||||
|
'method': 'get_txpool_backlog',
|
||||||
|
'params': {
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_txpool_backlog)
|
||||||
|
|
||||||
|
def prune_blockchain(self, check = False):
|
||||||
|
prune_blockchain = {
|
||||||
|
'method': 'prune_blockchain',
|
||||||
|
'params': {
|
||||||
|
'check': check,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(prune_blockchain)
|
||||||
|
|
||||||
|
def get_block_rate(self, seconds = [3600]):
|
||||||
|
get_block_rate = {
|
||||||
|
'method': 'get_block_rate',
|
||||||
|
'params': {
|
||||||
|
'seconds': seconds,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_block_rate)
|
||||||
|
|
|
@ -37,18 +37,6 @@ class Wallet(object):
|
||||||
self.port = port
|
self.port = port
|
||||||
self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else 18090+idx))
|
self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else 18090+idx))
|
||||||
|
|
||||||
def make_uniform_destinations(self, address, transfer_amount, transfer_number_of_destinations=1):
|
|
||||||
destinations = []
|
|
||||||
for i in range(transfer_number_of_destinations):
|
|
||||||
destinations.append({"amount":transfer_amount,"address":address})
|
|
||||||
return destinations
|
|
||||||
|
|
||||||
def make_destinations(self, addresses, transfer_amounts):
|
|
||||||
destinations = []
|
|
||||||
for i in range(len(addresses)):
|
|
||||||
destinations.append({'amount':transfer_amounts[i],'address':addresses[i]})
|
|
||||||
return destinations
|
|
||||||
|
|
||||||
def transfer(self, destinations, account_index = 0, subaddr_indices = [], priority = 0, ring_size = 0, unlock_time = 0, payment_id = '', get_tx_key = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
|
def transfer(self, destinations, account_index = 0, subaddr_indices = [], priority = 0, ring_size = 0, unlock_time = 0, payment_id = '', get_tx_key = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
|
||||||
transfer = {
|
transfer = {
|
||||||
'method': 'transfer',
|
'method': 'transfer',
|
||||||
|
@ -103,6 +91,17 @@ class Wallet(object):
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(get_transfer_by_txid)
|
return self.rpc.send_json_rpc_request(get_transfer_by_txid)
|
||||||
|
|
||||||
|
def get_payments(self, payment_id):
|
||||||
|
get_payments = {
|
||||||
|
'method': 'get_payments',
|
||||||
|
'params': {
|
||||||
|
'payment_id': payment_id,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_payments)
|
||||||
|
|
||||||
def get_bulk_payments(self, payment_ids = [], min_block_height = 0):
|
def get_bulk_payments(self, payment_ids = [], min_block_height = 0):
|
||||||
get_bulk_payments = {
|
get_bulk_payments = {
|
||||||
'method': 'get_bulk_payments',
|
'method': 'get_bulk_payments',
|
||||||
|
@ -153,14 +152,22 @@ class Wallet(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(get_balance)
|
return self.rpc.send_json_rpc_request(get_balance)
|
||||||
|
getbalance = get_balance
|
||||||
|
|
||||||
def sweep_dust(self):
|
def sweep_dust(self, get_tx_keys = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
|
||||||
sweep_dust = {
|
sweep_dust = {
|
||||||
'method': 'sweep_dust',
|
'method': 'sweep_dust',
|
||||||
|
'params': {
|
||||||
|
'get_tx_keys': get_tx_keys,
|
||||||
|
'do_not_relay': do_not_relay,
|
||||||
|
'get_tx_hex': get_tx_hex,
|
||||||
|
'get_tx_metadata': get_tx_metadata,
|
||||||
|
},
|
||||||
'jsonrpc': '2.0',
|
'jsonrpc': '2.0',
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(sweep_dust)
|
return self.rpc.send_json_rpc_request(sweep_dust)
|
||||||
|
sweep_unmixable = sweep_dust
|
||||||
|
|
||||||
def sweep_all(self, address = '', account_index = 0, subaddr_indices = [], priority = 0, ring_size = 0, outputs = 1, unlock_time = 0, payment_id = '', get_tx_keys = False, below_amount = 0, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
|
def sweep_all(self, address = '', account_index = 0, subaddr_indices = [], priority = 0, ring_size = 0, outputs = 1, unlock_time = 0, payment_id = '', get_tx_keys = False, below_amount = 0, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
|
||||||
sweep_all = {
|
sweep_all = {
|
||||||
|
@ -217,6 +224,7 @@ class Wallet(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(get_address)
|
return self.rpc.send_json_rpc_request(get_address)
|
||||||
|
getaddress = get_address
|
||||||
|
|
||||||
def create_account(self, label = ""):
|
def create_account(self, label = ""):
|
||||||
create_account = {
|
create_account = {
|
||||||
|
@ -345,6 +353,34 @@ class Wallet(object):
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(close_wallet)
|
return self.rpc.send_json_rpc_request(close_wallet)
|
||||||
|
|
||||||
|
def change_wallet_password(self, old_password, new_password):
|
||||||
|
change_wallet_password = {
|
||||||
|
'method': 'change_wallet_password',
|
||||||
|
'params' : {
|
||||||
|
'old_password': old_password,
|
||||||
|
'new_password': new_password,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(change_wallet_password)
|
||||||
|
|
||||||
|
def store(self):
|
||||||
|
store = {
|
||||||
|
'method': 'store',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(store)
|
||||||
|
|
||||||
|
def stop_wallet(self):
|
||||||
|
stop_wallet = {
|
||||||
|
'method': 'stop_wallet',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(stop_wallet)
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
refresh = {
|
refresh = {
|
||||||
'method': 'refresh',
|
'method': 'refresh',
|
||||||
|
@ -475,6 +511,18 @@ class Wallet(object):
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(make_multisig)
|
return self.rpc.send_json_rpc_request(make_multisig)
|
||||||
|
|
||||||
|
def finalize_multisig(self, multisig_info, password = ''):
|
||||||
|
finalize_multisig = {
|
||||||
|
'method': 'finalize_multisig',
|
||||||
|
'params' : {
|
||||||
|
'multisig_info': multisig_info,
|
||||||
|
'password': password,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(finalize_multisig)
|
||||||
|
|
||||||
def exchange_multisig_keys(self, multisig_info, password = ''):
|
def exchange_multisig_keys(self, multisig_info, password = ''):
|
||||||
exchange_multisig_keys = {
|
exchange_multisig_keys = {
|
||||||
'method': 'exchange_multisig_keys',
|
'method': 'exchange_multisig_keys',
|
||||||
|
@ -605,6 +653,31 @@ class Wallet(object):
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(check_tx_proof)
|
return self.rpc.send_json_rpc_request(check_tx_proof)
|
||||||
|
|
||||||
|
def get_spend_proof(self, txid = '', message = ''):
|
||||||
|
get_spend_proof = {
|
||||||
|
'method': 'get_spend_proof',
|
||||||
|
'params' : {
|
||||||
|
'txid': txid,
|
||||||
|
'message': message,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_spend_proof)
|
||||||
|
|
||||||
|
def check_spend_proof(self, txid = '', message = '', signature = ''):
|
||||||
|
check_spend_proof = {
|
||||||
|
'method': 'check_spend_proof',
|
||||||
|
'params' : {
|
||||||
|
'txid': txid,
|
||||||
|
'message': message,
|
||||||
|
'signature': signature,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(check_spend_proof)
|
||||||
|
|
||||||
def get_reserve_proof(self, all_ = True, account_index = 0, amount = 0, message = ''):
|
def get_reserve_proof(self, all_ = True, account_index = 0, amount = 0, message = ''):
|
||||||
get_reserve_proof = {
|
get_reserve_proof = {
|
||||||
'method': 'get_reserve_proof',
|
'method': 'get_reserve_proof',
|
||||||
|
@ -663,6 +736,7 @@ class Wallet(object):
|
||||||
'id': '0'
|
'id': '0'
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(get_height)
|
return self.rpc.send_json_rpc_request(get_height)
|
||||||
|
getheight = get_height
|
||||||
|
|
||||||
def relay_tx(self, hex_):
|
def relay_tx(self, hex_):
|
||||||
relay_tx = {
|
relay_tx = {
|
||||||
|
@ -764,6 +838,230 @@ class Wallet(object):
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(validate_address)
|
return self.rpc.send_json_rpc_request(validate_address)
|
||||||
|
|
||||||
|
def get_accounts(self, tag):
|
||||||
|
get_accounts = {
|
||||||
|
'method': 'get_accounts',
|
||||||
|
'params': {
|
||||||
|
'tag': tag,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_accounts)
|
||||||
|
|
||||||
|
def get_account_tags(self):
|
||||||
|
get_account_tags = {
|
||||||
|
'method': 'get_account_tags',
|
||||||
|
'params': {
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_account_tags)
|
||||||
|
|
||||||
|
def tag_accounts(self, tag, accounts = []):
|
||||||
|
tag_accounts = {
|
||||||
|
'method': 'tag_accounts',
|
||||||
|
'params': {
|
||||||
|
'tag': tag,
|
||||||
|
'accounts': accounts,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(tag_accounts)
|
||||||
|
|
||||||
|
def untag_accounts(self, accounts = []):
|
||||||
|
untag_accounts = {
|
||||||
|
'method': 'untag_accounts',
|
||||||
|
'params': {
|
||||||
|
'accounts': accounts,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(untag_accounts)
|
||||||
|
|
||||||
|
def set_account_tag_description(self, tag, description):
|
||||||
|
set_account_tag_description = {
|
||||||
|
'method': 'set_account_tag_description',
|
||||||
|
'params': {
|
||||||
|
'tag': tag,
|
||||||
|
'description': description,
|
||||||
|
},
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(set_account_tag_description)
|
||||||
|
|
||||||
|
def rescan_blockchain(self, hard = False):
|
||||||
|
rescan_blockchain = {
|
||||||
|
'method': 'rescan_blockchain',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'hard': hard,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(rescan_blockchain)
|
||||||
|
|
||||||
|
def rescan_spent(self):
|
||||||
|
rescan_spent = {
|
||||||
|
'method': 'rescan_spent',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(rescan_spent)
|
||||||
|
|
||||||
|
def set_tx_notes(self, txids = [], notes = []):
|
||||||
|
set_tx_notes = {
|
||||||
|
'method': 'set_tx_notes',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'txids': txids,
|
||||||
|
'notes': notes,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(set_tx_notes)
|
||||||
|
|
||||||
|
def get_tx_notes(self, txids = []):
|
||||||
|
get_tx_notes = {
|
||||||
|
'method': 'get_tx_notes',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'txids': txids,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_tx_notes)
|
||||||
|
|
||||||
|
def set_attribute(self, key, value):
|
||||||
|
set_attribute = {
|
||||||
|
'method': 'set_attribute',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'key': key,
|
||||||
|
'value': value,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(set_attribute)
|
||||||
|
|
||||||
|
def get_attribute(self, key):
|
||||||
|
get_attribute = {
|
||||||
|
'method': 'get_attribute',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'key': key,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_attribute)
|
||||||
|
|
||||||
|
def make_uri(self, address = '', payment_id = '', amount = 0, tx_description = '', recipient_name = ''):
|
||||||
|
make_uri = {
|
||||||
|
'method': 'make_uri',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'address': address,
|
||||||
|
'payment_id': payment_id,
|
||||||
|
'amount': amount,
|
||||||
|
'tx_description': tx_description,
|
||||||
|
'recipient_name': recipient_name,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(make_uri)
|
||||||
|
|
||||||
|
def parse_uri(self, uri):
|
||||||
|
parse_uri = {
|
||||||
|
'method': 'parse_uri',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'uri': uri,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(parse_uri)
|
||||||
|
|
||||||
|
def add_address_book(self, address = '', payment_id = '', description = ''):
|
||||||
|
add_address_book = {
|
||||||
|
'method': 'add_address_book',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'address': address,
|
||||||
|
'payment_id': payment_id,
|
||||||
|
'description': description,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(add_address_book)
|
||||||
|
|
||||||
|
def edit_address_book(self, index, address = None, payment_id = None, description = None):
|
||||||
|
edit_address_book = {
|
||||||
|
'method': 'edit_address_book',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'index': index,
|
||||||
|
'set_address': address != None,
|
||||||
|
'address': address or '',
|
||||||
|
'set_payment_id': payment_id != None,
|
||||||
|
'payment_id': payment_id or '',
|
||||||
|
'set_description': description != None,
|
||||||
|
'description': description or '',
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(edit_address_book)
|
||||||
|
|
||||||
|
def get_address_book(self, entries = []):
|
||||||
|
get_address_book = {
|
||||||
|
'method': 'get_address_book',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'entries': entries,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(get_address_book)
|
||||||
|
|
||||||
|
def delete_address_book(self, index):
|
||||||
|
delete_address_book = {
|
||||||
|
'method': 'delete_address_book',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'index': index,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(delete_address_book)
|
||||||
|
|
||||||
|
def start_mining(self, threads_count, do_background_mining = False, ignore_battery = False):
|
||||||
|
start_mining = {
|
||||||
|
'method': 'start_mining',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
'threads_count': threads_count,
|
||||||
|
'do_background_mining': do_background_mining,
|
||||||
|
'ignore_battery': ignore_battery,
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(start_mining)
|
||||||
|
|
||||||
|
def stop_mining(self):
|
||||||
|
stop_mining = {
|
||||||
|
'method': 'stop_mining',
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'params': {
|
||||||
|
},
|
||||||
|
'id': '0'
|
||||||
|
}
|
||||||
|
return self.rpc.send_json_rpc_request(stop_mining)
|
||||||
|
|
||||||
def get_version(self):
|
def get_version(self):
|
||||||
get_version = {
|
get_version = {
|
||||||
'method': 'get_version',
|
'method': 'get_version',
|
||||||
|
|
Loading…
Reference in New Issue