aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--contrib/epee/include/storages/portable_storage_from_json.h1
-rw-r--r--contrib/gitian/README.md3
-rwxr-xr-xcontrib/gitian/gitian-build.py6
-rw-r--r--external/boost/archive/portable_binary_archive.hpp3
-rw-r--r--external/db_drivers/liblmdb/mdb.c58
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp40
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h1
-rw-r--r--src/common/util.cpp19
-rw-r--r--src/common/util.h20
-rw-r--r--src/cryptonote_basic/account.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp8
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h18
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl62
-rw-r--r--src/p2p/net_node.inl18
-rw-r--r--src/simplewallet/simplewallet.cpp57
-rw-r--r--src/simplewallet/simplewallet.h1
-rw-r--r--src/wallet/api/wallet.cpp36
-rw-r--r--src/wallet/api/wallet.h1
-rw-r--r--src/wallet/api/wallet2_api.h7
-rw-r--r--src/wallet/wallet2.cpp23
-rw-r--r--src/wallet/wallet2.h3
-rw-r--r--src/wallet/wallet_rpc_server.cpp33
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h3
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h1
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/data/sha256sum/CLSAG.pdfbin0 -> 374754 bytes
-rw-r--r--tests/data/sha256sum/empty.txt0
-rw-r--r--tests/data/sha256sum/small_file.txt19
-rwxr-xr-xtests/functional_tests/multisig.py10
-rw-r--r--tests/unit_tests/node_server.cpp4
-rw-r--r--tests/unit_tests/sha256.cpp22
-rw-r--r--utils/build_scripts/windows.bat45
-rw-r--r--utils/python-rpc/framework/wallet.py3
34 files changed, 376 insertions, 158 deletions
diff --git a/.gitignore b/.gitignore
index a39168ac5..9f62575e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,12 @@ external/miniupnpc/Makefile
miniupnpcstrings.h
version/
ClangBuildAnalyzerSession.txt
+
+# gitian
+contrib/gitian/builder/
+contrib/gitian/docker/
+contrib/gitian/sigs/
+
# Created by https://www.gitignore.io
### C++ ###
diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h
index 3021598f5..69192ca6b 100644
--- a/contrib/epee/include/storages/portable_storage_from_json.h
+++ b/contrib/epee/include/storages/portable_storage_from_json.h
@@ -51,7 +51,6 @@ namespace epee
{
CHECK_AND_ASSERT_THROW_MES(recursion < EPEE_JSON_RECURSION_LIMIT_INTERNAL, "Wrong JSON data: recursion limitation (" << EPEE_JSON_RECURSION_LIMIT_INTERNAL << ") exceeded");
- std::string::const_iterator sub_element_start;
std::string name;
typename t_storage::harray h_array = nullptr;
enum match_state
diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md
index 9852b07ba..24cf26fa3 100644
--- a/contrib/gitian/README.md
+++ b/contrib/gitian/README.md
@@ -133,10 +133,11 @@ Common setup part:
su - gitianuser
GH_USER=YOUR_GITHUB_USER_NAME
-VERSION=v0.17.2.0
+VERSION=v0.17.3.2
```
Where `GH_USER` is your GitHub user name and `VERSION` is the version tag you want to build.
+The `gitian-build.py`'s `--setup` switch will also refresh the environment of any stale files and submodules.
Setup for LXC:
diff --git a/contrib/gitian/gitian-build.py b/contrib/gitian/gitian-build.py
index 859c2c645..859f460a7 100755
--- a/contrib/gitian/gitian-build.py
+++ b/contrib/gitian/gitian-build.py
@@ -31,8 +31,10 @@ def setup():
subprocess.check_call(['git', 'checkout', 'c0f77ca018cb5332bfd595e0aff0468f77542c23'])
os.makedirs('inputs', exist_ok=True)
os.chdir('inputs')
- if not os.path.isdir('monero'):
- subprocess.check_call(['git', 'clone', args.url, 'monero'])
+ if os.path.isdir('monero'):
+ # Remove the potentially stale monero dir. Otherwise you might face submodule mismatches.
+ subprocess.check_call(['rm', 'monero', '-fR'])
+ subprocess.check_call(['git', 'clone', args.url, 'monero'])
os.chdir('..')
make_image_prog = ['bin/make-base-vm', '--suite', 'bionic', '--arch', 'amd64']
if args.docker:
diff --git a/external/boost/archive/portable_binary_archive.hpp b/external/boost/archive/portable_binary_archive.hpp
index 7ae01a225..cdbd38aad 100644
--- a/external/boost/archive/portable_binary_archive.hpp
+++ b/external/boost/archive/portable_binary_archive.hpp
@@ -44,9 +44,12 @@ reverse_bytes(signed char size, char *address){
char * first = address;
char * last = first + size - 1;
for(;first < last;++first, --last){
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow="
char x = *last;
*last = *first;
*first = x;
+#pragma GCC diagnostic pop
}
}
diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c
index 6314d5775..bf60c7013 100644
--- a/external/db_drivers/liblmdb/mdb.c
+++ b/external/db_drivers/liblmdb/mdb.c
@@ -1467,6 +1467,8 @@ struct MDB_env {
#endif
/** Failed to update the meta page. Probably an I/O error. */
#define MDB_FATAL_ERROR 0x80000000U
+ /** using a raw block device */
+#define MDB_RAWPART 0x40000000U
/** Some fields are initialized. */
#define MDB_ENV_ACTIVE 0x20000000U
/** me_txkey is set */
@@ -4038,6 +4040,8 @@ fail:
return rc;
}
+static int ESECT mdb_env_map(MDB_env *env, void *addr);
+
/** Read the environment parameters of a DB environment before
* mapping it into memory.
* @param[in] env the environment handle
@@ -4054,6 +4058,31 @@ mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta)
int i, rc, off;
enum { Size = sizeof(pbuf) };
+ if (env->me_flags & MDB_RAWPART) {
+#define VM_ALIGN 0x200000
+ env->me_mapsize += VM_ALIGN-1;
+ env->me_mapsize &= ~(VM_ALIGN-1);
+ env->me_psize = env->me_os_psize;
+ rc = mdb_env_map(env, NULL);
+ if (rc) {
+ DPRINTF(("mdb_env_map: %s", mdb_strerror(rc)));
+ return rc;
+ }
+ p = (MDB_page *)env->me_map;
+ for (i=0; i<NUM_METAS; i++) {
+ if (!F_ISSET(p->mp_flags, P_META))
+ return ENOENT;
+ if (env->me_metas[i]->mm_magic != MDB_MAGIC)
+ return MDB_INVALID;
+ if (env->me_metas[i]->mm_version != MDB_DATA_VERSION)
+ return MDB_VERSION_MISMATCH;
+ if (i == 0 || env->me_metas[i]->mm_txnid > meta->mm_txnid)
+ *meta = *env->me_metas[i];
+ p = (MDB_page *)((char *)p + env->me_psize);
+ }
+ return 0;
+ }
+
/* We don't know the page size yet, so use a minimum value.
* Read both meta pages so we can use the latest one.
*/
@@ -4081,6 +4110,8 @@ mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta)
p = (MDB_page *)&pbuf;
if (!F_ISSET(p->mp_flags, P_META)) {
+ if (env->me_flags & MDB_RAWPART)
+ return ENOENT;
DPRINTF(("page %"Yu" not a meta page", p->mp_pgno));
return MDB_INVALID;
}
@@ -4148,6 +4179,18 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta)
psize = env->me_psize;
+ if ((env->me_flags & (MDB_RAWPART|MDB_WRITEMAP)) == (MDB_RAWPART|MDB_WRITEMAP)) {
+ p = (MDB_page *)env->me_map;
+ p->mp_pgno = 0;
+ p->mp_flags = P_META;
+ *(MDB_meta *)METADATA(p) = *meta;
+ q = (MDB_page *)((char *)p + psize);
+ q->mp_pgno = 1;
+ q->mp_flags = P_META;
+ *(MDB_meta *)METADATA(q) = *meta;
+ return 0;
+ }
+
p = calloc(NUM_METAS, psize);
if (!p)
return ENOMEM;
@@ -4410,7 +4453,7 @@ mdb_env_map(MDB_env *env, void *addr)
int prot = PROT_READ;
if (flags & MDB_WRITEMAP) {
prot |= PROT_WRITE;
- if (ftruncate(env->me_fd, env->me_mapsize) < 0)
+ if (!(flags & MDB_RAWPART) && ftruncate(env->me_fd, env->me_mapsize) < 0)
return ErrCode();
}
env->me_map = mmap(addr, env->me_mapsize, prot, MAP_SHARED,
@@ -5449,6 +5492,17 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
goto leave;
#endif
#endif
+#ifndef _WIN32
+ {
+ struct stat st;
+ flags &= ~MDB_RAWPART;
+ if (!stat(path, &st) && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) {
+ flags |= MDB_RAWPART | MDB_NOSUBDIR;
+ if (!env->me_mapsize)
+ env->me_mapsize = DEFAULT_MAPSIZE;
+ }
+ }
+#endif
flags |= MDB_ENV_ACTIVE; /* tell mdb_env_close0() to clean up */
if (flags & MDB_RDONLY) {
@@ -7668,7 +7722,7 @@ more:
offset *= 4; /* space for 4 more */
break;
}
- /* FALLTHRU: Big enough MDB_DUPFIXED sub-page */
+ /* FALLTHRU *//* Big enough MDB_DUPFIXED sub-page */
case MDB_CURRENT:
fp->mp_flags |= P_DIRTY;
COPY_PGNO(fp->mp_pgno, mp->mp_pgno);
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index e2ac9df0b..db7fa6c7c 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -25,13 +25,6 @@
// 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.
-#ifndef _WIN32
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#endif
-
#include "db_lmdb.h"
#include <boost/filesystem.hpp>
@@ -1303,26 +1296,6 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB()
m_hardfork = nullptr;
}
-void BlockchainLMDB::check_mmap_support()
-{
-#ifndef _WIN32
- const boost::filesystem::path mmap_test_file = m_folder / boost::filesystem::unique_path();
- int mmap_test_fd = ::open(mmap_test_file.string().c_str(), O_RDWR | O_CREAT, 0600);
- if (mmap_test_fd < 0)
- throw0(DB_ERROR((std::string("Failed to check for mmap support: open failed: ") + strerror(errno)).c_str()));
- epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([mmap_test_fd, &mmap_test_file]() {
- ::close(mmap_test_fd);
- boost::filesystem::remove(mmap_test_file.string());
- });
- if (write(mmap_test_fd, "mmaptest", 8) != 8)
- throw0(DB_ERROR((std::string("Failed to check for mmap support: write failed: ") + strerror(errno)).c_str()));
- void *mmap_res = mmap(NULL, 8, PROT_READ, MAP_SHARED, mmap_test_fd, 0);
- if (mmap_res == MAP_FAILED)
- throw0(DB_ERROR("This filesystem does not support mmap: use --data-dir to place the blockchain on a filesystem which does"));
- munmap(mmap_res, 8);
-#endif
-}
-
void BlockchainLMDB::open(const std::string& filename, const int db_flags)
{
int result;
@@ -1334,14 +1307,8 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
throw0(DB_OPEN_FAILURE("Attempted to open db, but it's already open"));
boost::filesystem::path direc(filename);
- if (boost::filesystem::exists(direc))
- {
- if (!boost::filesystem::is_directory(direc))
- throw0(DB_OPEN_FAILURE("LMDB needs a directory path, but a file was passed"));
- }
- else
- {
- if (!boost::filesystem::create_directories(direc))
+ if (!boost::filesystem::exists(direc) &&
+ !boost::filesystem::create_directories(direc)) {
throw0(DB_OPEN_FAILURE(std::string("Failed to create directory ").append(filename).c_str()));
}
@@ -1364,9 +1331,6 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
m_folder = filename;
- try { check_mmap_support(); }
- catch(...) { MERROR("Failed to check for mmap support, proceeding"); }
-
#ifdef __OpenBSD__
if ((mdb_flags & MDB_WRITEMAP) == 0) {
MCLOG_RED(el::Level::Info, "global", "Running on OpenBSD: forcing WRITEMAP");
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 20edab2e9..bdae44948 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -359,7 +359,6 @@ public:
static int compare_string(const MDB_val *a, const MDB_val *b);
private:
- void check_mmap_support();
void do_resize(uint64_t size_increase=0);
bool need_resize(uint64_t threshold_size=0) const;
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 89dcf4fef..f0de73a06 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -85,7 +85,7 @@ using namespace epee;
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <boost/format.hpp>
-#include <openssl/sha.h>
+#include <openssl/evp.h>
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "util"
@@ -941,14 +941,7 @@ std::string get_nix_version_display_string()
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash)
{
- SHA256_CTX ctx;
- if (!SHA256_Init(&ctx))
- return false;
- if (!SHA256_Update(&ctx, data, len))
- return false;
- if (!SHA256_Final((unsigned char*)hash.data, &ctx))
- return false;
- return true;
+ return EVP_Digest(data, len, (unsigned char*) hash.data, NULL, EVP_sha256(), NULL) != 0;
}
bool sha256sum(const std::string &filename, crypto::hash &hash)
@@ -961,8 +954,8 @@ std::string get_nix_version_display_string()
if (!f)
return false;
std::ifstream::pos_type file_size = f.tellg();
- SHA256_CTX ctx;
- if (!SHA256_Init(&ctx))
+ std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> ctx(EVP_MD_CTX_new(), &EVP_MD_CTX_free);
+ if (!EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr))
return false;
size_t size_left = file_size;
f.seekg(0, std::ios::beg);
@@ -973,12 +966,12 @@ std::string get_nix_version_display_string()
f.read(buf, read_size);
if (!f || !f.good())
return false;
- if (!SHA256_Update(&ctx, buf, read_size))
+ if (!EVP_DigestUpdate(ctx.get(), buf, read_size))
return false;
size_left -= read_size;
}
f.close();
- if (!SHA256_Final((unsigned char*)hash.data, &ctx))
+ if (!EVP_DigestFinal_ex(ctx.get(), (unsigned char*)hash.data, nullptr))
return false;
return true;
}
diff --git a/src/common/util.h b/src/common/util.h
index 25f5ceb47..f489594e8 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -231,7 +231,27 @@ namespace tools
bool is_privacy_preserving_network(const std::string &address);
int vercmp(const char *v0, const char *v1); // returns < 0, 0, > 0, similar to strcmp, but more human friendly than lexical - does not attempt to validate
+ /**
+ * \brief Creates a SHA-256 digest of a data buffer
+ *
+ * \param[in] data pointer to the buffer
+ * \param[in] len size of the buffer in bytes
+ * \param[out] hash where message digest will be written to
+ *
+ * \returns true if successful, false otherwise
+ */
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash);
+
+ /**
+ * \brief Creates a SHA-256 digest of a file's contents, equivalent to the sha256sum command in Linux
+ *
+ * \param[in] filename path to target file
+ * \param[out] hash where message digest will be written to
+ *
+ * \returns true if successful, false if the file can not be opened or there is an OpenSSL failure
+ *
+ * \throws ios_base::failure if after the file is successfully opened, an error occurs during reading
+ */
bool sha256sum(const std::string &filename, crypto::hash &hash);
boost::optional<bool> is_hdd(const char *path);
diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h
index 6e887db6d..2ee9545d4 100644
--- a/src/cryptonote_basic/account.h
+++ b/src/cryptonote_basic/account.h
@@ -55,8 +55,6 @@ namespace cryptonote
KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv)
END_KV_SERIALIZE_MAP()
- account_keys& operator=(account_keys const&) = default;
-
void encrypt(const crypto::chacha_key &key);
void decrypt(const crypto::chacha_key &key);
void encrypt_viewkey(const crypto::chacha_key &key);
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index c27261860..a68da0e62 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -97,9 +97,9 @@ namespace cryptonote
constexpr const std::chrono::seconds forward_delay_average{CRYPTONOTE_FORWARD_DELAY_AVERAGE};
// a kind of increasing backoff within min/max bounds
- uint64_t get_relay_delay(time_t now, time_t received)
+ uint64_t get_relay_delay(time_t last_relay, time_t received)
{
- time_t d = (now - received + MIN_RELAY_TIME) / MIN_RELAY_TIME * MIN_RELAY_TIME;
+ time_t d = (last_relay - received + MIN_RELAY_TIME) / MIN_RELAY_TIME * MIN_RELAY_TIME;
if (d > MAX_RELAY_TIME)
d = MAX_RELAY_TIME;
return d;
@@ -779,7 +779,7 @@ namespace cryptonote
case relay_method::local:
case relay_method::fluff:
case relay_method::block:
- if (now - meta.last_relayed_time <= get_relay_delay(now, meta.receive_time))
+ if (now - meta.last_relayed_time <= get_relay_delay(meta.last_relayed_time, meta.receive_time))
return true; // continue to next tx
break;
}
@@ -812,7 +812,7 @@ namespace cryptonote
function is only called every ~2 minutes, so this resetting should be
unnecessary, but is primarily a precaution against potential changes
to the callback routines. */
- elem.second.last_relayed_time = now + get_relay_delay(now, elem.second.receive_time);
+ elem.second.last_relayed_time = now + get_relay_delay(elem.second.last_relayed_time, elem.second.receive_time);
m_blockchain.update_txpool_tx(elem.first, elem.second);
}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index a1e4df563..515b78c94 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -113,12 +113,23 @@ namespace cryptonote
const block_queue &get_block_queue() const { return m_block_queue; }
void stop();
void on_connection_close(cryptonote_connection_context &context);
- void set_max_out_peers(unsigned int max) { m_max_out_peers = max; }
+ void set_max_out_peers(epee::net_utils::zone zone, unsigned int max) { CRITICAL_REGION_LOCAL(m_max_out_peers_lock); m_max_out_peers[zone] = max; }
+ unsigned int get_max_out_peers(epee::net_utils::zone zone) const
+ {
+ CRITICAL_REGION_LOCAL(m_max_out_peers_lock);
+ const auto it = m_max_out_peers.find(zone);
+ if (it == m_max_out_peers.end())
+ {
+ MWARNING(epee::net_utils::zone_to_string(zone) << " max out peers not set, using default");
+ return P2P_DEFAULT_CONNECTIONS_COUNT;
+ }
+ return it->second;
+ }
bool no_sync() const { return m_no_sync; }
void set_no_sync(bool value) { m_no_sync = value; }
std::string get_peers_overview() const;
std::pair<uint32_t, uint32_t> get_next_needed_pruning_stripe() const;
- bool needs_new_sync_connections() const;
+ bool needs_new_sync_connections(epee::net_utils::zone zone) const;
bool is_busy_syncing();
private:
@@ -171,7 +182,8 @@ namespace cryptonote
epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
epee::math_helper::once_a_time_seconds<101> m_sync_search_checker;
epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker;
- std::atomic<unsigned int> m_max_out_peers;
+ std::unordered_map<epee::net_utils::zone, unsigned int> m_max_out_peers;
+ mutable epee::critical_section m_max_out_peers_lock;
tools::PerformanceTimer m_sync_timer, m_add_timer;
uint64_t m_last_add_end_time;
uint64_t m_sync_spans_downloaded, m_sync_old_spans_downloaded, m_sync_bad_spans_downloaded;
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 891ee109d..af3031263 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -1776,33 +1776,49 @@ skip:
return true;
MTRACE("Checking for outgoing syncing peers...");
- unsigned n_syncing = 0, n_synced = 0;
- boost::uuids::uuid last_synced_peer_id(boost::uuids::nil_uuid());
+ std::unordered_map<epee::net_utils::zone, unsigned> n_syncing, n_synced;
+ std::unordered_map<epee::net_utils::zone, boost::uuids::uuid> last_synced_peer_id;
+ std::vector<epee::net_utils::zone> zones;
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
{
if (!peer_id || context.m_is_income) // only consider connected outgoing peers
return true;
+
+ const epee::net_utils::zone zone = context.m_remote_address.get_zone();
+ if (n_syncing.find(zone) == n_syncing.end())
+ {
+ n_syncing[zone] = 0;
+ n_synced[zone] = 0;
+ last_synced_peer_id[zone] = boost::uuids::nil_uuid();
+ zones.push_back(zone);
+ }
+
if (context.m_state == cryptonote_connection_context::state_synchronizing)
- ++n_syncing;
+ ++n_syncing[zone];
if (context.m_state == cryptonote_connection_context::state_normal)
{
- ++n_synced;
+ ++n_synced[zone];
if (!context.m_anchor)
- last_synced_peer_id = context.m_connection_id;
+ last_synced_peer_id[zone] = context.m_connection_id;
}
return true;
});
- MTRACE(n_syncing << " syncing, " << n_synced << " synced");
- // if we're at max out peers, and not enough are syncing
- if (n_synced + n_syncing >= m_max_out_peers && n_syncing < P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT && last_synced_peer_id != boost::uuids::nil_uuid())
+ for (const auto& zone : zones)
{
- if (!m_p2p->for_connection(last_synced_peer_id, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
- MINFO(ctx << "dropping synced peer, " << n_syncing << " syncing, " << n_synced << " synced");
- drop_connection(ctx, false, false);
- return true;
- }))
- MDEBUG("Failed to find peer we wanted to drop");
+ const unsigned int max_out_peers = get_max_out_peers(zone);
+ MTRACE("[" << epee::net_utils::zone_to_string(zone) << "] " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers");
+
+ // if we're at max out peers, and not enough are syncing, drop the last sync'd non-anchor
+ if (n_synced[zone] + n_syncing[zone] >= max_out_peers && n_syncing[zone] < P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT && last_synced_peer_id[zone] != boost::uuids::nil_uuid())
+ {
+ if (!m_p2p->for_connection(last_synced_peer_id[zone], [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
+ MINFO(ctx << "dropping synced peer, " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers");
+ drop_connection(ctx, false, false);
+ return true;
+ }))
+ MDEBUG("Failed to find peer we wanted to drop");
+ }
}
return true;
@@ -1987,11 +2003,13 @@ skip:
++n_peers_on_next_stripe;
return true;
});
+ // TODO: investigate tallying by zone and comparing to max out peers by zone
+ const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_);
const uint32_t distance = (peer_stripe + (1<<CRYPTONOTE_PRUNING_LOG_STRIPES) - next_stripe) % (1<<CRYPTONOTE_PRUNING_LOG_STRIPES);
- if ((n_out_peers >= m_max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2)
+ if ((n_out_peers >= max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2)
{
MDEBUG(context << "we want seed " << next_stripe << ", and either " << n_out_peers << " is at max out peers ("
- << m_max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe <<
+ << max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe <<
" is too large and we have only " << n_peers_on_next_stripe << " peers on next seed, dropping connection to make space");
return true;
}
@@ -2812,11 +2830,13 @@ skip:
}
return true;
});
- const bool use_next = (n_next > m_max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0);
+ // TODO: investigate tallying by zone and comparing to max out peers by zone
+ const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_);
+ const bool use_next = (n_next > max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0);
const uint32_t ret_stripe = use_next ? subsequent_pruning_stripe: next_pruning_stripe;
MIDEBUG(const std::string po = get_peers_overview(), "get_next_needed_pruning_stripe: want height " << want_height << " (" <<
want_height_from_blockchain << " from blockchain, " << want_height_from_block_queue << " from block queue), stripe " <<
- next_pruning_stripe << " (" << n_next << "/" << m_max_out_peers << " on it and " << n_subsequent << " on " <<
+ next_pruning_stripe << " (" << n_next << "/" << max_out_peers << " on it and " << n_subsequent << " on " <<
subsequent_pruning_stripe << ", " << n_others << " others) -> " << ret_stripe << " (+" <<
(ret_stripe - next_pruning_stripe + (1 << CRYPTONOTE_PRUNING_LOG_STRIPES)) % (1 << CRYPTONOTE_PRUNING_LOG_STRIPES) <<
"), current peers " << po);
@@ -2824,7 +2844,7 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
- bool t_cryptonote_protocol_handler<t_core>::needs_new_sync_connections() const
+ bool t_cryptonote_protocol_handler<t_core>::needs_new_sync_connections(epee::net_utils::zone zone) const
{
const uint64_t target = m_core.get_target_blockchain_height();
const uint64_t height = m_core.get_current_blockchain_height();
@@ -2832,11 +2852,11 @@ skip:
return false;
size_t n_out_peers = 0;
m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
- if (!ctx.m_is_income)
+ if (!ctx.m_is_income && ctx.m_remote_address.get_zone() == zone)
++n_out_peers;
return true;
});
- if (n_out_peers >= m_max_out_peers)
+ if (n_out_peers >= get_max_out_peers(zone))
return false;
return true;
}
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index a3bc3bf24..f33ce977d 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -538,7 +538,7 @@ namespace nodetool
if ( !set_max_out_peers(public_zone, command_line::get_arg(vm, arg_out_peers) ) )
return false;
else
- m_payload_handler.set_max_out_peers(public_zone.m_config.m_net_config.max_out_connection_count);
+ m_payload_handler.set_max_out_peers(epee::net_utils::zone::public_, public_zone.m_config.m_net_config.max_out_connection_count);
if ( !set_max_in_peers(public_zone, command_line::get_arg(vm, arg_in_peers) ) )
@@ -575,6 +575,8 @@ namespace nodetool
if (!set_max_out_peers(zone, proxy.max_connections))
return false;
+ else
+ m_payload_handler.set_max_out_peers(proxy.zone, proxy.max_connections);
epee::byte_slice this_noise = nullptr;
if (proxy.noise)
@@ -2462,8 +2464,12 @@ namespace nodetool
const epee::net_utils::zone zone_type = context.m_remote_address.get_zone();
network_zone& zone = m_network_zones.at(zone_type);
+ //will add self to peerlist if in same zone as outgoing later in this function
+ const bool outgoing_to_same_zone = !context.m_is_income && zone.m_our_address.get_zone() == zone_type;
+ const uint32_t max_peerlist_size = P2P_DEFAULT_PEERS_IN_HANDSHAKE - (outgoing_to_same_zone ? 1 : 0);
+
std::vector<peerlist_entry> local_peerlist_new;
- zone.m_peerlist.get_peerlist_head(local_peerlist_new, true, P2P_DEFAULT_PEERS_IN_HANDSHAKE);
+ zone.m_peerlist.get_peerlist_head(local_peerlist_new, true, max_peerlist_size);
//only include out peers we did not already send
rsp.local_peerlist_new.reserve(local_peerlist_new.size());
@@ -2483,7 +2489,7 @@ namespace nodetool
etc., because someone could give faulty addresses over Tor/I2P to get the
real peer with that identity banned/blacklisted. */
- if(!context.m_is_income && zone.m_our_address.get_zone() == zone_type)
+ if(outgoing_to_same_zone)
rsp.local_peerlist_new.push_back(peerlist_entry{zone.m_our_address, zone.m_config.m_peer_id, std::time(nullptr)});
LOG_DEBUG_CC(context, "COMMAND_TIMED_SYNC");
@@ -2758,7 +2764,7 @@ namespace nodetool
public_zone->second.m_config.m_net_config.max_out_connection_count = count;
if(current > count)
public_zone->second.m_net_server.get_config_object().del_out_connections(current - count);
- m_payload_handler.set_max_out_peers(count);
+ m_payload_handler.set_max_out_peers(epee::net_utils::zone::public_, count);
}
}
@@ -2887,10 +2893,12 @@ namespace nodetool
{
if (m_offline) return true;
if (!m_exclusive_peers.empty()) return true;
- if (m_payload_handler.needs_new_sync_connections()) return true;
for (auto& zone : m_network_zones)
{
+ if (m_payload_handler.needs_new_sync_connections(zone.first))
+ continue;
+
if (zone.second.m_net_server.is_stop_signal_sent())
return false;
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index d3e40ab74..f6e313089 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -142,6 +142,19 @@ typedef cryptonote::simple_wallet sw;
#define MIN_PAYMENT_RATE 0.01f // per hash
#define MAX_MNEW_ADDRESSES 1000
+#define CHECK_MULTISIG_ENABLED() \
+ do \
+ { \
+ if (!m_wallet->is_multisig_enabled()) \
+ { \
+ fail_msg_writer() << tr("Multisig is disabled."); \
+ fail_msg_writer() << tr("Multisig is an experimental feature and may have bugs. Things that could go wrong include: funds sent to a multisig wallet can't be spent at all, can only be spent with the participation of a malicious group member, or can be stolen by a malicious group member."); \
+ fail_msg_writer() << tr("You can enable it with:"); \
+ fail_msg_writer() << tr(" set enable-multisig-experimental 1"); \
+ return false; \
+ } \
+ } while(0)
+
enum TransferType {
Transfer,
TransferLocked,
@@ -986,12 +999,14 @@ bool simple_wallet::print_fee_info(const std::vector<std::string> &args/* = std:
bool simple_wallet::prepare_multisig(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
prepare_multisig_main(args, false);
return true;
}
bool simple_wallet::prepare_multisig_main(const std::vector<std::string> &args, bool called_by_mms)
{
+ CHECK_MULTISIG_ENABLED();
if (m_wallet->key_on_device())
{
fail_msg_writer() << tr("command not supported by HW wallet");
@@ -1031,12 +1046,14 @@ bool simple_wallet::prepare_multisig_main(const std::vector<std::string> &args,
bool simple_wallet::make_multisig(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
make_multisig_main(args, false);
return true;
}
bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, bool called_by_mms)
{
+ CHECK_MULTISIG_ENABLED();
if (m_wallet->key_on_device())
{
fail_msg_writer() << tr("command not supported by HW wallet");
@@ -1121,11 +1138,13 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo
bool simple_wallet::exchange_multisig_keys(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
exchange_multisig_keys_main(args, false);
return true;
}
bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> &args, bool called_by_mms) {
+ CHECK_MULTISIG_ENABLED();
bool ready;
if (m_wallet->key_on_device())
{
@@ -1189,12 +1208,14 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> &
bool simple_wallet::export_multisig(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
export_multisig_main(args, false);
return true;
}
bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, bool called_by_mms)
{
+ CHECK_MULTISIG_ENABLED();
bool ready;
if (m_wallet->key_on_device())
{
@@ -1254,12 +1275,14 @@ bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, b
bool simple_wallet::import_multisig(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
import_multisig_main(args, false);
return true;
}
bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, bool called_by_mms)
{
+ CHECK_MULTISIG_ENABLED();
bool ready;
uint32_t threshold, total;
if (m_wallet->key_on_device())
@@ -1349,12 +1372,14 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::multisig_tx_set &txs)
bool simple_wallet::sign_multisig(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
sign_multisig_main(args, false);
return true;
}
bool simple_wallet::sign_multisig_main(const std::vector<std::string> &args, bool called_by_mms)
{
+ CHECK_MULTISIG_ENABLED();
bool ready;
if (m_wallet->key_on_device())
{
@@ -1464,12 +1489,14 @@ bool simple_wallet::sign_multisig_main(const std::vector<std::string> &args, boo
bool simple_wallet::submit_multisig(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
submit_multisig_main(args, false);
return true;
}
bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, bool called_by_mms)
{
+ CHECK_MULTISIG_ENABLED();
bool ready;
uint32_t threshold;
if (m_wallet->key_on_device())
@@ -1551,6 +1578,7 @@ bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, b
bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
bool ready;
uint32_t threshold;
if (m_wallet->key_on_device())
@@ -3074,6 +3102,25 @@ bool simple_wallet::set_load_deprecated_formats(const std::vector<std::string> &
return true;
}
+bool simple_wallet::set_enable_multisig(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ if (args.size() < 2)
+ {
+ fail_msg_writer() << tr("Value not specified");
+ return true;
+ }
+
+ const auto pwd_container = get_and_verify_password();
+ if (pwd_container)
+ {
+ parse_bool_and_use(args[1], [&](bool r) {
+ m_wallet->enable_multisig(r);
+ m_wallet->rewrite(m_wallet_file, pwd_container->password());
+ });
+ }
+ return true;
+}
+
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if(args.empty())
@@ -3391,6 +3438,8 @@ simple_wallet::simple_wallet()
" The RPC payment credits balance to target (0 for default).\n "
"show-wallet-name-when-locked <1|0>\n "
" Set this if you would like to display the wallet name when locked.\n "
+ "enable-multisig-experimental <1|0>\n "
+ " Set this to allow multisig commands. Multisig may currently be exploitable if parties do not trust each other.\n "
"inactivity-lock-timeout <unsigned int>\n "
" How many seconds to wait before locking the wallet (0 to disable)."));
m_cmd_binder.set_handler("encrypted_seed",
@@ -3806,6 +3855,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "auto-mine-for-rpc-payment-threshold = " << m_wallet->auto_mine_for_rpc_payment_threshold();
success_msg_writer() << "credits-target = " << m_wallet->credits_target();
success_msg_writer() << "load-deprecated-formats = " << m_wallet->load_deprecated_formats();
+ success_msg_writer() << "enable-multisig-experimental = " << m_wallet->is_multisig_enabled();
return true;
}
else
@@ -3872,6 +3922,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("persistent-rpc-client-id", set_persistent_rpc_client_id, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("auto-mine-for-rpc-payment-threshold", set_auto_mine_for_rpc_payment_threshold, tr("floating point >= 0"));
CHECK_SIMPLE_VARIABLE("credits-target", set_credits_target, tr("unsigned integer"));
+ CHECK_SIMPLE_VARIABLE("enable-multisig-experimental", set_enable_multisig, tr("0 or 1"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
return true;
@@ -6560,7 +6611,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
vector<cryptonote::address_parse_info> dsts_info;
vector<cryptonote::tx_destination_entry> dsts;
- size_t num_subaddresses = 0;
for (size_t i = 0; i < local_args.size(); )
{
dsts_info.emplace_back();
@@ -6619,7 +6669,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
de.addr = info.address;
de.is_subaddress = info.is_subaddress;
de.is_integrated = info.has_payment_id;
- num_subaddresses += info.is_subaddress;
if (info.has_payment_id || !payment_id_uri.empty())
{
@@ -6980,6 +7029,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
// actually commit the transactions
if (m_wallet->multisig())
{
+ CHECK_MULTISIG_ENABLED();
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
if (!r)
{
@@ -7284,6 +7334,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
// actually commit the transactions
if (m_wallet->multisig())
{
+ CHECK_MULTISIG_ENABLED();
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
if (!r)
{
@@ -7518,6 +7569,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
// actually commit the transactions
if (m_wallet->multisig())
{
+ CHECK_MULTISIG_ENABLED();
bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx");
if (!r)
{
@@ -11549,6 +11601,7 @@ void simple_wallet::mms_auto_config(const std::vector<std::string> &args)
bool simple_wallet::mms(const std::vector<std::string> &args)
{
+ CHECK_MULTISIG_ENABLED();
try
{
m_wallet->get_multisig_wallet_state();
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 4c005c53a..6c4ddd4e7 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -153,6 +153,7 @@ namespace cryptonote
bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool set_export_format(const std::vector<std::string> &args = std::vector<std::string>());
bool set_load_deprecated_formats(const std::vector<std::string> &args = std::vector<std::string>());
+ bool set_enable_multisig(const std::vector<std::string> &args = std::vector<std::string>());
bool set_persistent_rpc_client_id(const std::vector<std::string> &args = std::vector<std::string>());
bool set_auto_mine_for_rpc_payment_threshold(const std::vector<std::string> &args = std::vector<std::string>());
bool set_credits_target(const std::vector<std::string> &args = std::vector<std::string>());
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 7cd8656e1..260caa551 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1280,6 +1280,42 @@ bool WalletImpl::importOutputs(const string &filename)
return true;
}
+bool WalletImpl::scanTransactions(const std::vector<std::string> &txids)
+{
+ if (txids.empty())
+ {
+ setStatusError(string(tr("Failed to scan transactions: no transaction ids provided.")));
+ return false;
+ }
+
+ // Parse and dedup args
+ std::unordered_set<crypto::hash> txids_u;
+ for (const auto &s : txids)
+ {
+ crypto::hash txid;
+ if (!epee::string_tools::hex_to_pod(s, txid))
+ {
+ setStatusError(string(tr("Invalid txid specified: ")) + s);
+ return false;
+ }
+ txids_u.insert(txid);
+ }
+ std::vector<crypto::hash> txids_v(txids_u.begin(), txids_u.end());
+
+ try
+ {
+ m_wallet->scan_tx(txids_v);
+ }
+ catch (const std::exception &e)
+ {
+ LOG_ERROR("Failed to scan transaction: " << e.what());
+ setStatusError(string(tr("Failed to scan transaction: ")) + e.what());
+ return false;
+ }
+
+ return true;
+}
+
void WalletImpl::addSubaddressAccount(const std::string& label)
{
m_wallet->add_subaddress_account(label);
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 0e61ee330..018b2a0ed 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -169,6 +169,7 @@ public:
bool importKeyImages(const std::string &filename) override;
bool exportOutputs(const std::string &filename, bool all = false) override;
bool importOutputs(const std::string &filename) override;
+ bool scanTransactions(const std::vector<std::string> &txids) override;
virtual void disposeTransaction(PendingTransaction * t) override;
virtual uint64_t estimateTransactionFee(const std::vector<std::pair<std::string, uint64_t>> &destinations,
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index c6f81f0e4..b67bce60c 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -927,6 +927,13 @@ struct Wallet
*/
virtual bool importOutputs(const std::string &filename) = 0;
+ /*!
+ * \brief scanTransactions - scan a list of transaction ids, this operation may reveal the txids to the remote node and affect your privacy
+ * \param txids - list of transaction ids
+ * \return - true on success
+ */
+ virtual bool scanTransactions(const std::vector<std::string> &txids) = 0;
+
virtual TransactionHistory * history() = 0;
virtual AddressBook * addressBook() = 0;
virtual Subaddress * subaddress() = 0;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 1eeb893c0..0b2a6c0f5 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1216,7 +1216,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std
m_rpc_version(0),
m_export_format(ExportFormat::Binary),
m_load_deprecated_formats(false),
- m_credits_target(0)
+ m_credits_target(0),
+ m_enable_multisig(false)
{
set_rpc_client_secret_key(rct::rct2sk(rct::skGen()));
}
@@ -2882,6 +2883,11 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
" (height " + std::to_string(start_height) + "), local block id at this height: " +
string_tools::pod_to_hex(m_blockchain[current_index]));
+ const uint64_t reorg_depth = m_blockchain.size() - current_index;
+ THROW_WALLET_EXCEPTION_IF(reorg_depth > m_max_reorg_depth, error::reorg_depth_error,
+ tr("reorg exceeds maximum allowed depth, use 'set max-reorg-depth N' to allow it, reorg depth: ") +
+ std::to_string(reorg_depth));
+
detach_blockchain(current_index, output_tracker_cache);
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
}
@@ -3532,15 +3538,6 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
first = false;
- if (!next_blocks.empty())
- {
- const uint64_t expected_start_height = std::max(static_cast<uint64_t>(m_blockchain.size()), uint64_t(1)) - 1;
- const uint64_t reorg_depth = expected_start_height - std::min(expected_start_height, next_blocks_start_height);
- THROW_WALLET_EXCEPTION_IF(reorg_depth > m_max_reorg_depth, error::reorg_depth_error,
- tr("reorg exceeds maximum allowed depth, use 'set max-reorg-depth N' to allow it, reorg depth: ") +
- std::to_string(reorg_depth));
- }
-
// if we've got at least 10 blocks to refresh, assume we're starting
// a long refresh, and setup a tracking output cache if we need to
if (m_track_uses && (!output_tracker_cache || output_tracker_cache->empty()) && next_blocks.size() >= 10)
@@ -4051,6 +4048,9 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
value2.SetUint64(m_credits_target);
json.AddMember("credits_target", value2, json.GetAllocator());
+ value2.SetInt(m_enable_multisig ? 1 : 0);
+ json.AddMember("enable_multisig", value2, json.GetAllocator());
+
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -4199,6 +4199,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
m_persistent_rpc_client_id = false;
m_auto_mine_for_rpc_payment_threshold = -1.0f;
m_credits_target = 0;
+ m_enable_multisig = false;
}
else if(json.IsObject())
{
@@ -4431,6 +4432,8 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
m_auto_mine_for_rpc_payment_threshold = field_auto_mine_for_rpc_payment;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, credits_target, uint64_t, Uint64, false, 0);
m_credits_target = field_credits_target;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, enable_multisig, int, Int, false, false);
+ m_enable_multisig = field_enable_multisig;
}
else
{
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index e9e5bc95e..e051946ad 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1297,6 +1297,8 @@ private:
void set_rpc_client_secret_key(const crypto::secret_key &key) { m_rpc_client_secret_key = key; m_node_rpc_proxy.set_client_secret_key(key); }
uint64_t credits_target() const { return m_credits_target; }
void credits_target(uint64_t threshold) { m_credits_target = threshold; }
+ bool is_multisig_enabled() const { return m_enable_multisig; }
+ void enable_multisig(bool enable) { m_enable_multisig = enable; }
bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const;
void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, const boost::optional<cryptonote::account_public_address> &single_destination_subaddress = boost::none);
@@ -1813,6 +1815,7 @@ private:
crypto::secret_key m_rpc_client_secret_key;
rpc_payment_state_t m_rpc_payment_state;
uint64_t m_credits_target;
+ bool m_enable_multisig;
// Aux transaction data from device
serializable_unordered_map<crypto::hash, std::string> m_tx_device;
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 57baf428f..7ec5fc7a1 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -61,6 +61,17 @@ using namespace epee;
#define DEFAULT_AUTO_REFRESH_PERIOD 20 // seconds
+#define CHECK_MULTISIG_ENABLED() \
+ do \
+ { \
+ if (m_wallet->multisig() && !m_wallet->is_multisig_enabled()) \
+ { \
+ er.code = WALLET_RPC_ERROR_CODE_DISABLED; \
+ er.message = "This wallet is multisig, and multisig is disabled. Multisig is an experimental feature and may have bugs. Things that could go wrong include: funds sent to a multisig wallet can't be spent at all, can only be spent with the participation of a malicious group member, or can be stolen by a malicious group member. You can enable it by running this once in monero-wallet-cli: set enable-multisig-experimental 1"; \
+ return false; \
+ } \
+ } while(0)
+
namespace
{
const command_line::arg_descriptor<std::string, true> arg_rpc_bind_port = {"rpc-bind-port", "Sets bind port for server"};
@@ -1057,6 +1068,8 @@ namespace tools
return false;
}
+ CHECK_MULTISIG_ENABLED();
+
// validate the transfer requested and populate dsts & extra
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er))
{
@@ -1109,6 +1122,8 @@ namespace tools
return false;
}
+ CHECK_MULTISIG_ENABLED();
+
// validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types.
if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er))
{
@@ -1163,6 +1178,8 @@ namespace tools
return false;
}
+ CHECK_MULTISIG_ENABLED();
+
cryptonote::blobdata blob;
if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob))
{
@@ -1511,6 +1528,8 @@ namespace tools
return false;
}
+ CHECK_MULTISIG_ENABLED();
+
try
{
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions();
@@ -1539,6 +1558,8 @@ namespace tools
return false;
}
+ CHECK_MULTISIG_ENABLED();
+
// validate the transfer requested and populate dsts & extra
std::list<wallet_rpc::transfer_destination> destination;
destination.push_back(wallet_rpc::transfer_destination());
@@ -1604,6 +1625,8 @@ namespace tools
return false;
}
+ CHECK_MULTISIG_ENABLED();
+
// validate the transfer requested and populate dsts & extra
std::list<wallet_rpc::transfer_destination> destination;
destination.push_back(wallet_rpc::transfer_destination());
@@ -3933,6 +3956,9 @@ namespace tools
er.message = "This wallet is already multisig";
return false;
}
+ if (req.enable_multisig_experimental)
+ m_wallet->enable_multisig(true);
+ CHECK_MULTISIG_ENABLED();
if (m_wallet->watch_only())
{
er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY;
@@ -3959,6 +3985,7 @@ namespace tools
er.message = "This wallet is already multisig";
return false;
}
+ CHECK_MULTISIG_ENABLED();
if (m_wallet->watch_only())
{
er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY;
@@ -4003,6 +4030,7 @@ namespace tools
er.message = "This wallet is multisig, but not yet finalized";
return false;
}
+ CHECK_MULTISIG_ENABLED();
cryptonote::blobdata info;
try
@@ -4044,6 +4072,7 @@ namespace tools
er.message = "This wallet is multisig, but not yet finalized";
return false;
}
+ CHECK_MULTISIG_ENABLED();
if (req.info.size() < threshold - 1)
{
@@ -4096,6 +4125,7 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_finalize_multisig(const wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
+ CHECK_MULTISIG_ENABLED();
return false;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -4123,6 +4153,7 @@ namespace tools
er.message = "This wallet is multisig, and already finalized";
return false;
}
+ CHECK_MULTISIG_ENABLED();
if (req.multisig_info.size() + 1 < total)
{
@@ -4172,6 +4203,7 @@ namespace tools
er.message = "This wallet is multisig, but not yet finalized";
return false;
}
+ CHECK_MULTISIG_ENABLED();
cryptonote::blobdata blob;
if (!epee::string_tools::parse_hexstr_to_binbuff(req.tx_data_hex, blob))
@@ -4241,6 +4273,7 @@ namespace tools
er.message = "This wallet is multisig, but not yet finalized";
return false;
}
+ CHECK_MULTISIG_ENABLED();
cryptonote::blobdata blob;
if (!epee::string_tools::parse_hexstr_to_binbuff(req.tx_data_hex, blob))
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index fe53e293f..ecfc8e673 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -2416,7 +2416,10 @@ namespace wallet_rpc
{
struct request_t
{
+ bool enable_multisig_experimental;
+
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_OPT(enable_multisig_experimental, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index 914939573..734229380 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -78,3 +78,4 @@
#define WALLET_RPC_ERROR_CODE_ATTRIBUTE_NOT_FOUND -45
#define WALLET_RPC_ERROR_CODE_ZERO_AMOUNT -46
#define WALLET_RPC_ERROR_CODE_INVALID_SIGNATURE_TYPE -47
+#define WALLET_RPC_ERROR_CODE_DISABLED -48
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5a3c49560..2cabb1ba5 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -78,6 +78,7 @@ file(COPY
data/outputs
data/unsigned_monero_tx
data/signed_monero_tx
+ data/sha256sum
DESTINATION data)
if (CMAKE_BUILD_TYPE STREQUAL "fuzz" OR OSSFUZZ)
diff --git a/tests/data/sha256sum/CLSAG.pdf b/tests/data/sha256sum/CLSAG.pdf
new file mode 100644
index 000000000..6d7bb79ae
--- /dev/null
+++ b/tests/data/sha256sum/CLSAG.pdf
Binary files differ
diff --git a/tests/data/sha256sum/empty.txt b/tests/data/sha256sum/empty.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/data/sha256sum/empty.txt
diff --git a/tests/data/sha256sum/small_file.txt b/tests/data/sha256sum/small_file.txt
new file mode 100644
index 000000000..74ca63e8d
--- /dev/null
+++ b/tests/data/sha256sum/small_file.txt
@@ -0,0 +1,19 @@
+From: https://localmonero.co/knowledge/monero-circular-economies
+
+How does Monero uniquely enable these circular economies?
+
+While Monero shares some of the core attributes of Bitcoin that enable circular economies in a new way (censorship-resistant payments, p2p transactions, etc.), it brings an absolutely unique empowerment to those wishing to build and engage in circular economies.
+
+1. Monero enables global p2p transactions without fear of surveillance or censorship
+Monero users do not need to worry about mass surveillance or even targeted censorship of their transactions, enabling unique peace of mind and preventing any burdens on commerce. You can transact with anyone in the world, at any time, without any surveillance using the Monero wallet of your choice.
+
+2. Fungibility removes the risk of tainted coins and ensures trust
+As Monero is fungible (1 XMR equals 1 XMR, no matter what), participants in the circular economy don’t need to worry about the funds they are sending or receiving. Any Monero they send cannot be traced back to their other transactions and has no history and thus cannot be censored based on history, and Monero received will always be able to be spent freely at full market value. This fungibility adds to the peace of mind of participants, ensures that chain analysis firms cannot force their way into circular economies, and prevents a breakdown of trust in Monero as a method of exchange.
+The current breakdown of trust in Bitcoin as a method of exchange is leading to it rapidly losing traction in circular economies where Monero is present. People don’t want to have to check funds for taint, worry about if they will be able to spend them freely, or feel the need to use any chain analysis tools to protect themselves from legal or regulatory issues.
+
+3. Monero’s low fees ensure a free flow of commerce
+One of the simplest points to grasp about Monero transactions is that transaction fees are incredibly low and will remain reasonable in the long-term thanks to the tail emission and dynamic block size.
+These low fees make sure that commerce can flow freely no matter the amount of blockchain congestion, further reducing the mental burden and stress on participants to try and time their transactions or wait hours/days to confirm low-fee transactions. With fees around 1c today, you can transact freely with any size of transaction without worry about fees down the line.
+
+Conclusion
+Ultimately, Monero is digital cash as it should be. The peace of mind, fungibility, and privacy of transacting in cash but with all of the advantages of digital, global, and p2p transactions detached from the states control or surveillance. This ability to act as digital cash is uniquely enabling circular economies today and helping them to grow and prosper over time in ways that other cryptocurrencies like Bitcoin simply can’t.
diff --git a/tests/functional_tests/multisig.py b/tests/functional_tests/multisig.py
index 89cb2fdc7..1c5894f47 100755
--- a/tests/functional_tests/multisig.py
+++ b/tests/functional_tests/multisig.py
@@ -107,7 +107,7 @@ class MultisigTest():
try: self.wallet[i].close_wallet()
except: pass
res = self.wallet[i].restore_deterministic_wallet(seed = seeds[i])
- res = self.wallet[i].prepare_multisig()
+ res = self.wallet[i].prepare_multisig(enable_multisig_experimental = True)
assert len(res.multisig_info) > 0
info.append(res.multisig_info)
@@ -172,7 +172,7 @@ class MultisigTest():
res = wallet2of2[i].restore_deterministic_wallet(seed = seeds[i])
res = wallet2of2[i].is_multisig()
assert not res.multisig
- res = wallet2of2[i].prepare_multisig()
+ res = wallet2of2[i].prepare_multisig(enable_multisig_experimental = True)
assert len(res.multisig_info) > 0
info2of2.append(res.multisig_info)
@@ -187,7 +187,7 @@ class MultisigTest():
assert res.ready
ok = False
- try: res = wallet2of2[0].prepare_multisig()
+ try: res = wallet2of2[0].prepare_multisig(enable_multisig_experimental = True)
except: ok = True
assert ok
@@ -205,7 +205,7 @@ class MultisigTest():
res = wallet2of3[i].restore_deterministic_wallet(seed = seeds[i])
res = wallet2of3[i].is_multisig()
assert not res.multisig
- res = wallet2of3[i].prepare_multisig()
+ res = wallet2of3[i].prepare_multisig(enable_multisig_experimental = True)
assert len(res.multisig_info) > 0
info2of3.append(res.multisig_info)
@@ -223,7 +223,7 @@ class MultisigTest():
assert not res.ready
ok = False
- try: res = wallet2of3[1].prepare_multisig()
+ try: res = wallet2of3[1].prepare_multisig(enable_multisig_experimental = True)
except: ok = True
assert ok
diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp
index 134fa6ece..6c8cd9f8d 100644
--- a/tests/unit_tests/node_server.cpp
+++ b/tests/unit_tests/node_server.cpp
@@ -1026,12 +1026,12 @@ TEST(node_server, race_condition)
}
void stop() {}
void on_connection_close(context_t &context) {}
- void set_max_out_peers(unsigned int max) {}
+ void set_max_out_peers(epee::net_utils::zone zone, unsigned int max) {}
bool no_sync() const { return {}; }
void set_no_sync(bool value) {}
string_t get_peers_overview() const { return {}; }
stripes_t get_next_needed_pruning_stripe() const { return {}; }
- bool needs_new_sync_connections() const { return {}; }
+ bool needs_new_sync_connections(epee::net_utils::zone zone) const { return {}; }
bool is_busy_syncing() { return {}; }
};
using node_server_t = nodetool::node_server<protocol_t>;
diff --git a/tests/unit_tests/sha256.cpp b/tests/unit_tests/sha256.cpp
index 486f31c5b..7a96a783b 100644
--- a/tests/unit_tests/sha256.cpp
+++ b/tests/unit_tests/sha256.cpp
@@ -26,10 +26,13 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <boost/filesystem.hpp>
+
#include "gtest/gtest.h"
#include "common/util.h"
#include "string_tools.h"
+#include "unit_tests_utils.h"
static bool check(const std::string &data, const char *expected_hash_hex)
{
@@ -39,7 +42,26 @@ static bool check(const std::string &data, const char *expected_hash_hex)
return tools::sha256sum((const uint8_t*)data.data(), data.size(), hash) && hash == expected_hash;
}
+static std::string file_to_hex_hash(const std::string& filename)
+ {
+ const boost::filesystem::path full_path = unit_test::data_dir / "sha256sum" / filename;
+
+ crypto::hash hash;
+ if (!tools::sha256sum(full_path.string(), hash)) {
+ throw std::runtime_error("sha256sum failed");
+ }
+
+ const std::string data_cstr(hash.data, sizeof(hash.data));
+ const std::string hex_hash = epee::string_tools::buff_to_hex_nodelimer(data_cstr);
+
+ return hex_hash;
+ }
+
TEST(sha256, empty) { ASSERT_TRUE(check(std::string(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); }
TEST(sha256, small) { ASSERT_TRUE(check("0123456789", "84d89877f0d4041efb6bf91a16f0248f2fd573e6af05c19f96bedb9f882f7882")); }
TEST(sha256, large) { ASSERT_TRUE(check(std::string(65536*256, 0), "080acf35a507ac9849cfcba47dc2ad83e01b75663a516279c8b9d243b719643e")); }
+TEST(sha256, emptyfile) { EXPECT_EQ(file_to_hex_hash("empty.txt"), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); }
+TEST(sha256, smallfile) { EXPECT_EQ(file_to_hex_hash("small_file.txt"), "91c60f6d9ad0235306115913febccb93a5014bf4cea1ecd1fa33f3cf07ad9e8d"); }
+TEST(sha256, largefile) { EXPECT_EQ(file_to_hex_hash("CLSAG.pdf"), "c38699c9a235a70285165ff8cce0bf3e48989de8092c15514116ca4c95d41e3f"); }
+TEST(sha256, noexist) { crypto::hash hash; EXPECT_FALSE(tools::sha256sum("this_file_does_not_exist.exe", hash)); }
diff --git a/utils/build_scripts/windows.bat b/utils/build_scripts/windows.bat
deleted file mode 100644
index 77ffd1c96..000000000
--- a/utils/build_scripts/windows.bat
+++ /dev/null
@@ -1,45 +0,0 @@
-:: Copyright (c) 2014-2022, 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.
-
-:: Set the following variables according to your environment
-set BuildProcessorArchitecture=64
-set LocationDependencyBoostRoot=D:\Development\boost_1_55_0
-set LocationEnvironmentVariableSetterMsbuild=C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
-
-call "%LocationEnvironmentVariableSetterMsbuild%"
-set LocationDependencyBoostLibrary=%LocationDependencyBoostRoot%\lib%BuildProcessorArchitecture%-msvc-%VisualStudioVersion%
-
-cd ..\..
-set LocationBuildSource=%CD%
-mkdir build\win%BuildProcessorArchitecture%
-cd build\win%BuildProcessorArchitecture%
-
-cmake -G "Visual Studio %VisualStudioVersion:.0=% Win%BuildProcessorArchitecture%" -DBOOST_ROOT="%LocationDependencyBoostRoot%" -DBOOST_LIBRARYDIR="%LocationDependencyBoostLibrary%" "%LocationBuildSource%"
-msbuild Project.sln /p:Configuration=Release
-
-pause
diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py
index 037beee84..01e937627 100644
--- a/utils/python-rpc/framework/wallet.py
+++ b/utils/python-rpc/framework/wallet.py
@@ -490,10 +490,11 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(is_multisig)
- def prepare_multisig(self):
+ def prepare_multisig(self, enable_multisig_experimental = False):
prepare_multisig = {
'method': 'prepare_multisig',
'params' : {
+ 'enable_multisig_experimental': enable_multisig_experimental,
},
'jsonrpc': '2.0',
'id': '0'