diff options
-rw-r--r-- | external/db_drivers/liblmdb/lmdb.h | 2 | ||||
-rw-r--r-- | external/db_drivers/liblmdb/mdb.c | 148 | ||||
-rw-r--r-- | src/blockchain_db/berkeleydb/db_bdb.cpp | 6 | ||||
-rw-r--r-- | src/blockchain_db/berkeleydb/db_bdb.h | 3 | ||||
-rw-r--r-- | src/blockchain_db/blockchain_db.cpp | 5 | ||||
-rw-r--r-- | src/blockchain_db/blockchain_db.h | 2 | ||||
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.cpp | 14 | ||||
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.h | 2 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 8 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 3 | ||||
-rw-r--r-- | src/cryptonote_core/hardfork.cpp | 4 | ||||
-rw-r--r-- | tests/unit_tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/unit_tests/canonical_amounts.cpp | 83 |
13 files changed, 195 insertions, 86 deletions
diff --git a/external/db_drivers/liblmdb/lmdb.h b/external/db_drivers/liblmdb/lmdb.h index 587a44eaf..d616cabf9 100644 --- a/external/db_drivers/liblmdb/lmdb.h +++ b/external/db_drivers/liblmdb/lmdb.h @@ -176,7 +176,7 @@ typedef mode_t mdb_mode_t; #ifdef MDB_VL32 typedef uint64_t mdb_size_t; -#define mdb_env_create(env) mdb_env_create_vl32(env) /**< Prevent mixing with non-VL32 builds */ +#define mdb_env_create mdb_env_create_vl32 /**< Prevent mixing with non-VL32 builds */ #else typedef size_t mdb_size_t; #endif diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c index e42c34498..ae32c9896 100644 --- a/external/db_drivers/liblmdb/mdb.c +++ b/external/db_drivers/liblmdb/mdb.c @@ -455,15 +455,14 @@ typedef pthread_mutex_t mdb_mutex_t[1], *mdb_mutexref_t; #define GET_PAGESIZE(x) ((x) = sysconf(_SC_PAGE_SIZE)) #endif -#ifndef MDB_VL32 -#define Yd Z"d" -#define Yu Z"u" -#elif defined _WIN32 -#define Yd "I64d" -#define Yu "I64u" +#ifdef MDB_VL32 +#ifdef _WIN32 +#define Y "I64" +#else +#define Y "ll" +#endif #else -#define Yd PRId64 -#define Yu PRIu64 +#define Y Z #endif #if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) @@ -1706,20 +1705,20 @@ mdb_page_list(MDB_page *mp) case P_LEAF|P_LEAF2: type = "LEAF2 page"; break; case P_LEAF|P_LEAF2|P_SUBP: type = "LEAF2 sub-page"; break; case P_OVERFLOW: - fprintf(stderr, "Overflow page %"Yu" pages %u%s\n", + fprintf(stderr, "Overflow page %"Y"u pages %u%s\n", pgno, mp->mp_pages, state); return; case P_META: - fprintf(stderr, "Meta-page %"Yu" txnid %"Yu"\n", + fprintf(stderr, "Meta-page %"Y"u txnid %"Y"u\n", pgno, ((MDB_meta *)METADATA(mp))->mm_txnid); return; default: - fprintf(stderr, "Bad page %"Yu" flags 0x%u\n", pgno, mp->mp_flags); + fprintf(stderr, "Bad page %"Y"u flags 0x%u\n", pgno, mp->mp_flags); return; } nkeys = NUMKEYS(mp); - fprintf(stderr, "%s %"Yu" numkeys %d%s\n", type, pgno, nkeys, state); + fprintf(stderr, "%s %"Y"u numkeys %d%s\n", type, pgno, nkeys, state); for (i=0; i<nkeys; i++) { if (IS_LEAF2(mp)) { /* LEAF2 pages have no mp_ptrs[] or node headers */ @@ -1734,7 +1733,7 @@ mdb_page_list(MDB_page *mp) key.mv_data = node->mn_data; nsize = NODESIZE + key.mv_size; if (IS_BRANCH(mp)) { - fprintf(stderr, "key %d: page %"Yu", %s\n", i, NODEPGNO(node), + fprintf(stderr, "key %d: page %"Y"u, %s\n", i, NODEPGNO(node), DKEY(&key)); total += nsize; } else { @@ -1830,7 +1829,7 @@ static void mdb_audit(MDB_txn *txn) } } if (freecount + count + NUM_METAS != txn->mt_next_pgno) { - fprintf(stderr, "audit: %"Yu" freecount: %"Yu" count: %"Yu" total: %"Yu" next_pgno: %"Yu"\n", + fprintf(stderr, "audit: %"Y"u freecount: %"Y"u count: %"Y"u total: %"Y"u next_pgno: %"Y"u\n", txn->mt_txnid, freecount, count+NUM_METAS, freecount+count+NUM_METAS, txn->mt_next_pgno); } @@ -1953,7 +1952,7 @@ static void mdb_cursor_unref(MDB_cursor *mc) { int i; - if (!mc->mc_pg[0] || IS_SUBP(mc->mc_pg[0])) + if (!mc->mc_snum || !mc->mc_pg[0] || IS_SUBP(mc->mc_pg[0])) return; for (i=0; i<mc->mc_snum; i++) mdb_page_unref(mc->mc_txn, mc->mc_pg[i]); @@ -2010,7 +2009,7 @@ mdb_page_loose(MDB_cursor *mc, MDB_page *mp) } } if (loose) { - DPRINTF(("loosen db %d page %"Yu"", DDBI(mc), + DPRINTF(("loosen db %d page %"Y"u", DDBI(mc), mp->mp_pgno)); NEXT_LOOSE_PAGE(mp) = txn->mt_loose_pgs; txn->mt_loose_pgs = mp; @@ -2308,7 +2307,7 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) np = txn->mt_loose_pgs; txn->mt_loose_pgs = NEXT_LOOSE_PAGE(np); txn->mt_loose_count--; - DPRINTF(("db %d use loose page %"Yu"", DDBI(mc), + DPRINTF(("db %d use loose page %"Y"u", DDBI(mc), np->mp_pgno)); *mp = np; return MDB_SUCCESS; @@ -2411,10 +2410,10 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) } env->me_pglast = last; #if (MDB_DEBUG) > 1 - DPRINTF(("IDL read txn %"Yu" root %"Yu" num %u", + DPRINTF(("IDL read txn %"Y"u root %"Y"u num %u", last, txn->mt_dbs[FREE_DBI].md_root, i)); for (j = i; j; j--) - DPRINTF(("IDL %"Yu"", idl[j])); + DPRINTF(("IDL %"Y"u", idl[j])); #endif /* Merge in descending sorted order */ mdb_midl_xmerge(mop, idl); @@ -2584,7 +2583,7 @@ mdb_page_touch(MDB_cursor *mc) (rc = mdb_page_alloc(mc, 1, &np))) goto fail; pgno = np->mp_pgno; - DPRINTF(("touched db %d page %"Yu" -> %"Yu"", DDBI(mc), + DPRINTF(("touched db %d page %"Y"u -> %"Y"u", DDBI(mc), mp->mp_pgno, pgno)); mdb_cassert(mc, mp->mp_pgno != pgno); mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno); @@ -2985,7 +2984,7 @@ mdb_txn_renew(MDB_txn *txn) rc = mdb_txn_renew0(txn); if (rc == MDB_SUCCESS) { - DPRINTF(("renew txn %"Yu"%c %p on mdbenv %p, root page %"Yu"", + DPRINTF(("renew txn %"Y"u%c %p on mdbenv %p, root page %"Y"u", txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w', (void *)txn, (void *)txn->mt_env, txn->mt_dbs[MAIN_DBI].md_root)); } @@ -3103,7 +3102,7 @@ renew: } else { txn->mt_flags |= flags; /* could not change txn=me_txn0 earlier */ *ret = txn; - DPRINTF(("begin txn %"Yu"%c %p on mdbenv %p, root page %"Yu"", + DPRINTF(("begin txn %"Y"u%c %p on mdbenv %p, root page %"Y"u", txn->mt_txnid, (flags & MDB_RDONLY) ? 'r' : 'w', (void *) txn, (void *) env, txn->mt_dbs[MAIN_DBI].md_root)); } @@ -3170,7 +3169,7 @@ mdb_txn_end(MDB_txn *txn, unsigned mode) /* Export or close DBI handles opened in this txn */ mdb_dbis_update(txn, mode & MDB_END_UPDATE); - DPRINTF(("%s txn %"Yu"%c %p on mdbenv %p, root page %"Yu"", + DPRINTF(("%s txn %"Y"u%c %p on mdbenv %p, root page %"Y"u", names[mode & MDB_END_OPMASK], txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w', (void *) txn, (void *)env, txn->mt_dbs[MAIN_DBI].md_root)); @@ -3371,10 +3370,10 @@ mdb_freelist_save(MDB_txn *txn) #if (MDB_DEBUG) > 1 { unsigned int i = free_pgs[0]; - DPRINTF(("IDL write txn %"Yu" root %"Yu" num %u", + DPRINTF(("IDL write txn %"Y"u root %"Y"u num %u", txn->mt_txnid, txn->mt_dbs[FREE_DBI].md_root, i)); for (; i; i--) - DPRINTF(("IDL %"Yu"", free_pgs[i])); + DPRINTF(("IDL %"Y"u", free_pgs[i])); } #endif continue; @@ -3593,7 +3592,7 @@ retry_seek: wpos = pos; wsize = 0; } - DPRINTF(("committing page %"Yu"", pgno)); + DPRINTF(("committing page %"Y"u", pgno)); next_pos = pos + size; iov[n].iov_len = size; iov[n].iov_base = (char *)dp; @@ -3806,7 +3805,7 @@ mdb_txn_commit(MDB_txn *txn) !(txn->mt_flags & (MDB_TXN_DIRTY|MDB_TXN_SPILLS))) goto done; - DPRINTF(("committing txn %"Yu" %p on mdbenv %p, root page %"Yu"", + DPRINTF(("committing txn %"Y"u %p on mdbenv %p, root page %"Y"u", txn->mt_txnid, (void*)txn, (void*)env, txn->mt_dbs[MAIN_DBI].md_root)); /* Update DB root pointers */ @@ -3904,7 +3903,7 @@ mdb_env_read_header(MDB_env *env, MDB_meta *meta) p = (MDB_page *)&pbuf; if (!F_ISSET(p->mp_flags, P_META)) { - DPRINTF(("page %"Yu" not a meta page", p->mp_pgno)); + DPRINTF(("page %"Y"u not a meta page", p->mp_pgno)); return MDB_INVALID; } @@ -4016,7 +4015,7 @@ mdb_env_write_meta(MDB_txn *txn) #endif toggle = txn->mt_txnid & 1; - DPRINTF(("writing meta page %d for root page %"Yu"", + DPRINTF(("writing meta page %d for root page %"Y"u", toggle, txn->mt_dbs[MAIN_DBI].md_root)); env = txn->mt_env; @@ -4499,11 +4498,11 @@ mdb_env_open2(MDB_env *env) meta->mm_version, env->me_psize)); DPRINTF(("using meta page %d", (int) (meta->mm_txnid & 1))); DPRINTF(("depth: %u", db->md_depth)); - DPRINTF(("entries: %"Yu"", db->md_entries)); - DPRINTF(("branch pages: %"Yu"", db->md_branch_pages)); - DPRINTF(("leaf pages: %"Yu"", db->md_leaf_pages)); - DPRINTF(("overflow pages: %"Yu"", db->md_overflow_pages)); - DPRINTF(("root: %"Yu"", db->md_root)); + DPRINTF(("entries: %"Y"u", db->md_entries)); + DPRINTF(("branch pages: %"Y"u", db->md_branch_pages)); + DPRINTF(("leaf pages: %"Y"u", db->md_leaf_pages)); + DPRINTF(("overflow pages: %"Y"u", db->md_overflow_pages)); + DPRINTF(("root: %"Y"u", db->md_root)); } #endif @@ -5351,6 +5350,7 @@ mdb_env_close0(MDB_env *env, int excl) } #ifdef MDB_VL32 #ifdef _WIN32 + if (env->me_fmh) CloseHandle(env->me_fmh); if (env->me_rpmutex) CloseHandle(env->me_rpmutex); #else pthread_mutex_destroy(&env->me_rpmutex); @@ -5495,7 +5495,7 @@ mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp) nkeys = NUMKEYS(mp); - DPRINTF(("searching %u keys in %s %spage %"Yu"", + DPRINTF(("searching %u keys in %s %spage %"Y"u", nkeys, IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "", mdb_dbg_pgno(mp))); @@ -5543,7 +5543,7 @@ mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp) DPRINTF(("found leaf index %u [%s], rc = %i", i, DKEY(&nodekey), rc)); else - DPRINTF(("found branch index %u [%s -> %"Yu"], rc = %i", + DPRINTF(("found branch index %u [%s -> %"Y"u], rc = %i", i, DKEY(&nodekey), NODEPGNO(node), rc)); #endif if (rc == 0) @@ -5591,7 +5591,7 @@ static void mdb_cursor_pop(MDB_cursor *mc) { if (mc->mc_snum) { - DPRINTF(("popping page %"Yu" off db %d cursor %p", + DPRINTF(("popping page %"Y"u off db %d cursor %p", mc->mc_pg[mc->mc_top]->mp_pgno, DDBI(mc), (void *) mc)); mc->mc_snum--; @@ -5607,7 +5607,7 @@ mdb_cursor_pop(MDB_cursor *mc) static int mdb_cursor_push(MDB_cursor *mc, MDB_page *mp) { - DPRINTF(("pushing page %"Yu" on db %d cursor %p", mp->mp_pgno, + DPRINTF(("pushing page %"Y"u on db %d cursor %p", mp->mp_pgno, DDBI(mc), (void *) mc)); if (mc->mc_snum >= CURSOR_STACK) { @@ -5995,7 +5995,7 @@ mdb_page_get(MDB_cursor *mc, pgno_t pgno, MDB_page **ret, int *lvl) p = (MDB_page *)(env->me_map + env->me_psize * pgno); #endif } else { - DPRINTF(("page %"Yu" not found", pgno)); + DPRINTF(("page %"Y"u not found", pgno)); txn->mt_flags |= MDB_TXN_ERROR; return MDB_PAGE_NOTFOUND; } @@ -6021,13 +6021,13 @@ mdb_page_search_root(MDB_cursor *mc, MDB_val *key, int flags) MDB_node *node; indx_t i; - DPRINTF(("branch page %"Yu" has %u keys", mp->mp_pgno, NUMKEYS(mp))); + DPRINTF(("branch page %"Y"u has %u keys", mp->mp_pgno, NUMKEYS(mp))); /* Don't assert on branch pages in the FreeDB. We can get here * while in the process of rebalancing a FreeDB branch page; we must * let that proceed. ITS#8336 */ mdb_cassert(mc, !mc->mc_dbi || NUMKEYS(mp) > 1); - DPRINTF(("found index 0 to page %"Yu"", NODEPGNO(NODEPTR(mp, 0)))); + DPRINTF(("found index 0 to page %"Y"u", NODEPGNO(NODEPTR(mp, 0)))); if (flags & (MDB_PS_FIRST|MDB_PS_LAST)) { i = 0; @@ -6072,7 +6072,7 @@ mdb_page_search_root(MDB_cursor *mc, MDB_val *key, int flags) return MDB_CORRUPTED; } - DPRINTF(("found leaf page %"Yu" for key [%s]", mp->mp_pgno, + DPRINTF(("found leaf page %"Y"u for key [%s]", mp->mp_pgno, key ? DKEY(key) : "null")); mc->mc_flags |= C_INITIALIZED; mc->mc_flags &= ~C_EOF; @@ -6187,7 +6187,7 @@ mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags) mc->mc_snum = 1; mc->mc_top = 0; - DPRINTF(("db %d root page %"Yu" has flags 0x%X", + DPRINTF(("db %d root page %"Y"u has flags 0x%X", DDBI(mc), root, mc->mc_pg[0]->mp_flags)); if (flags & MDB_PS_MODIFY) { @@ -6212,7 +6212,7 @@ mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp) MDB_ID pn = pg << 1; int rc; - DPRINTF(("free ov page %"Yu" (%d)", pg, ovpages)); + DPRINTF(("free ov page %"Y"u (%d)", pg, ovpages)); /* If the page is dirty or on the spill list we just acquired it, * so we should give it back to our current free list, if any. * Otherwise put it onto the list of pages we freed in this txn. @@ -6307,7 +6307,7 @@ mdb_node_read(MDB_cursor *mc, MDB_node *leaf, MDB_val *data) data->mv_size = NODEDSZ(leaf); memcpy(&pgno, NODEDATA(leaf), sizeof(pgno)); if ((rc = mdb_page_get(mc, pgno, &omp, NULL)) != 0) { - DPRINTF(("read overflow page %"Yu" failed", pgno)); + DPRINTF(("read overflow page %"Y"u failed", pgno)); return rc; } data->mv_data = METADATA(omp); @@ -6374,7 +6374,7 @@ mdb_cursor_sibling(MDB_cursor *mc, int move_right) op = mc->mc_pg[mc->mc_top]; #endif mdb_cursor_pop(mc); - DPRINTF(("parent page is page %"Yu", index %u", + DPRINTF(("parent page is page %"Y"u, index %u", mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top])); if (move_right ? (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mc->mc_pg[mc->mc_top])) @@ -6454,7 +6454,7 @@ mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) } } - DPRINTF(("cursor_next: top page is %"Yu" in cursor %p", + DPRINTF(("cursor_next: top page is %"Y"u in cursor %p", mdb_dbg_pgno(mp), (void *) mc)); if (mc->mc_flags & C_DEL) goto skip; @@ -6466,12 +6466,12 @@ mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) return rc; } mp = mc->mc_pg[mc->mc_top]; - DPRINTF(("next page is %"Yu", key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top])); + DPRINTF(("next page is %"Y"u, key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top])); } else mc->mc_ki[mc->mc_top]++; skip: - DPRINTF(("==> cursor points to page %"Yu" with %u keys, key index %u", + DPRINTF(("==> cursor points to page %"Y"u with %u keys, key index %u", mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top])); if (IS_LEAF2(mp)) { @@ -6540,7 +6540,7 @@ mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) } } - DPRINTF(("cursor_prev: top page is %"Yu" in cursor %p", + DPRINTF(("cursor_prev: top page is %"Y"u in cursor %p", mdb_dbg_pgno(mp), (void *) mc)); if (mc->mc_ki[mc->mc_top] == 0) { @@ -6550,13 +6550,13 @@ mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) } mp = mc->mc_pg[mc->mc_top]; mc->mc_ki[mc->mc_top] = NUMKEYS(mp) - 1; - DPRINTF(("prev page is %"Yu", key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top])); + DPRINTF(("prev page is %"Y"u, key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top])); } else mc->mc_ki[mc->mc_top]--; mc->mc_flags &= ~C_EOF; - DPRINTF(("==> cursor points to page %"Yu" with %u keys, key index %u", + DPRINTF(("==> cursor points to page %"Y"u with %u keys, key index %u", mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top])); if (IS_LEAF2(mp)) { @@ -7749,7 +7749,7 @@ mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp) if ((rc = mdb_page_alloc(mc, num, &np))) return rc; - DPRINTF(("allocated new mpage %"Yu", page size %u", + DPRINTF(("allocated new mpage %"Y"u, page size %u", np->mp_pgno, mc->mc_txn->mt_env->me_psize)); np->mp_flags = flags | P_DIRTY; np->mp_lower = (PAGEHDRSZ-PAGEBASE); @@ -7849,7 +7849,7 @@ mdb_node_add(MDB_cursor *mc, indx_t indx, mdb_cassert(mc, mp->mp_upper >= mp->mp_lower); - DPRINTF(("add to %s %spage %"Yu" index %i, data size %"Z"u key size %"Z"u [%s]", + DPRINTF(("add to %s %spage %"Y"u index %i, data size %"Z"u key size %"Z"u [%s]", IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "", mdb_dbg_pgno(mp), indx, data ? data->mv_size : 0, @@ -7890,7 +7890,7 @@ mdb_node_add(MDB_cursor *mc, indx_t indx, goto full; if ((rc = mdb_page_new(mc, P_OVERFLOW, ovpages, &ofp))) return rc; - DPRINTF(("allocated overflow page %"Yu"", ofp->mp_pgno)); + DPRINTF(("allocated overflow page %"Y"u", ofp->mp_pgno)); flags |= F_BIGDATA; goto update; } else { @@ -7947,7 +7947,7 @@ update: return MDB_SUCCESS; full: - DPRINTF(("not enough room in page %"Yu", got %u ptrs", + DPRINTF(("not enough room in page %"Y"u, got %u ptrs", mdb_dbg_pgno(mp), NUMKEYS(mp))); DPRINTF(("upper-lower = %u - %u = %"Z"d", mp->mp_upper,mp->mp_lower,room)); DPRINTF(("node size = %"Z"u", node_size)); @@ -7970,7 +7970,7 @@ mdb_node_del(MDB_cursor *mc, int ksize) MDB_node *node; char *base; - DPRINTF(("delete node %u on %s page %"Yu"", indx, + DPRINTF(("delete node %u on %s page %"Y"u", indx, IS_LEAF(mp) ? "leaf" : "branch", mdb_dbg_pgno(mp))); numkeys = NUMKEYS(mp); mdb_cassert(mc, indx < numkeys); @@ -8129,7 +8129,7 @@ mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node) mx->mx_db.md_flags |= MDB_INTEGERKEY; } } - DPRINTF(("Sub-db -%u root page %"Yu"", mx->mx_cursor.mc_dbi, + DPRINTF(("Sub-db -%u root page %"Y"u", mx->mx_cursor.mc_dbi, mx->mx_db.md_root)); mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */ #if UINT_MAX < SIZE_MAX || defined(MDB_VL32) @@ -8166,7 +8166,7 @@ mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int new_dupdata) } mx->mx_db = src_mx->mx_db; mx->mx_cursor.mc_pg[0] = src_mx->mx_cursor.mc_pg[0]; - DPRINTF(("Sub-db -%u root page %"Yu"", mx->mx_cursor.mc_dbi, + DPRINTF(("Sub-db -%u root page %"Y"u", mx->mx_cursor.mc_dbi, mx->mx_db.md_root)); } @@ -8338,7 +8338,7 @@ mdb_update_key(MDB_cursor *mc, MDB_val *key) char kbuf2[DKBUF_MAXKEYSIZE*2+1]; k2.mv_data = NODEKEY(node); k2.mv_size = node->mn_ksize; - DPRINTF(("update key %u (ofs %u) [%s] to [%s] on page %"Yu"", + DPRINTF(("update key %u (ofs %u) [%s] to [%s] on page %"Y"u", indx, ptr, mdb_dkey(&k2, kbuf2), DKEY(key), @@ -8486,7 +8486,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) return rc; } - DPRINTF(("moving %s node %u [%s] on page %"Yu" to node %u on page %"Yu"", + DPRINTF(("moving %s node %u [%s] on page %"Y"u to node %u on page %"Y"u", IS_LEAF(csrc->mc_pg[csrc->mc_top]) ? "leaf" : "branch", csrc->mc_ki[csrc->mc_top], DKEY(&key), @@ -8580,7 +8580,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) key.mv_size = NODEKSZ(srcnode); key.mv_data = NODEKEY(srcnode); } - DPRINTF(("update separator for source page %"Yu" to [%s]", + DPRINTF(("update separator for source page %"Y"u to [%s]", csrc->mc_pg[csrc->mc_top]->mp_pgno, DKEY(&key))); mdb_cursor_copy(csrc, &mn); mn.mc_snum--; @@ -8611,7 +8611,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) key.mv_size = NODEKSZ(srcnode); key.mv_data = NODEKEY(srcnode); } - DPRINTF(("update separator for destination page %"Yu" to [%s]", + DPRINTF(("update separator for destination page %"Y"u to [%s]", cdst->mc_pg[cdst->mc_top]->mp_pgno, DKEY(&key))); mdb_cursor_copy(cdst, &mn); mn.mc_snum--; @@ -8657,7 +8657,7 @@ mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst) psrc = csrc->mc_pg[csrc->mc_top]; pdst = cdst->mc_pg[cdst->mc_top]; - DPRINTF(("merging page %"Yu" into %"Yu"", psrc->mp_pgno, pdst->mp_pgno)); + DPRINTF(("merging page %"Y"u into %"Y"u", psrc->mp_pgno, pdst->mp_pgno)); mdb_cassert(csrc, csrc->mc_snum > 1); /* can't merge root page */ mdb_cassert(csrc, cdst->mc_snum > 1); @@ -8714,7 +8714,7 @@ mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst) } } - DPRINTF(("dst page %"Yu" now has %u keys (%.1f%% filled)", + DPRINTF(("dst page %"Y"u now has %u keys (%.1f%% filled)", pdst->mp_pgno, NUMKEYS(pdst), (float)PAGEFILL(cdst->mc_txn->mt_env, pdst) / 10)); @@ -8833,14 +8833,14 @@ mdb_rebalance(MDB_cursor *mc) minkeys = 1; thresh = FILL_THRESHOLD; } - DPRINTF(("rebalancing %s page %"Yu" (has %u keys, %.1f%% full)", + DPRINTF(("rebalancing %s page %"Y"u (has %u keys, %.1f%% full)", IS_LEAF(mc->mc_pg[mc->mc_top]) ? "leaf" : "branch", mdb_dbg_pgno(mc->mc_pg[mc->mc_top]), NUMKEYS(mc->mc_pg[mc->mc_top]), (float)PAGEFILL(mc->mc_txn->mt_env, mc->mc_pg[mc->mc_top]) / 10)); if (PAGEFILL(mc->mc_txn->mt_env, mc->mc_pg[mc->mc_top]) >= thresh && NUMKEYS(mc->mc_pg[mc->mc_top]) >= minkeys) { - DPRINTF(("no need to rebalance page %"Yu", above fill threshold", + DPRINTF(("no need to rebalance page %"Y"u, above fill threshold", mdb_dbg_pgno(mc->mc_pg[mc->mc_top]))); return MDB_SUCCESS; } @@ -8969,7 +8969,7 @@ mdb_rebalance(MDB_cursor *mc) fromleft = 1; } - DPRINTF(("found neighbor page %"Yu" (%u keys, %.1f%% full)", + DPRINTF(("found neighbor page %"Y"u (%u keys, %.1f%% full)", mn.mc_pg[mn.mc_top]->mp_pgno, NUMKEYS(mn.mc_pg[mn.mc_top]), (float)PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) / 10)); @@ -9171,7 +9171,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno newindx = mc->mc_ki[mc->mc_top]; nkeys = NUMKEYS(mp); - DPRINTF(("-----> splitting %s page %"Yu" and adding [%s] at index %i/%i", + DPRINTF(("-----> splitting %s page %"Y"u and adding [%s] at index %i/%i", IS_LEAF(mp) ? "leaf" : "branch", mp->mp_pgno, DKEY(newkey), mc->mc_ki[mc->mc_top], nkeys)); @@ -9179,7 +9179,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno if ((rc = mdb_page_new(mc, mp->mp_flags, 1, &rp))) return rc; rp->mp_pad = mp->mp_pad; - DPRINTF(("new right sibling: page %"Yu"", rp->mp_pgno)); + DPRINTF(("new right sibling: page %"Y"u", rp->mp_pgno)); /* Usually when splitting the root page, the cursor * height is 1. But when called from mdb_update_key, @@ -9197,7 +9197,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno mc->mc_pg[0] = pp; mc->mc_ki[0] = 0; mc->mc_db->md_root = pp->mp_pgno; - DPRINTF(("root split! new root = %"Yu"", pp->mp_pgno)); + DPRINTF(("root split! new root = %"Y"u", pp->mp_pgno)); new_root = mc->mc_db->md_depth++; /* Add left (implicit) pointer. */ @@ -9214,7 +9214,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno ptop = 0; } else { ptop = mc->mc_top-1; - DPRINTF(("parent branch page is %"Yu"", mc->mc_pg[ptop]->mp_pgno)); + DPRINTF(("parent branch page is %"Y"u", mc->mc_pg[ptop]->mp_pgno)); } mdb_cursor_copy(mc, &mn); @@ -10669,7 +10669,7 @@ mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx) if (mr[i].mr_pid) { txnid_t txnid = mr[i].mr_txnid; sprintf(buf, txnid == (txnid_t)-1 ? - "%10d %"Z"x -\n" : "%10d %"Z"x %"Yu"\n", + "%10d %"Z"x -\n" : "%10d %"Z"x %"Y"u\n", (int)mr[i].mr_pid, (size_t)mr[i].mr_tid, txnid); if (first) { first = 0; @@ -10774,7 +10774,7 @@ mdb_reader_check0(MDB_env *env, int rlocked, int *dead) } for (; j<rdrs; j++) if (mr[j].mr_pid == pid) { - DPRINTF(("clear stale reader pid %u txn %"Yd, + DPRINTF(("clear stale reader pid %u txn %"Y"d", (unsigned) pid, mr[j].mr_txnid)); mr[j].mr_pid = 0; count++; diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp index 4799afebc..e37058a99 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.cpp +++ b/src/blockchain_db/berkeleydb/db_bdb.cpp @@ -2200,8 +2200,14 @@ void BlockchainBDB::checkpoint_worker() const LOG_PRINT_L0("Leaving BDB checkpoint thread."); } +bool BlockchainBDB::is_read_only() const +{ + return false; +} + void BlockchainBDB::fixup() { + LOG_PRINT_L3("BlockchainBDB::" << __func__); // Always call parent as well BlockchainDB::fixup(); } diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h index ce3da91e8..906b320c7 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.h +++ b/src/blockchain_db/berkeleydb/db_bdb.h @@ -405,6 +405,9 @@ private: uint64_t get_output_global_index(const uint64_t& amount, const uint64_t& index); void checkpoint_worker() const; void check_open() const; + + virtual bool is_read_only() const; + // // fix up anything that may be wrong due to past bugs virtual void fixup(); diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index 4fa8cce26..0635f2000 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -199,6 +199,11 @@ void BlockchainDB::show_stats() void BlockchainDB::fixup() { + if (is_read_only()) { + LOG_PRINT_L1("Database is opened read only - skipping fixup check"); + return; + } + // There was a bug that would cause key images for transactions without // any outputs to not be added to the spent key image set. There are two // instances of such transactions, in blocks 202612 and 685498. diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 702de18b5..f6f50d2e9 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -503,6 +503,8 @@ public: virtual void set_hard_fork_version(uint64_t height, uint8_t version) = 0; virtual uint8_t get_hard_fork_version(uint64_t height) const = 0; + virtual bool is_read_only() const = 0; + // fix up anything that may be wrong due to past bugs virtual void fixup(); diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 0fd18bc18..9555318a5 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -2502,8 +2502,22 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const return ret; } +bool BlockchainLMDB::is_read_only() const +{ + unsigned int flags; + auto result = mdb_env_get_flags(m_env, &flags); + if (result) + throw0(DB_ERROR(std::string("Error getting database environment info: ").append(mdb_strerror(result)).c_str())); + + if (flags & MDB_RDONLY) + return true; + + return false; +} + void BlockchainLMDB::fixup() { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); // Always call parent as well BlockchainDB::fixup(); } diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index d1d3b942d..7332d64c6 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -266,6 +266,8 @@ private: void check_open() const; + virtual bool is_read_only() const; + // fix up anything that may be wrong due to past bugs virtual void fixup(); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 02cb348d6..141a42f49 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -490,7 +490,7 @@ block Blockchain::pop_block_from_blockchain() } } } - m_tx_pool.on_blockchain_dec(m_blocks.size()-1, get_tail_id()); + m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id()); return popped_block; } @@ -499,11 +499,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b) { LOG_PRINT_L3("Blockchain::" << __func__); CRITICAL_REGION_LOCAL(m_blockchain_lock); - m_transactions.clear(); - m_blocks.clear(); - m_blocks_index.clear(); m_alternative_chains.clear(); - m_outputs.clear(); m_db->reset(); block_verification_context bvc = boost::value_initialized<block_verification_context>(); @@ -1251,7 +1247,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id { // if block parent is not part of main chain or an alternate chain, // we ignore it - CHECK_AND_ASSERT_MES(parent_in_main, false, "internal error: broken imperative condition it_main_prev != m_blocks_index.end()"); + CHECK_AND_ASSERT_MES(parent_in_main, false, "internal error: broken imperative condition: parent_in_main"); complete_timestamps_vector(m_db->get_block_height(b.prev_id), timestamps); } diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 2f9287e81..bc167f489 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -195,8 +195,6 @@ namespace cryptonote mutable epee::critical_section m_blockchain_lock; // TODO: add here reader/writer lock // main chain - blocks_container m_blocks; // height -> block_extended_info - blocks_by_id_index m_blocks_index; // crypto::hash -> height transactions_container m_transactions; size_t m_current_block_cumul_sz_limit; @@ -230,7 +228,6 @@ namespace cryptonote // some invalid blocks blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info - outputs_container m_outputs; checkpoints m_checkpoints; diff --git a/src/cryptonote_core/hardfork.cpp b/src/cryptonote_core/hardfork.cpp index 9bd4a337c..e8ac7be98 100644 --- a/src/cryptonote_core/hardfork.cpp +++ b/src/cryptonote_core/hardfork.cpp @@ -210,7 +210,7 @@ bool HardFork::reorganize_from_block_height(uint64_t height) last_versions[n] = 0; const uint64_t rescan_height = height >= (window_size - 1) ? height - (window_size -1) : 0; const uint8_t start_version = height == 0 ? original_version : db.get_hard_fork_version(height); - while (heights[current_fork_index].version > start_version) { + while (current_fork_index > 0 && heights[current_fork_index].version > start_version) { db.set_hard_fork_starting_height(heights[current_fork_index].version, std::numeric_limits<uint64_t>::max()); --current_fork_index; } @@ -375,7 +375,7 @@ bool HardFork::get_voting_info(uint8_t version, uint32_t &window, uint32_t &vote for (size_t n = version; n < 256; ++n) votes += last_versions[n]; threshold = (window * heights[current_version].threshold + 99) / 100; - assert((votes >= threshold) == enabled); + //assert((votes >= threshold) == enabled); earliest_height = get_earliest_ideal_height_for_version(version); voting = heights.back().version; return enabled; diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index caf8e60ff..d13e09002 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -32,6 +32,7 @@ set(unit_tests_sources base58.cpp blockchain_db.cpp block_reward.cpp + canonical_amounts.cpp chacha8.cpp checkpoints.cpp decompose_amount_into_digits.cpp diff --git a/tests/unit_tests/canonical_amounts.cpp b/tests/unit_tests/canonical_amounts.cpp new file mode 100644 index 000000000..54159d5d4 --- /dev/null +++ b/tests/unit_tests/canonical_amounts.cpp @@ -0,0 +1,83 @@ +// Copyright (c) 2014-2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "gtest/gtest.h" +#include "cryptonote_core/cryptonote_format_utils.h" + +static const uint64_t valid_decomposed_outputs[] = { + (uint64_t)1, (uint64_t)2, (uint64_t)3, (uint64_t)4, (uint64_t)5, (uint64_t)6, (uint64_t)7, (uint64_t)8, (uint64_t)9, // 1 piconero + (uint64_t)10, (uint64_t)20, (uint64_t)30, (uint64_t)40, (uint64_t)50, (uint64_t)60, (uint64_t)70, (uint64_t)80, (uint64_t)90, + (uint64_t)100, (uint64_t)200, (uint64_t)300, (uint64_t)400, (uint64_t)500, (uint64_t)600, (uint64_t)700, (uint64_t)800, (uint64_t)900, + (uint64_t)1000, (uint64_t)2000, (uint64_t)3000, (uint64_t)4000, (uint64_t)5000, (uint64_t)6000, (uint64_t)7000, (uint64_t)8000, (uint64_t)9000, + (uint64_t)10000, (uint64_t)20000, (uint64_t)30000, (uint64_t)40000, (uint64_t)50000, (uint64_t)60000, (uint64_t)70000, (uint64_t)80000, (uint64_t)90000, + (uint64_t)100000, (uint64_t)200000, (uint64_t)300000, (uint64_t)400000, (uint64_t)500000, (uint64_t)600000, (uint64_t)700000, (uint64_t)800000, (uint64_t)900000, + (uint64_t)1000000, (uint64_t)2000000, (uint64_t)3000000, (uint64_t)4000000, (uint64_t)5000000, (uint64_t)6000000, (uint64_t)7000000, (uint64_t)8000000, (uint64_t)9000000, // 1 micronero + (uint64_t)10000000, (uint64_t)20000000, (uint64_t)30000000, (uint64_t)40000000, (uint64_t)50000000, (uint64_t)60000000, (uint64_t)70000000, (uint64_t)80000000, (uint64_t)90000000, + (uint64_t)100000000, (uint64_t)200000000, (uint64_t)300000000, (uint64_t)400000000, (uint64_t)500000000, (uint64_t)600000000, (uint64_t)700000000, (uint64_t)800000000, (uint64_t)900000000, + (uint64_t)1000000000, (uint64_t)2000000000, (uint64_t)3000000000, (uint64_t)4000000000, (uint64_t)5000000000, (uint64_t)6000000000, (uint64_t)7000000000, (uint64_t)8000000000, (uint64_t)9000000000, + (uint64_t)10000000000, (uint64_t)20000000000, (uint64_t)30000000000, (uint64_t)40000000000, (uint64_t)50000000000, (uint64_t)60000000000, (uint64_t)70000000000, (uint64_t)80000000000, (uint64_t)90000000000, + (uint64_t)100000000000, (uint64_t)200000000000, (uint64_t)300000000000, (uint64_t)400000000000, (uint64_t)500000000000, (uint64_t)600000000000, (uint64_t)700000000000, (uint64_t)800000000000, (uint64_t)900000000000, + (uint64_t)1000000000000, (uint64_t)2000000000000, (uint64_t)3000000000000, (uint64_t)4000000000000, (uint64_t)5000000000000, (uint64_t)6000000000000, (uint64_t)7000000000000, (uint64_t)8000000000000, (uint64_t)9000000000000, // 1 monero + (uint64_t)10000000000000, (uint64_t)20000000000000, (uint64_t)30000000000000, (uint64_t)40000000000000, (uint64_t)50000000000000, (uint64_t)60000000000000, (uint64_t)70000000000000, (uint64_t)80000000000000, (uint64_t)90000000000000, + (uint64_t)100000000000000, (uint64_t)200000000000000, (uint64_t)300000000000000, (uint64_t)400000000000000, (uint64_t)500000000000000, (uint64_t)600000000000000, (uint64_t)700000000000000, (uint64_t)800000000000000, (uint64_t)900000000000000, + (uint64_t)1000000000000000, (uint64_t)2000000000000000, (uint64_t)3000000000000000, (uint64_t)4000000000000000, (uint64_t)5000000000000000, (uint64_t)6000000000000000, (uint64_t)7000000000000000, (uint64_t)8000000000000000, (uint64_t)9000000000000000, + (uint64_t)10000000000000000, (uint64_t)20000000000000000, (uint64_t)30000000000000000, (uint64_t)40000000000000000, (uint64_t)50000000000000000, (uint64_t)60000000000000000, (uint64_t)70000000000000000, (uint64_t)80000000000000000, (uint64_t)90000000000000000, + (uint64_t)100000000000000000, (uint64_t)200000000000000000, (uint64_t)300000000000000000, (uint64_t)400000000000000000, (uint64_t)500000000000000000, (uint64_t)600000000000000000, (uint64_t)700000000000000000, (uint64_t)800000000000000000, (uint64_t)900000000000000000, + (uint64_t)1000000000000000000, (uint64_t)2000000000000000000, (uint64_t)3000000000000000000, (uint64_t)4000000000000000000, (uint64_t)5000000000000000000, (uint64_t)6000000000000000000, (uint64_t)7000000000000000000, (uint64_t)8000000000000000000, (uint64_t)9000000000000000000, // 1 meganero + (uint64_t)10000000000000000000ull +}; + +TEST(canonical_amounts, valid) +{ + for (size_t n = 0; n < sizeof(valid_decomposed_outputs) / sizeof(valid_decomposed_outputs[0]); ++n) + { + ASSERT_TRUE(cryptonote::is_valid_decomposed_amount(valid_decomposed_outputs[n])); + } +} + +TEST(canonical_amounts, invalid) +{ + for (size_t n = 0; n < sizeof(valid_decomposed_outputs) / sizeof(valid_decomposed_outputs[0]); ++n) + { + // 10 and below have adjacent valid decomposed amounts + if (valid_decomposed_outputs[n] > 10) + { + ASSERT_FALSE(cryptonote::is_valid_decomposed_amount(valid_decomposed_outputs[n]+1)); + ASSERT_FALSE(cryptonote::is_valid_decomposed_amount(valid_decomposed_outputs[n]-1)); + } + } + + ASSERT_FALSE(cryptonote::is_valid_decomposed_amount(0)); + ASSERT_FALSE(cryptonote::is_valid_decomposed_amount(11)); + ASSERT_FALSE(cryptonote::is_valid_decomposed_amount((uint64_t)-1)); + ASSERT_FALSE(cryptonote::is_valid_decomposed_amount(10000000000001ul)); + ASSERT_FALSE(cryptonote::is_valid_decomposed_amount(11000000000000ul)); +} + |