forked from lthn/blockchain
Merge branch 'pos_impr' into develop
This commit is contained in:
commit
d218716983
73 changed files with 3165 additions and 2040 deletions
|
|
@ -1,14 +1,70 @@
|
|||
LMDB 0.9 Change Log
|
||||
|
||||
LMDB 0.9.18 Release Engineering
|
||||
LMDB 0.9.24 Release (2019/07/24)
|
||||
ITS#8969 Tweak mdb_page_split
|
||||
ITS#8975 WIN32 fix writemap set_mapsize crash
|
||||
ITS#9007 Fix loose pages in WRITEMAP
|
||||
|
||||
LMDB 0.9.23 Release (2018/12/19)
|
||||
ITS#8756 Fix loose pages in dirty list
|
||||
ITS#8831 Fix mdb_load flag init
|
||||
ITS#8844 Fix mdb_env_close in forked process
|
||||
Documentation
|
||||
ITS#8857 mdb_cursor_del doesn't invalidate cursor
|
||||
ITS#8908 GET_MULTIPLE etc don't change passed in key
|
||||
|
||||
LMDB 0.9.22 Release (2018/03/22)
|
||||
Fix MDB_DUPSORT alignment bug (ITS#8819)
|
||||
Fix regression with new db from 0.9.19 (ITS#8760)
|
||||
Fix liblmdb to build on Solaris (ITS#8612)
|
||||
Fix delete behavior with DUPSORT DB (ITS#8622)
|
||||
Fix mdb_cursor_get/mdb_cursor_del behavior (ITS#8722)
|
||||
|
||||
LMDB 0.9.21 Release (2017/06/01)
|
||||
Fix xcursor after cursor_del (ITS#8622)
|
||||
|
||||
LMDB 0.9.20 (Withdrawn)
|
||||
Fix mdb_load with escaped plaintext (ITS#8558)
|
||||
Fix mdb_cursor_last / mdb_put interaction (ITS#8557)
|
||||
|
||||
LMDB 0.9.19 Release (2016/12/28)
|
||||
Fix mdb_env_cwalk cursor init (ITS#8424)
|
||||
Fix robust mutexes on Solaris 10/11 (ITS#8339)
|
||||
Tweak Win32 error message buffer
|
||||
Fix MDB_GET_BOTH on non-dup record (ITS#8393)
|
||||
Optimize mdb_drop
|
||||
Fix xcursors after mdb_cursor_del (ITS#8406)
|
||||
Fix MDB_NEXT_DUP after mdb_cursor_del (ITS#8412)
|
||||
Fix mdb_cursor_put resetting C_EOF (ITS#8489)
|
||||
Fix mdb_env_copyfd2 to return EPIPE on SIGPIPE (ITS#8504)
|
||||
Fix mdb_env_copy with empty DB (ITS#8209)
|
||||
Fix behaviors with fork (ITS#8505)
|
||||
Fix mdb_dbi_open with mainDB cursors (ITS#8542)
|
||||
Fix robust mutexes on kFreeBSD (ITS#8554)
|
||||
Fix utf8_to_utf16 error checks (ITS#7992)
|
||||
Fix F_NOCACHE on MacOS, error is non-fatal (ITS#7682)
|
||||
Build
|
||||
Make shared lib suffix overridable (ITS#8481)
|
||||
Documentation
|
||||
Cleanup doxygen nits
|
||||
Note reserved vs actual mem/disk usage
|
||||
|
||||
|
||||
LMDB 0.9.18 Release (2016/02/05)
|
||||
Fix robust mutex detection on glibc 2.10-11 (ITS#8330)
|
||||
Fix page_search_root assert on FreeDB (ITS#8336)
|
||||
Fix MDB_APPENDDUP vs. rewrite(single item) (ITS#8334)
|
||||
Fix mdb_copy of large files on Windows
|
||||
Fix subcursor move after delete (ITS#8355)
|
||||
Fix mdb_midl_shirnk off-by-one (ITS#8363)
|
||||
Check for utf8_to_utf16 failures (ITS#7992)
|
||||
Catch strdup failure in mdb_dbi_open
|
||||
Build
|
||||
Additional makefile var tweaks (ITS#8169)
|
||||
Documentation
|
||||
Add Getting Started page
|
||||
|
||||
Update WRITEMAP description
|
||||
|
||||
|
||||
LMDB 0.9.17 Release (2015/11/30)
|
||||
Fix ITS#7377 catch calloc failure
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
Copyright 2011-2019 Howard Chu, Symas Corp.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ IDL_PROPERTY_SUPPORT = YES
|
|||
# member in the group (if any) for the other members of the group. By default
|
||||
# all members of a group must be documented explicitly.
|
||||
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
DISTRIBUTE_GROUP_DOC = YES
|
||||
|
||||
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
|
||||
# the same type (for instance a group of public functions) to be put as a
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
# platforms; you should not need to change any of these.
|
||||
# Read their descriptions in mdb.c if you do:
|
||||
#
|
||||
# - MDB_USE_POSIX_MUTEX, MDB_USE_POSIX_SEM, MDB_USE_SYSV_SEM
|
||||
# - MDB_USE_POSIX_SEM
|
||||
# - MDB_DSYNC
|
||||
# - MDB_FDATASYNC
|
||||
# - MDB_FDATASYNC_WORKS
|
||||
|
|
@ -24,8 +24,9 @@ W = -W -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized
|
|||
THREADS = -pthread
|
||||
OPT = -O2 -g
|
||||
CFLAGS = $(THREADS) $(OPT) $(W) $(XCFLAGS)
|
||||
LDLIBS = # -lntdll # Windows needs ntdll
|
||||
SOLIBS = # -lntdll
|
||||
LDLIBS =
|
||||
SOLIBS =
|
||||
SOEXT = .so
|
||||
prefix = /usr/local
|
||||
exec_prefix = $(prefix)
|
||||
bindir = $(exec_prefix)/bin
|
||||
|
|
@ -37,7 +38,7 @@ mandir = $(datarootdir)/man
|
|||
########################################################################
|
||||
|
||||
IHDRS = lmdb.h
|
||||
ILIBS = liblmdb.a liblmdb.so
|
||||
ILIBS = liblmdb.a liblmdb$(SOEXT)
|
||||
IPROGS = mdb_stat mdb_copy mdb_dump mdb_load
|
||||
IDOCS = mdb_stat.1 mdb_copy.1 mdb_dump.1 mdb_load.1
|
||||
PROGS = $(IPROGS) mtest mtest2 mtest3 mtest4 mtest5
|
||||
|
|
@ -63,7 +64,7 @@ test: all
|
|||
liblmdb.a: mdb.o midl.o
|
||||
$(AR) rs $@ mdb.o midl.o
|
||||
|
||||
liblmdb.so: mdb.lo midl.lo
|
||||
liblmdb$(SOEXT): mdb.lo midl.lo
|
||||
# $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS)
|
||||
$(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.lo midl.lo $(SOLIBS)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2015-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -53,15 +53,14 @@
|
|||
*
|
||||
* Fix: Check for stale readers periodically, using the
|
||||
* #mdb_reader_check function or the \ref mdb_stat_1 "mdb_stat" tool.
|
||||
* Stale writers will be cleared automatically on most systems:
|
||||
* Stale writers will be cleared automatically on some systems:
|
||||
* - Windows - automatic
|
||||
* - BSD, systems using SysV semaphores - automatic
|
||||
* - Linux, systems using POSIX mutexes with Robust option - automatic
|
||||
* - not on BSD, systems using POSIX semaphores.
|
||||
* Otherwise just make all programs using the database close it;
|
||||
* the lockfile is always reset on first open of the environment.
|
||||
*
|
||||
* - On BSD systems or others configured with MDB_USE_SYSV_SEM or
|
||||
* MDB_USE_POSIX_SEM,
|
||||
* - On BSD systems or others configured with MDB_USE_POSIX_SEM,
|
||||
* startup can fail due to semaphores owned by another userid.
|
||||
*
|
||||
* Fix: Open and close the database as the user which owns the
|
||||
|
|
@ -97,11 +96,12 @@
|
|||
* transactions. Each transaction belongs to one thread. See below.
|
||||
* The #MDB_NOTLS flag changes this for read-only transactions.
|
||||
*
|
||||
* - Use an MDB_env* in the process which opened it, without fork()ing.
|
||||
* - Use an MDB_env* in the process which opened it, not after fork().
|
||||
*
|
||||
* - Do not have open an LMDB database twice in the same process at
|
||||
* the same time. Not even from a plain open() call - close()ing it
|
||||
* breaks flock() advisory locking.
|
||||
* breaks fcntl() advisory locking. (It is OK to reopen it after
|
||||
* fork() - exec*(), since the lockfile has FD_CLOEXEC set.)
|
||||
*
|
||||
* - Avoid long-lived transactions. Read transactions prevent
|
||||
* reuse of pages freed by newer write transactions, thus the
|
||||
|
|
@ -135,7 +135,7 @@
|
|||
*
|
||||
* @author Howard Chu, Symas Corporation.
|
||||
*
|
||||
* @copyright Copyright 2011-2016 Howard Chu, Symas Corp. All rights reserved.
|
||||
* @copyright Copyright 2011-2019 Howard Chu, Symas Corp. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
|
|
@ -166,7 +166,6 @@
|
|||
#define _LMDB_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -179,13 +178,6 @@ typedef int mdb_mode_t;
|
|||
typedef mode_t mdb_mode_t;
|
||||
#endif
|
||||
|
||||
#ifdef MDB_VL32
|
||||
typedef uint64_t mdb_size_t;
|
||||
#define mdb_env_create mdb_env_create_vl32 /**< Prevent mixing with non-VL32 builds */
|
||||
#else
|
||||
typedef size_t mdb_size_t;
|
||||
#endif
|
||||
|
||||
/** An abstraction for a file handle.
|
||||
* On POSIX systems file handles are small integers. On Windows
|
||||
* they're opaque pointers.
|
||||
|
|
@ -208,7 +200,7 @@ typedef int mdb_filehandle_t;
|
|||
/** Library minor version */
|
||||
#define MDB_VERSION_MINOR 9
|
||||
/** Library patch version */
|
||||
#define MDB_VERSION_PATCH 70
|
||||
#define MDB_VERSION_PATCH 24
|
||||
|
||||
/** Combine args a,b,c into a single integer for easy version comparisons */
|
||||
#define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c))
|
||||
|
|
@ -218,7 +210,7 @@ typedef int mdb_filehandle_t;
|
|||
MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH)
|
||||
|
||||
/** The release date of this library version */
|
||||
#define MDB_VERSION_DATE "December 19, 2015"
|
||||
#define MDB_VERSION_DATE "July 24, 2019"
|
||||
|
||||
/** A stringifier for the version info */
|
||||
#define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")"
|
||||
|
|
@ -311,8 +303,6 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel
|
|||
#define MDB_NORDAHEAD 0x800000
|
||||
/** don't initialize malloc'd memory before writing to datafile */
|
||||
#define MDB_NOMEMINIT 0x1000000
|
||||
/** use the previous snapshot rather than the latest one */
|
||||
#define MDB_PREVSNAPSHOT 0x2000000
|
||||
/** @} */
|
||||
|
||||
/** @defgroup mdb_dbi_open Database Flags
|
||||
|
|
@ -380,7 +370,7 @@ typedef enum MDB_cursor_op {
|
|||
MDB_GET_BOTH, /**< Position at key/data pair. Only for #MDB_DUPSORT */
|
||||
MDB_GET_BOTH_RANGE, /**< position at key, nearest data. Only for #MDB_DUPSORT */
|
||||
MDB_GET_CURRENT, /**< Return key/data at current cursor position */
|
||||
MDB_GET_MULTIPLE, /**< Return key and up to a page of duplicate data items
|
||||
MDB_GET_MULTIPLE, /**< Return up to a page of duplicate data items
|
||||
from current cursor position. Move cursor to prepare
|
||||
for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */
|
||||
MDB_LAST, /**< Position at last key/data item */
|
||||
|
|
@ -389,7 +379,7 @@ typedef enum MDB_cursor_op {
|
|||
MDB_NEXT, /**< Position at next data item */
|
||||
MDB_NEXT_DUP, /**< Position at next data item of current key.
|
||||
Only for #MDB_DUPSORT */
|
||||
MDB_NEXT_MULTIPLE, /**< Return key and up to a page of duplicate data items
|
||||
MDB_NEXT_MULTIPLE, /**< Return up to a page of duplicate data items
|
||||
from next cursor position. Move cursor to prepare
|
||||
for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */
|
||||
MDB_NEXT_NODUP, /**< Position at first data item of next key */
|
||||
|
|
@ -400,7 +390,7 @@ typedef enum MDB_cursor_op {
|
|||
MDB_SET, /**< Position at specified key */
|
||||
MDB_SET_KEY, /**< Position at specified key, return key + data */
|
||||
MDB_SET_RANGE, /**< Position at first key greater than or equal to specified key. */
|
||||
MDB_PREV_MULTIPLE /**< Position at previous page and return key and up to
|
||||
MDB_PREV_MULTIPLE /**< Position at previous page and return up to
|
||||
a page of duplicate data items. Only for #MDB_DUPFIXED */
|
||||
} MDB_cursor_op;
|
||||
|
||||
|
|
@ -467,18 +457,18 @@ typedef struct MDB_stat {
|
|||
unsigned int ms_psize; /**< Size of a database page.
|
||||
This is currently the same for all databases. */
|
||||
unsigned int ms_depth; /**< Depth (height) of the B-tree */
|
||||
mdb_size_t ms_branch_pages; /**< Number of internal (non-leaf) pages */
|
||||
mdb_size_t ms_leaf_pages; /**< Number of leaf pages */
|
||||
mdb_size_t ms_overflow_pages; /**< Number of overflow pages */
|
||||
mdb_size_t ms_entries; /**< Number of data items */
|
||||
size_t ms_branch_pages; /**< Number of internal (non-leaf) pages */
|
||||
size_t ms_leaf_pages; /**< Number of leaf pages */
|
||||
size_t ms_overflow_pages; /**< Number of overflow pages */
|
||||
size_t ms_entries; /**< Number of data items */
|
||||
} MDB_stat;
|
||||
|
||||
/** @brief Information about the environment */
|
||||
typedef struct MDB_envinfo {
|
||||
void *me_mapaddr; /**< Address of map, if fixed */
|
||||
mdb_size_t me_mapsize; /**< Size of the data memory map */
|
||||
mdb_size_t me_last_pgno; /**< ID of the last used page */
|
||||
mdb_size_t me_last_txnid; /**< ID of the last committed transaction */
|
||||
size_t me_mapsize; /**< Size of the data memory map */
|
||||
size_t me_last_pgno; /**< ID of the last used page */
|
||||
size_t me_last_txnid; /**< ID of the last committed transaction */
|
||||
unsigned int me_maxreaders; /**< max reader slots in the environment */
|
||||
unsigned int me_numreaders; /**< max reader slots used in the environment */
|
||||
} MDB_envinfo;
|
||||
|
|
@ -624,12 +614,6 @@ int mdb_env_create(MDB_env **env);
|
|||
* caller is expected to overwrite all of the memory that was
|
||||
* reserved in that case.
|
||||
* This flag may be changed at any time using #mdb_env_set_flags().
|
||||
* <li>#MDB_PREVSNAPSHOT
|
||||
* Open the environment with the previous snapshot rather than the latest
|
||||
* one. This loses the latest transaction, but may help work around some
|
||||
* types of corruption. If opened with write access, this must be the
|
||||
* only process using the environment. This flag is automatically reset
|
||||
* after a write transaction is successfully committed.
|
||||
* </ul>
|
||||
* @param[in] mode The UNIX permissions to set on created files and semaphores.
|
||||
* This parameter is ignored on Windows.
|
||||
|
|
@ -696,6 +680,7 @@ int mdb_env_copyfd(MDB_env *env, mdb_filehandle_t fd);
|
|||
* <li>#MDB_CP_COMPACT - Perform compaction while copying: omit free
|
||||
* pages and sequentially renumber all pages in output. This option
|
||||
* consumes more CPU and runs more slowly than the default.
|
||||
* Currently it fails if the environment has suffered a page leak.
|
||||
* </ul>
|
||||
* @return A non-zero error value on failure and 0 on success.
|
||||
*/
|
||||
|
|
@ -810,6 +795,10 @@ int mdb_env_get_flags(MDB_env *env, unsigned int *flags);
|
|||
int mdb_env_get_path(MDB_env *env, const char **path);
|
||||
|
||||
/** @brief Return the filedescriptor for the given environment.
|
||||
*
|
||||
* This function may be called after fork(), so the descriptor can be
|
||||
* closed before exec*(). Other LMDB file descriptors have FD_CLOEXEC.
|
||||
* (Until LMDB 0.9.18, only the lockfile had that.)
|
||||
*
|
||||
* @param[in] env An environment handle returned by #mdb_env_create()
|
||||
* @param[out] fd Address of a mdb_filehandle_t to contain the descriptor.
|
||||
|
|
@ -853,7 +842,7 @@ int mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *fd);
|
|||
* an active write transaction.
|
||||
* </ul>
|
||||
*/
|
||||
int mdb_env_set_mapsize(MDB_env *env, mdb_size_t size);
|
||||
int mdb_env_set_mapsize(MDB_env *env, size_t size);
|
||||
|
||||
/** @brief Set the maximum number of threads/reader slots for the environment.
|
||||
*
|
||||
|
|
@ -966,10 +955,6 @@ int mdb_env_set_assert(MDB_env *env, MDB_assert_func *func);
|
|||
* <ul>
|
||||
* <li>#MDB_RDONLY
|
||||
* This transaction will not perform any write operations.
|
||||
* <li>#MDB_NOSYNC
|
||||
* Don't flush system buffers to disk when committing this transaction.
|
||||
* <li>#MDB_NOMETASYNC
|
||||
* Flush system buffers but omit metadata flush when committing this transaction.
|
||||
* </ul>
|
||||
* @param[out] txn Address where the new #MDB_txn handle will be stored
|
||||
* @return A non-zero error value on failure and 0 on success. Some possible
|
||||
|
|
@ -1002,7 +987,7 @@ MDB_env *mdb_txn_env(MDB_txn *txn);
|
|||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @return A transaction ID, valid if input is an active transaction.
|
||||
*/
|
||||
mdb_size_t mdb_txn_id(MDB_txn *txn);
|
||||
size_t mdb_txn_id(MDB_txn *txn);
|
||||
|
||||
/** @brief Commit all the operations of a transaction into the database.
|
||||
*
|
||||
|
|
@ -1118,8 +1103,9 @@ int mdb_txn_renew(MDB_txn *txn);
|
|||
* This flag may only be used in combination with #MDB_DUPSORT. This option
|
||||
* tells the library that the data items for this database are all the same
|
||||
* size, which allows further optimizations in storage and retrieval. When
|
||||
* all data items are the same size, the #MDB_GET_MULTIPLE and #MDB_NEXT_MULTIPLE
|
||||
* cursor operations may be used to retrieve multiple items at once.
|
||||
* all data items are the same size, the #MDB_GET_MULTIPLE, #MDB_NEXT_MULTIPLE
|
||||
* and #MDB_PREV_MULTIPLE cursor operations may be used to retrieve multiple
|
||||
* items at once.
|
||||
* <li>#MDB_INTEGERDUP
|
||||
* This option specifies that duplicate data items are binary integers,
|
||||
* similar to #MDB_INTEGERKEY keys.
|
||||
|
|
@ -1524,6 +1510,10 @@ int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
|
|||
/** @brief Delete current key/data pair
|
||||
*
|
||||
* This function deletes the key/data pair to which the cursor refers.
|
||||
* This does not invalidate the cursor, so operations such as MDB_NEXT
|
||||
* can still be used on it.
|
||||
* Both MDB_NEXT and MDB_GET_CURRENT will return the same record after
|
||||
* this operation.
|
||||
* @param[in] cursor A cursor handle returned by #mdb_cursor_open()
|
||||
* @param[in] flags Options for this operation. This parameter
|
||||
* must be set to 0 or one of the values described here.
|
||||
|
|
@ -1552,7 +1542,7 @@ int mdb_cursor_del(MDB_cursor *cursor, unsigned int flags);
|
|||
* <li>EINVAL - cursor is not initialized, or an invalid parameter was specified.
|
||||
* </ul>
|
||||
*/
|
||||
int mdb_cursor_count(MDB_cursor *cursor, mdb_size_t *countp);
|
||||
int mdb_cursor_count(MDB_cursor *cursor, size_t *countp);
|
||||
|
||||
/** @brief Compare two data items according to a particular database.
|
||||
*
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
.TH MDB_COPY 1 "2014/06/20" "LMDB 0.9.14"
|
||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.TH MDB_COPY 1 "2014/07/01" "LMDB 0.9.14"
|
||||
.\" Copyright 2012-2018 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_copy \- LMDB environment copy tool
|
||||
|
|
@ -11,8 +11,6 @@ mdb_copy \- LMDB environment copy tool
|
|||
.BR \-c ]
|
||||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
.B srcpath
|
||||
[\c
|
||||
.BR dstpath ]
|
||||
|
|
@ -38,13 +36,10 @@ Write the library version number to the standard output, and exit.
|
|||
Compact while copying. Only current data pages will be copied; freed
|
||||
or unused pages will be omitted from the copy. This option will
|
||||
slow down the backup process as it is more CPU-intensive.
|
||||
Currently it fails if the environment has suffered a page leak.
|
||||
.TP
|
||||
.BR \-n
|
||||
Open LDMB environment(s) which do not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is zero if no errors occur.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mdb_copy.c - memory-mapped database backup tool */
|
||||
/*
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2012-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -38,8 +38,6 @@ int main(int argc,char * argv[])
|
|||
for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
|
||||
if (argv[1][1] == 'n' && argv[1][2] == '\0')
|
||||
flags |= MDB_NOSUBDIR;
|
||||
else if (argv[1][1] == 'v' && argv[1][2] == '\0')
|
||||
flags |= MDB_PREVSNAPSHOT;
|
||||
else if (argv[1][1] == 'c' && argv[1][2] == '\0')
|
||||
cpflags |= MDB_CP_COMPACT;
|
||||
else if (argv[1][1] == 'V' && argv[1][2] == '\0') {
|
||||
|
|
@ -50,7 +48,7 @@ int main(int argc,char * argv[])
|
|||
}
|
||||
|
||||
if (argc<2 || argc>3) {
|
||||
fprintf(stderr, "usage: %s [-V] [-c] [-n] [-v] srcpath [dstpath]\n", progname);
|
||||
fprintf(stderr, "usage: %s [-V] [-c] [-n] srcpath [dstpath]\n", progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.TH MDB_DUMP 1 "2014/06/20" "LMDB 0.9.14"
|
||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.TH MDB_DUMP 1 "2015/09/30" "LMDB 0.9.17"
|
||||
.\" Copyright 2014-2018 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_dump \- LMDB environment export tool
|
||||
|
|
@ -14,8 +14,6 @@ mdb_dump \- LMDB environment export tool
|
|||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
[\c
|
||||
.BR \-p ]
|
||||
[\c
|
||||
.BR \-a \ |
|
||||
|
|
@ -44,10 +42,6 @@ names will be listed, no data will be output.
|
|||
.BR \-n
|
||||
Dump an LMDB database which does not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
.TP
|
||||
.BR \-p
|
||||
If characters in either the key or data items are printing characters (as
|
||||
defined by isprint(3)), output them directly. This option permits users to
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mdb_dump.c - memory-mapped database dump tool */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -25,15 +25,6 @@
|
|||
#else
|
||||
#define Z "z"
|
||||
#endif
|
||||
#ifdef MDB_VL32
|
||||
#ifdef _WIN32
|
||||
#define Y "I64"
|
||||
#else
|
||||
#define Y "ll"
|
||||
#endif
|
||||
#else
|
||||
#define Y Z
|
||||
#endif
|
||||
|
||||
#define PRINT 1
|
||||
static int mode;
|
||||
|
|
@ -124,7 +115,7 @@ static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name)
|
|||
if (name)
|
||||
printf("database=%s\n", name);
|
||||
printf("type=btree\n");
|
||||
printf("mapsize=%" Y "u\n", info.me_mapsize);
|
||||
printf("mapsize=%" Z "u\n", info.me_mapsize);
|
||||
if (info.me_mapaddr)
|
||||
printf("mapaddr=%p\n", info.me_mapaddr);
|
||||
printf("maxreaders=%u\n", info.me_maxreaders);
|
||||
|
|
@ -164,7 +155,7 @@ static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name)
|
|||
|
||||
static void usage(char *prog)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-v] [-a|-s subdb] dbpath\n", prog);
|
||||
fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-a|-s subdb] dbpath\n", prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +179,6 @@ int main(int argc, char *argv[])
|
|||
* -n: use NOSUBDIR flag on env_open
|
||||
* -p: use printable characters
|
||||
* -f: write to file instead of stdout
|
||||
* -v: use previous snapshot
|
||||
* -V: print version and exit
|
||||
* (default) dump only the main DB
|
||||
*/
|
||||
|
|
@ -216,9 +206,6 @@ int main(int argc, char *argv[])
|
|||
case 'n':
|
||||
envflags |= MDB_NOSUBDIR;
|
||||
break;
|
||||
case 'v':
|
||||
envflags |= MDB_PREVSNAPSHOT;
|
||||
break;
|
||||
case 'p':
|
||||
mode |= PRINT;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.TH MDB_LOAD 1 "2014/06/20" "LMDB 0.9.14"
|
||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.TH MDB_LOAD 1 "2015/09/30" "LMDB 0.9.17"
|
||||
.\" Copyright 2014-2018 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_load \- LMDB environment import tool
|
||||
|
|
@ -37,13 +37,6 @@ option below.
|
|||
.BR \-V
|
||||
Write the library version number to the standard output, and exit.
|
||||
.TP
|
||||
.BR \-a
|
||||
Append all records in the order they appear in the input. The input is assumed to already be
|
||||
in correctly sorted order and no sorting or checking for redundant values will be performed.
|
||||
This option must be used to reload data that was produced by running
|
||||
.B mdb_dump
|
||||
on a database that uses custom compare functions.
|
||||
.TP
|
||||
.BR \-f \ file
|
||||
Read from the specified file instead of from the standard input.
|
||||
.TP
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mdb_load.c - memory-mapped database load tool */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -37,22 +37,12 @@ static int Eof;
|
|||
static MDB_envinfo info;
|
||||
|
||||
static MDB_val kbuf, dbuf;
|
||||
static MDB_val k0buf;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define Z "I"
|
||||
#else
|
||||
#define Z "z"
|
||||
#endif
|
||||
#ifdef MDB_VL32
|
||||
#ifdef _WIN32
|
||||
#define Y "I64"
|
||||
#else
|
||||
#define Y "ll"
|
||||
#endif
|
||||
#else
|
||||
#define Y Z
|
||||
#endif
|
||||
|
||||
#define STRLENOF(s) (sizeof(s)-1)
|
||||
|
||||
|
|
@ -78,6 +68,7 @@ static void readhdr(void)
|
|||
{
|
||||
char *ptr;
|
||||
|
||||
flags = 0;
|
||||
while (fgets(dbuf.mv_data, dbuf.mv_size, stdin) != NULL) {
|
||||
lineno++;
|
||||
if (!strncmp(dbuf.mv_data, "VERSION=", STRLENOF("VERSION="))) {
|
||||
|
|
@ -122,7 +113,7 @@ static void readhdr(void)
|
|||
int i;
|
||||
ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
|
||||
if (ptr) *ptr = '\0';
|
||||
i = sscanf((char *)dbuf.mv_data+STRLENOF("mapsize="), "%" Y "u", &info.me_mapsize);
|
||||
i = sscanf((char *)dbuf.mv_data+STRLENOF("mapsize="), "%" Z "u", &info.me_mapsize);
|
||||
if (i != 1) {
|
||||
fprintf(stderr, "%s: line %" Z "d: invalid mapsize %s\n",
|
||||
prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapsize="));
|
||||
|
|
@ -258,7 +249,8 @@ badend:
|
|||
c2 += 2;
|
||||
}
|
||||
} else {
|
||||
c1++; c2++;
|
||||
/* copies are redundant when no escapes were used */
|
||||
*c1++ = *c2++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -286,15 +278,10 @@ badend:
|
|||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-V] [-a] [-f input] [-n] [-s name] [-N] [-T] dbpath\n", prog);
|
||||
fprintf(stderr, "usage: %s [-V] [-f input] [-n] [-s name] [-N] [-T] dbpath\n", prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int greater(const MDB_val *a, const MDB_val *b)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, rc;
|
||||
|
|
@ -304,8 +291,7 @@ int main(int argc, char *argv[])
|
|||
MDB_dbi dbi;
|
||||
char *envname;
|
||||
int envflags = 0, putflags = 0;
|
||||
int dohdr = 0, append = 0;
|
||||
MDB_val prevk;
|
||||
int dohdr = 0;
|
||||
|
||||
prog = argv[0];
|
||||
|
||||
|
|
@ -313,23 +299,19 @@ int main(int argc, char *argv[])
|
|||
usage();
|
||||
}
|
||||
|
||||
/* -a: append records in input order
|
||||
* -f: load file instead of stdin
|
||||
/* -f: load file instead of stdin
|
||||
* -n: use NOSUBDIR flag on env_open
|
||||
* -s: load into named subDB
|
||||
* -N: use NOOVERWRITE on puts
|
||||
* -T: read plaintext
|
||||
* -V: print version and exit
|
||||
*/
|
||||
while ((i = getopt(argc, argv, "af:ns:NTV")) != EOF) {
|
||||
while ((i = getopt(argc, argv, "f:ns:NTV")) != EOF) {
|
||||
switch(i) {
|
||||
case 'V':
|
||||
printf("%s\n", MDB_VERSION_STRING);
|
||||
exit(0);
|
||||
break;
|
||||
case 'a':
|
||||
append = 1;
|
||||
break;
|
||||
case 'f':
|
||||
if (freopen(optarg, "r", stdin) == NULL) {
|
||||
fprintf(stderr, "%s: %s: reopen: %s\n",
|
||||
|
|
@ -388,17 +370,11 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
kbuf.mv_size = mdb_env_get_maxkeysize(env) * 2 + 2;
|
||||
kbuf.mv_data = malloc(kbuf.mv_size * 2);
|
||||
k0buf.mv_size = kbuf.mv_size;
|
||||
k0buf.mv_data = (char *)kbuf.mv_data + kbuf.mv_size;
|
||||
prevk.mv_size = 0;
|
||||
prevk.mv_data = k0buf.mv_data;
|
||||
kbuf.mv_data = malloc(kbuf.mv_size);
|
||||
|
||||
while(!Eof) {
|
||||
MDB_val key, data;
|
||||
int batch = 0;
|
||||
flags = 0;
|
||||
int appflag;
|
||||
|
||||
if (!dohdr) {
|
||||
dohdr = 1;
|
||||
|
|
@ -416,11 +392,6 @@ int main(int argc, char *argv[])
|
|||
fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
if (append) {
|
||||
mdb_set_compare(txn, dbi, greater);
|
||||
if (flags & MDB_DUPSORT)
|
||||
mdb_set_dupsort(txn, dbi, greater);
|
||||
}
|
||||
|
||||
rc = mdb_cursor_open(txn, dbi, &mc);
|
||||
if (rc) {
|
||||
|
|
@ -439,20 +410,7 @@ int main(int argc, char *argv[])
|
|||
goto txn_abort;
|
||||
}
|
||||
|
||||
if (append) {
|
||||
appflag = MDB_APPEND;
|
||||
if (flags & MDB_DUPSORT) {
|
||||
if (prevk.mv_size == key.mv_size && !memcmp(prevk.mv_data, key.mv_data, key.mv_size))
|
||||
appflag = MDB_APPENDDUP;
|
||||
else {
|
||||
memcpy(prevk.mv_data, key.mv_data, key.mv_size);
|
||||
prevk.mv_size = key.mv_size;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
appflag = 0;
|
||||
}
|
||||
rc = mdb_cursor_put(mc, &key, &data, putflags|appflag);
|
||||
rc = mdb_cursor_put(mc, &key, &data, putflags);
|
||||
if (rc == MDB_KEYEXIST && putflags)
|
||||
continue;
|
||||
if (rc) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.TH MDB_STAT 1 "2014/06/20" "LMDB 0.9.14"
|
||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.TH MDB_STAT 1 "2015/09/30" "LMDB 0.9.17"
|
||||
.\" Copyright 2012-2018 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_stat \- LMDB environment status tool
|
||||
|
|
@ -14,8 +14,6 @@ mdb_stat \- LMDB environment status tool
|
|||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
[\c
|
||||
.BR \-r [ r ]]
|
||||
[\c
|
||||
.BR \-a \ |
|
||||
|
|
@ -41,10 +39,6 @@ If \fB\-fff\fP is given, display the full list of page IDs in the freelist.
|
|||
.BR \-n
|
||||
Display the status of an LMDB database which does not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
.TP
|
||||
.BR \-r
|
||||
Display information about the environment reader table.
|
||||
Shows the process ID, thread ID, and transaction ID for each active
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mdb_stat.c - memory-mapped database status tool */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -22,15 +22,6 @@
|
|||
#else
|
||||
#define Z "z"
|
||||
#endif
|
||||
#ifdef MDB_VL32
|
||||
#ifdef _WIN32
|
||||
#define Y "I64"
|
||||
#else
|
||||
#define Y "ll"
|
||||
#endif
|
||||
#else
|
||||
#define Y Z
|
||||
#endif
|
||||
|
||||
static void prstat(MDB_stat *ms)
|
||||
{
|
||||
|
|
@ -38,15 +29,15 @@ static void prstat(MDB_stat *ms)
|
|||
printf(" Page size: %u\n", ms->ms_psize);
|
||||
#endif
|
||||
printf(" Tree depth: %u\n", ms->ms_depth);
|
||||
printf(" Branch pages: %"Y"u\n", ms->ms_branch_pages);
|
||||
printf(" Leaf pages: %"Y"u\n", ms->ms_leaf_pages);
|
||||
printf(" Overflow pages: %"Y"u\n", ms->ms_overflow_pages);
|
||||
printf(" Entries: %"Y"u\n", ms->ms_entries);
|
||||
printf(" Branch pages: %"Z"u\n", ms->ms_branch_pages);
|
||||
printf(" Leaf pages: %"Z"u\n", ms->ms_leaf_pages);
|
||||
printf(" Overflow pages: %"Z"u\n", ms->ms_overflow_pages);
|
||||
printf(" Entries: %"Z"u\n", ms->ms_entries);
|
||||
}
|
||||
|
||||
static void usage(char *prog)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-v] [-a|-s subdb] dbpath\n", prog);
|
||||
fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-a|-s subdb] dbpath\n", prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +64,6 @@ int main(int argc, char *argv[])
|
|||
* -f: print freelist info
|
||||
* -r: print reader info
|
||||
* -n: use NOSUBDIR flag on env_open
|
||||
* -v: use previous snapshot
|
||||
* -V: print version and exit
|
||||
* (default) print stat of only the main DB
|
||||
*/
|
||||
|
|
@ -97,9 +87,6 @@ int main(int argc, char *argv[])
|
|||
case 'n':
|
||||
envflags |= MDB_NOSUBDIR;
|
||||
break;
|
||||
case 'v':
|
||||
envflags |= MDB_PREVSNAPSHOT;
|
||||
break;
|
||||
case 'r':
|
||||
rdrinfo++;
|
||||
break;
|
||||
|
|
@ -138,11 +125,11 @@ int main(int argc, char *argv[])
|
|||
(void)mdb_env_info(env, &mei);
|
||||
printf("Environment Info\n");
|
||||
printf(" Map address: %p\n", mei.me_mapaddr);
|
||||
printf(" Map size: %"Y"u\n", mei.me_mapsize);
|
||||
printf(" Map size: %"Z"u\n", mei.me_mapsize);
|
||||
printf(" Page size: %u\n", mst.ms_psize);
|
||||
printf(" Max pages: %"Y"u\n", mei.me_mapsize / mst.ms_psize);
|
||||
printf(" Number of pages used: %"Y"u\n", mei.me_last_pgno+1);
|
||||
printf(" Last transaction ID: %"Y"u\n", mei.me_last_txnid);
|
||||
printf(" Max pages: %"Z"u\n", mei.me_mapsize / mst.ms_psize);
|
||||
printf(" Number of pages used: %"Z"u\n", mei.me_last_pgno+1);
|
||||
printf(" Last transaction ID: %"Z"u\n", mei.me_last_txnid);
|
||||
printf(" Max readers: %u\n", mei.me_maxreaders);
|
||||
printf(" Number of readers used: %u\n", mei.me_numreaders);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2015 The OpenLDAP Foundation.
|
||||
* Copyright 2000-2019 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2001-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -354,67 +355,5 @@ int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id )
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MDB_VL32
|
||||
unsigned mdb_mid3l_search( MDB_ID3L ids, MDB_ID id )
|
||||
{
|
||||
/*
|
||||
* binary search of id in ids
|
||||
* if found, returns position of id
|
||||
* if not found, returns first position greater than id
|
||||
*/
|
||||
unsigned base = 0;
|
||||
unsigned cursor = 1;
|
||||
int val = 0;
|
||||
unsigned n = (unsigned)ids[0].mid;
|
||||
|
||||
while( 0 < n ) {
|
||||
unsigned pivot = n >> 1;
|
||||
cursor = base + pivot + 1;
|
||||
val = CMP( id, ids[cursor].mid );
|
||||
|
||||
if( val < 0 ) {
|
||||
n = pivot;
|
||||
|
||||
} else if ( val > 0 ) {
|
||||
base = cursor;
|
||||
n -= pivot + 1;
|
||||
|
||||
} else {
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
if( val > 0 ) {
|
||||
++cursor;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
int mdb_mid3l_insert( MDB_ID3L ids, MDB_ID3 *id )
|
||||
{
|
||||
unsigned x, i;
|
||||
|
||||
x = mdb_mid3l_search( ids, id->mid );
|
||||
|
||||
if( x < 1 ) {
|
||||
/* internal error */
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ( x <= ids[0].mid && ids[x].mid == id->mid ) {
|
||||
/* duplicate */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* insert id */
|
||||
ids[0].mid++;
|
||||
for (i=(unsigned)ids[0].mid; i>x; i--)
|
||||
ids[i] = ids[i-1];
|
||||
ids[x] = *id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* MDB_VL32 */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@
|
|||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2015 The OpenLDAP Foundation.
|
||||
* Copyright 2000-2019 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2001-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -27,7 +28,6 @@
|
|||
#define _MDB_MIDL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -43,11 +43,7 @@ extern "C" {
|
|||
/** A generic unsigned ID number. These were entryIDs in back-bdb.
|
||||
* Preferably it should have the same size as a pointer.
|
||||
*/
|
||||
#ifdef MDB_VL32
|
||||
typedef uint64_t MDB_ID;
|
||||
#else
|
||||
typedef size_t MDB_ID;
|
||||
#endif
|
||||
|
||||
/** An IDL is an ID List, a sorted array of IDs. The first
|
||||
* element of the array is a counter for how many actual
|
||||
|
|
@ -182,20 +178,6 @@ int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id );
|
|||
*/
|
||||
int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id );
|
||||
|
||||
#ifdef MDB_VL32
|
||||
typedef struct MDB_ID3 {
|
||||
MDB_ID mid; /**< The ID */
|
||||
void *mptr; /**< The pointer */
|
||||
unsigned int mcnt; /**< Number of pages */
|
||||
unsigned int mref; /**< Refcounter */
|
||||
} MDB_ID3;
|
||||
|
||||
typedef MDB_ID3 *MDB_ID3L;
|
||||
|
||||
unsigned mdb_mid3l_search( MDB_ID3L ids, MDB_ID id );
|
||||
int mdb_mid3l_insert( MDB_ID3L ids, MDB_ID3 *id );
|
||||
|
||||
#endif /* MDB_VL32 */
|
||||
/** @} */
|
||||
/** @} */
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mtest.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mtest2.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mtest3.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mtest4.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mtest5.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* mtest6.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2011-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* Do a line-by-line comparison of this and sample-mdb.txt
|
||||
*/
|
||||
/*
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2012-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* Do a line-by-line comparison of this and sample-bdb.txt
|
||||
*/
|
||||
/*
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2012-2018 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -251,6 +251,21 @@ DISABLE_VS_WARNINGS(4100)
|
|||
custom_code; \
|
||||
}
|
||||
|
||||
|
||||
#define CATCH_ENTRY_WITH_FORWARDING_EXCEPTION() } \
|
||||
catch(const std::exception& ex) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << LOCATION_SS << "], what=" << ex.what()); \
|
||||
throw std::runtime_error(std::string("[EXCEPTION FORWARDED]: ") + ex.what()); \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << LOCATION_SS << "], generic unknown exception \"...\""); \
|
||||
throw std::runtime_error("[EXCEPTION FORWARDED]"); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define NESTED_TRY_ENTRY() try { TRY_ENTRY();
|
||||
|
||||
#define NESTED_CATCH_ENTRY(location) \
|
||||
|
|
|
|||
|
|
@ -7,8 +7,13 @@
|
|||
#include "misc_language.h"
|
||||
#include "string_coding.h"
|
||||
#include "profile_tools.h"
|
||||
#include "util.h"
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
#define DB_RESIZE_MIN_FREE_SIZE (100 * 1024 * 1024) // DB map size will grow if that much space left on DB
|
||||
#define DB_RESIZE_MIN_MAX_SIZE (50 * 1024 * 1024) // Minimum DB map size (starting size)
|
||||
#define DB_RESIZE_INCREMENT_SIZE (100 * 1024 * 1024) // Grow step size
|
||||
#define DB_RESIZE_COMMITS_TO_CHECK 50
|
||||
|
||||
#define CHECK_AND_ASSERT_MESS_LMDB_DB(rc, ret, mess) CHECK_AND_ASSERT_MES(res == MDB_SUCCESS, ret, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
#define CHECK_AND_ASSERT_THROW_MESS_LMDB_DB(rc, mess) CHECK_AND_ASSERT_THROW_MES(res == MDB_SUCCESS, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
|
|
@ -22,10 +27,13 @@ namespace tools
|
|||
{
|
||||
namespace db
|
||||
{
|
||||
lmdb_db_backend::lmdb_db_backend() : m_penv(AUTO_VAL_INIT(m_penv))
|
||||
lmdb_db_backend::lmdb_db_backend()
|
||||
: m_penv(AUTO_VAL_INIT(m_penv))
|
||||
, m_commits_count(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
lmdb_db_backend::~lmdb_db_backend()
|
||||
{
|
||||
NESTED_TRY_ENTRY();
|
||||
|
|
@ -44,16 +52,17 @@ namespace tools
|
|||
res = mdb_env_set_maxdbs(m_penv, 15);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_maxdbs");
|
||||
|
||||
res = mdb_env_set_mapsize(m_penv, cache_sz);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_mapsize");
|
||||
|
||||
m_path = path_;
|
||||
#ifdef WIN32
|
||||
m_path = epee::string_encoding::convert_ansii_to_utf8(m_path);
|
||||
#endif
|
||||
|
||||
res = mdb_env_open(m_penv, m_path.c_str(), MDB_NORDAHEAD , 0644);
|
||||
CHECK_AND_ASSERT_MES(tools::create_directories_if_necessary(m_path), false, "create_directories_if_necessary failed: " << m_path);
|
||||
|
||||
res = mdb_env_open(m_penv, m_path.c_str(), MDB_NORDAHEAD /*| MDB_NOSYNC | MDB_WRITEMAP | MDB_MAPASYNC*/, 0644);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_open, m_path=" << m_path);
|
||||
|
||||
resize_if_needed();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -102,6 +111,13 @@ namespace tools
|
|||
{
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE LOCKED", LOG_LEVEL_3);
|
||||
CRITICAL_SECTION_LOCK(m_write_exclusive_lock);
|
||||
|
||||
if (m_commits_count.fetch_add(1, std::memory_order_relaxed) % DB_RESIZE_COMMITS_TO_CHECK == DB_RESIZE_COMMITS_TO_CHECK - 1)
|
||||
{
|
||||
if (!resize_if_needed())
|
||||
m_commits_count.store(DB_RESIZE_COMMITS_TO_CHECK - 1, std::memory_order_relaxed); // if failed, try again on next commit
|
||||
}
|
||||
|
||||
}
|
||||
PROFILE_FUNC("lmdb_db_backend::begin_transaction");
|
||||
{
|
||||
|
|
@ -326,6 +342,7 @@ namespace tools
|
|||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_put");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::enumerate(container_handle h, i_db_callback* pcb)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(pcb, false, "null capback ptr passed to enumerate");
|
||||
|
|
@ -380,6 +397,42 @@ namespace tools
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::resize_if_needed()
|
||||
{
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE LOCKED in resize_if_needed()", LOG_LEVEL_3);
|
||||
CRITICAL_REGION_LOCAL(m_write_exclusive_lock);
|
||||
|
||||
if (have_tx())
|
||||
{
|
||||
LOG_PRINT_RED("[DB " << m_path << "] : resize_if_needed(): Have txs on stack, unable to resize!", LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
MDB_stat st = AUTO_VAL_INIT(st);
|
||||
mdb_env_stat(m_penv, &st);
|
||||
MDB_envinfo ei = AUTO_VAL_INIT(ei);
|
||||
mdb_env_info(m_penv, &ei);
|
||||
|
||||
uint64_t dirty_size = ei.me_last_pgno * st.ms_psize;
|
||||
int64_t size_diff = ei.me_mapsize - dirty_size;
|
||||
if (size_diff >= DB_RESIZE_MIN_FREE_SIZE && ei.me_mapsize >= DB_RESIZE_MIN_MAX_SIZE)
|
||||
return true; // resize is not needed
|
||||
|
||||
double gigabyte = 1024 * 1024 * 1024;
|
||||
const uint64_t increment_size_pg_aligned = DB_RESIZE_INCREMENT_SIZE - (DB_RESIZE_INCREMENT_SIZE % st.ms_psize);
|
||||
|
||||
// need to resize DB
|
||||
uint64_t new_size = ei.me_mapsize - (ei.me_mapsize % increment_size_pg_aligned) + increment_size_pg_aligned;
|
||||
|
||||
int res = mdb_env_set_mapsize(m_penv, new_size);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_mapsize");
|
||||
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] has grown: " << std::fixed << std::setprecision(2) << ei.me_mapsize / gigabyte << " GiB -> " << std::fixed << std::setprecision(2) << new_size / gigabyte << " GiB", LOG_LEVEL_0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,11 @@ namespace tools
|
|||
boost::recursive_mutex m_cs;
|
||||
boost::recursive_mutex m_write_exclusive_lock;
|
||||
std::map<std::thread::id, transactions_list> m_txs; // size_t -> count of nested read_only transactions
|
||||
std::atomic<uint64_t> m_commits_count;
|
||||
|
||||
bool pop_tx_entry(tx_entry& txe);
|
||||
|
||||
|
||||
public:
|
||||
lmdb_db_backend();
|
||||
~lmdb_db_backend();
|
||||
|
|
@ -60,6 +64,7 @@ namespace tools
|
|||
//-------------------------------------------------------------------------------------
|
||||
bool have_tx();
|
||||
MDB_txn* get_current_tx();
|
||||
bool resize_if_needed();
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace currency
|
|||
//------------------------------------------------------------------
|
||||
int ethash_height_to_epoch(uint64_t height)
|
||||
{
|
||||
return height / ETHASH_EPOCH_LENGTH;
|
||||
return static_cast<int>(height / ETHASH_EPOCH_LENGTH);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
crypto::hash ethash_epoch_to_seed(int epoch)
|
||||
|
|
@ -51,7 +51,7 @@ namespace currency
|
|||
{
|
||||
int epoch = ethash_height_to_epoch(height);
|
||||
const auto& context = progpow::get_global_epoch_context_full(static_cast<int>(epoch));
|
||||
auto res_eth = progpow::hash(context, height, *(ethash::hash256*)&block_header_hash, nonce);
|
||||
auto res_eth = progpow::hash(context, static_cast<int>(height), *(ethash::hash256*)&block_header_hash, nonce);
|
||||
crypto::hash result = currency::null_hash;
|
||||
memcpy(&result.data, &res_eth.final_hash, sizeof(res_eth.final_hash));
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ using namespace currency;
|
|||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_BLOCK_CUMUL_SZ_LIMIT 0
|
||||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_PRUNED_RS_HEIGHT 1
|
||||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_LAST_WORKED_VERSION 2
|
||||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 3 //mismatch here means full resync
|
||||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 3 //DON'T CHANGE THIS, if you need to resync db change BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION
|
||||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION 4 //mismatch here means some reinitializations
|
||||
|
||||
#define TARGETDATA_CACHE_SIZE DIFFICULTY_WINDOW + 10
|
||||
|
|
@ -68,6 +68,9 @@ using namespace currency;
|
|||
#else
|
||||
#define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 18000
|
||||
#endif
|
||||
#define BLOCK_POS_STRICT_SEQUENCE_LIMIT 20
|
||||
|
||||
|
||||
|
||||
DISABLE_VS_WARNINGS(4267)
|
||||
|
||||
|
|
@ -106,7 +109,9 @@ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(std::share
|
|||
m_current_fee_median(0),
|
||||
m_current_fee_median_effective_index(0),
|
||||
m_is_reorganize_in_process(false),
|
||||
m_deinit_is_done(false)
|
||||
m_deinit_is_done(false),
|
||||
m_cached_next_pow_difficulty(0),
|
||||
m_cached_next_pos_difficulty(0)
|
||||
|
||||
|
||||
{
|
||||
|
|
@ -357,6 +362,16 @@ bool blockchain_storage::set_lost_tx_unmixable()
|
|||
//------------------------------------------------------------------
|
||||
void blockchain_storage::patch_out_if_needed(txout_to_key& out, const crypto::hash& tx_id, uint64_t n) const
|
||||
{
|
||||
static crypto::hash tx_id_1 = epee::string_tools::parse_tpod_from_hex_string<crypto::hash>("c2a2229d614e7c026433efbcfdbd0be1f68d9b419220336df3e2c209f5d57314");
|
||||
static crypto::hash tx_id_2 = epee::string_tools::parse_tpod_from_hex_string<crypto::hash>("647f936c6ffbd136f5c95d9a90ad554bdb4c01541c6eb5755ad40b984d80da67");
|
||||
|
||||
if (tx_id == tx_id_1 && n == 12)
|
||||
{
|
||||
out.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX;
|
||||
}else if(tx_id == tx_id_2 && n == 5)
|
||||
{
|
||||
out.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void blockchain_storage::initialize_db_solo_options_values()
|
||||
|
|
@ -967,12 +982,21 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) con
|
|||
wide_difficulty_type& dif = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty;
|
||||
TIME_MEASURE_FINISH_PD(target_calculating_enum_blocks);
|
||||
TIME_MEASURE_START_PD(target_calculating_calc);
|
||||
dif = next_difficulty(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET);
|
||||
if (m_db_blocks.size() > m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
{
|
||||
dif = next_difficulty_2(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET);
|
||||
}
|
||||
else
|
||||
{
|
||||
dif = next_difficulty_1(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET);
|
||||
}
|
||||
|
||||
|
||||
TIME_MEASURE_FINISH_PD(target_calculating_calc);
|
||||
return dif;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height) const
|
||||
wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
std::vector<uint64_t> timestamps;
|
||||
|
|
@ -995,7 +1019,13 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, co
|
|||
return true;
|
||||
};
|
||||
enum_blockchain(cb, alt_chain, split_height);
|
||||
return next_difficulty(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET);
|
||||
|
||||
wide_difficulty_type diff = 0;
|
||||
if(abei.height > m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
diff = next_difficulty_2(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET);
|
||||
else
|
||||
diff = next_difficulty_1(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET);
|
||||
return diff;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::get_cached_next_difficulty(bool pos) const
|
||||
|
|
@ -1054,7 +1084,7 @@ wide_difficulty_type blockchain_storage::get_next_difficulty_for_alternative_cha
|
|||
commulative_difficulties.push_back(m_db_blocks[i]->cumulative_diff_precise);
|
||||
}
|
||||
|
||||
return next_difficulty(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET:DIFFICULTY_POW_TARGET);
|
||||
return next_difficulty_1(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET:DIFFICULTY_POW_TARGET);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t height, bool pos) const
|
||||
|
|
@ -1071,9 +1101,29 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
|
|||
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake transaction in the block has the wrong type");
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_tx_unlock_time(b.miner_tx) == height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW,
|
||||
false,
|
||||
"coinbase transaction has wrong unlock time: " << get_tx_unlock_time(b.miner_tx) << ", expected: " << height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
if (height > m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
{
|
||||
// new rules that allow different unlock time in coinbase outputs
|
||||
uint64_t max_unlock_time = 0;
|
||||
uint64_t min_unlock_time = 0;
|
||||
bool r = get_tx_max_min_unlock_time(b.miner_tx, max_unlock_time, min_unlock_time);
|
||||
CHECK_AND_ASSERT_MES(r && min_unlock_time >= height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW,
|
||||
false,
|
||||
"coinbase transaction has wrong min_unlock_time: " << min_unlock_time << ", expected: " << height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
//------------------------------------------------------------------
|
||||
//bool blockchain_storage::
|
||||
// pre-hard fork rules that don't allow different unlock time in coinbase outputs
|
||||
uint64_t max_unlock_time = 0;
|
||||
uint64_t min_unlock_time = 0;
|
||||
bool r = get_tx_max_min_unlock_time(b.miner_tx, max_unlock_time, min_unlock_time);
|
||||
CHECK_AND_ASSERT_MES(r && max_unlock_time == min_unlock_time && min_unlock_time == height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW,
|
||||
false,
|
||||
"coinbase transaction has wrong min_unlock_time: " << min_unlock_time << ", expected: " << height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
}
|
||||
|
||||
|
||||
//check outs overflow
|
||||
if(!check_outs_overflow(b.miner_tx))
|
||||
|
|
@ -1192,7 +1242,12 @@ bool blockchain_storage::create_block_template(block& b,
|
|||
size_t median_size;
|
||||
boost::multiprecision::uint128_t already_generated_coins;
|
||||
CRITICAL_REGION_BEGIN(m_read_lock);
|
||||
b.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
height = m_db_blocks.size();
|
||||
if(height <= m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
b.major_version = BLOCK_MAJOR_VERSION_INITAL;
|
||||
else
|
||||
b.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
|
||||
b.minor_version = CURRENT_BLOCK_MINOR_VERSION;
|
||||
b.prev_id = get_top_block_id();
|
||||
b.timestamp = m_core_runtime_config.get_core_time();
|
||||
|
|
@ -1209,7 +1264,7 @@ bool blockchain_storage::create_block_template(block& b,
|
|||
CHECK_AND_ASSERT_MES(diffic, false, "difficulty owverhead.");
|
||||
|
||||
|
||||
height = m_db_blocks.size();
|
||||
|
||||
|
||||
median_size = m_db_current_block_cumul_sz_limit / 2;
|
||||
already_generated_coins = m_db_blocks.back()->already_generated_coins;
|
||||
|
|
@ -1470,6 +1525,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
|
||||
alt_block_extended_info abei = AUTO_VAL_INIT(abei);
|
||||
abei.bl = b;
|
||||
abei.timestamp = m_core_runtime_config.get_core_time();
|
||||
abei.height = alt_chain.size() ? it_prev->second.height + 1 : *ptr_main_prev + 1;
|
||||
CHECK_AND_ASSERT_MES_CUSTOM(coinbase_height == abei.height, false, bvc.m_verification_failed = true, "block coinbase height doesn't match with altchain height, declined");
|
||||
uint64_t connection_height = alt_chain.size() ? alt_chain.front()->second.height:abei.height;
|
||||
|
|
@ -1495,8 +1551,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
CHECK_AND_ASSERT_MES_CUSTOM(!(pos_block && abei.height < m_core_runtime_config.pos_minimum_heigh), false, bvc.m_verification_failed = true, "PoS block is not allowed on this height");
|
||||
|
||||
|
||||
//wide_difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei, pos_block);
|
||||
wide_difficulty_type current_diff = get_next_diff_conditional2(pos_block, alt_chain, connection_height);
|
||||
wide_difficulty_type current_diff = get_next_diff_conditional2(pos_block, alt_chain, connection_height, abei);
|
||||
|
||||
CHECK_AND_ASSERT_MES_CUSTOM(current_diff, false, bvc.m_verification_failed = true, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!");
|
||||
|
||||
|
|
@ -1555,7 +1610,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
if (abei.height >= m_core_runtime_config.pos_minimum_heigh)
|
||||
cumulative_diff_delta = correct_difficulty_with_sequence_factor(sequence_factor, cumulative_diff_delta);
|
||||
|
||||
if (abei.height > BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION && pos_block && sequence_factor > 20)
|
||||
if (abei.height > BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION && pos_block && sequence_factor > BLOCK_POS_STRICT_SEQUENCE_LIMIT)
|
||||
{
|
||||
LOG_PRINT_RED_L0("Alternative block " << id << " @ " << abei.height << " has too big sequence factor: " << sequence_factor << ", rejected");
|
||||
bvc.m_verification_failed = true;
|
||||
|
|
@ -1563,9 +1618,15 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
}
|
||||
|
||||
abei.cumulative_diff_adjusted += cumulative_diff_delta;
|
||||
|
||||
abei.cumulative_diff_precise = get_last_alt_x_block_cumulative_precise_difficulty(alt_chain, abei.height, pos_block);
|
||||
wide_difficulty_type last_x_cumul_dif_precise_adj = 0;
|
||||
abei.cumulative_diff_precise = get_last_alt_x_block_cumulative_precise_difficulty(alt_chain, abei.height-1, pos_block, last_x_cumul_dif_precise_adj);
|
||||
abei.cumulative_diff_precise += current_diff;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
wide_difficulty_type diff_precise_adj = correct_difficulty_with_sequence_factor(sequence_factor, current_diff);
|
||||
abei.cumulative_diff_precise_adjusted = last_x_cumul_dif_precise_adj + diff_precise_adj;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _DEBUG
|
||||
auto i_dres = m_alternative_chains.find(id);
|
||||
|
|
@ -1600,7 +1661,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
<< ENDL << "HEIGHT " << abei.height << ", difficulty: " << abei.difficulty << ", cumul_diff_precise: " << abei.cumulative_diff_precise << ", cumul_diff_adj: " << abei.cumulative_diff_adjusted << " (current mainchain cumul_diff_adj: " << m_db_blocks.back()->cumulative_diff_adjusted << ", ki lookup total: " << ki_lookup_total <<")"
|
||||
, LOG_LEVEL_0);
|
||||
|
||||
if (is_reorganize_required(*m_db_blocks.back(), abei, proof))
|
||||
if (is_reorganize_required(*m_db_blocks.back(), alt_chain, proof))
|
||||
{
|
||||
auto a = epee::misc_utils::create_scope_leave_handler([&]() { m_is_reorganize_in_process = false; });
|
||||
CHECK_AND_ASSERT_THROW_MES(!m_is_reorganize_in_process, "Detected recursive reorganzie");
|
||||
|
|
@ -1616,6 +1677,11 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
return r;
|
||||
}
|
||||
bvc.added_to_altchain = true;
|
||||
|
||||
//protect ourself from altchains container flood
|
||||
if (m_alternative_chains.size() > m_core_runtime_config.max_alt_blocks)
|
||||
prune_aged_alt_blocks();
|
||||
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
|
|
@ -1641,26 +1707,111 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
CATCH_ENTRY_CUSTOM("blockchain_storage::handle_alternative_block", bvc.m_verification_failed = true, false);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::is_reorganize_required(const block_extended_info& main_chain_bei, const block_extended_info& alt_chain_bei, const crypto::hash& proof_alt)
|
||||
wide_difficulty_type blockchain_storage::get_x_difficulty_after_height(uint64_t height, bool is_pos)
|
||||
{
|
||||
if (main_chain_bei.cumulative_diff_adjusted < alt_chain_bei.cumulative_diff_adjusted)
|
||||
return true;
|
||||
else if (main_chain_bei.cumulative_diff_adjusted > alt_chain_bei.cumulative_diff_adjusted)
|
||||
return false;
|
||||
else // main_chain_bei.cumulative_diff_adjusted == alt_chain_bei.cumulative_diff_adjusted
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
CHECK_AND_ASSERT_THROW_MES(height < m_db_blocks.size(), "Internal error: condition failed: height (" << height << ") < m_db_blocks.size() " << m_db_blocks.size());
|
||||
wide_difficulty_type diff = 0;
|
||||
for (uint64_t i = height + 1; i != m_db_blocks.size(); i++)
|
||||
{
|
||||
if (!is_pos_block(main_chain_bei.bl))
|
||||
return false; // do not reorganize on the same cummul diff if it's a PoW block
|
||||
auto bei_ptr = m_db_blocks[i];
|
||||
if (is_pos_block(bei_ptr->bl) == is_pos)
|
||||
{
|
||||
diff = bei_ptr->difficulty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (diff == 0)
|
||||
{
|
||||
//never met x type of block, that meanst that difficulty is current
|
||||
diff = get_cached_next_difficulty(is_pos);
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::is_reorganize_required(const block_extended_info& main_chain_bei, const alt_chain_type& alt_chain, const crypto::hash& proof_alt)
|
||||
{
|
||||
//alt_chain - back is latest(top), first - connection with main chain
|
||||
const block_extended_info& alt_chain_bei = alt_chain.back()->second;
|
||||
const block_extended_info& connection_point = alt_chain.front()->second;
|
||||
|
||||
//in case of simultaneous PoS blocks are happened on the same height (quite common for PoS)
|
||||
//we also try to weight them to guarantee consensus in network
|
||||
if (std::memcmp(&main_chain_bei.stake_hash, &proof_alt, sizeof(main_chain_bei.stake_hash)) >= 0)
|
||||
if (connection_point.height <= m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
{
|
||||
//use pre-hard fork, old-style comparing
|
||||
if (main_chain_bei.cumulative_diff_adjusted < alt_chain_bei.cumulative_diff_adjusted)
|
||||
return true;
|
||||
else if (main_chain_bei.cumulative_diff_adjusted > alt_chain_bei.cumulative_diff_adjusted)
|
||||
return false;
|
||||
else // main_chain_bei.cumulative_diff_adjusted == alt_chain_bei.cumulative_diff_adjusted
|
||||
{
|
||||
if (!is_pos_block(main_chain_bei.bl))
|
||||
return false; // do not reorganize on the same cummul diff if it's a PoW block
|
||||
|
||||
//in case of simultaneous PoS blocks are happened on the same height (quite common for PoS)
|
||||
//we also try to weight them to guarantee consensus in network
|
||||
if (std::memcmp(&main_chain_bei.stake_hash, &proof_alt, sizeof(main_chain_bei.stake_hash)) >= 0)
|
||||
return false;
|
||||
|
||||
LOG_PRINT_L2("[is_reorganize_required]:TRUE, \"by order of memcmp\" main_stake_hash:" << &main_chain_bei.stake_hash << ", alt_stake_hash" << proof_alt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (alt_chain_bei.height > m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
{
|
||||
//new rules, applied after HARD_FORK_1
|
||||
//to learn this algo please read https://github.com/hyle-team/docs/blob/master/zano/PoS_Analysis_and_improvements_proposal.pdf
|
||||
|
||||
wide_difficulty_type difficulty_pos_at_split_point = get_x_difficulty_after_height(connection_point.height - 1, true);
|
||||
wide_difficulty_type difficulty_pow_at_split_point = get_x_difficulty_after_height(connection_point.height - 1, false);
|
||||
|
||||
difficulties main_cumul_diff = AUTO_VAL_INIT(main_cumul_diff);
|
||||
difficulties alt_cumul_diff = AUTO_VAL_INIT(alt_cumul_diff);
|
||||
//we use get_last_alt_x_block_cumulative_precise_adj_difficulty for getting both alt chain and main chain diff of given block types
|
||||
|
||||
wide_difficulty_type alt_pos_diff_end = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain, alt_chain_bei.height, true);
|
||||
wide_difficulty_type alt_pos_diff_begin = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), connection_point.height-1, true);
|
||||
alt_cumul_diff.pos_diff = alt_pos_diff_end - alt_pos_diff_begin;
|
||||
|
||||
LOG_PRINT_L2("[is_reorganize_required]:TRUE, \"by order of memcmp\" main_stake_hash:" << &main_chain_bei.stake_hash << ", alt_stake_hash" << proof_alt);
|
||||
return true;
|
||||
wide_difficulty_type alt_pow_diff_end = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain, alt_chain_bei.height, false);
|
||||
wide_difficulty_type alt_pow_diff_begin = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), connection_point.height - 1, false);
|
||||
alt_cumul_diff.pow_diff = alt_pow_diff_end - alt_pow_diff_begin;
|
||||
|
||||
wide_difficulty_type main_pos_diff_end = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), m_db_blocks.size()-1, true);
|
||||
wide_difficulty_type main_pos_diff_begin = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), connection_point.height - 1, true);
|
||||
main_cumul_diff.pos_diff = main_pos_diff_end - main_pos_diff_begin;
|
||||
|
||||
wide_difficulty_type main_pow_diff_end = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), m_db_blocks.size() - 1, false);
|
||||
wide_difficulty_type main_pow_diff_begin = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), connection_point.height - 1, false);
|
||||
main_cumul_diff.pow_diff = main_pow_diff_end - main_pow_diff_begin;
|
||||
|
||||
//TODO: measurment of precise cumulative difficult
|
||||
wide_difficulty_type alt = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff);
|
||||
wide_difficulty_type main = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff);
|
||||
|
||||
if (main < alt)
|
||||
return true;
|
||||
else if (main > alt)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
if (!is_pos_block(main_chain_bei.bl))
|
||||
return false; // do not reorganize on the same cummul diff if it's a PoW block
|
||||
|
||||
//in case of simultaneous PoS blocks are happened on the same height (quite common for PoS)
|
||||
//we also try to weight them to guarantee consensus in network
|
||||
if (std::memcmp(&main_chain_bei.stake_hash, &proof_alt, sizeof(main_chain_bei.stake_hash)) >= 0)
|
||||
return false;
|
||||
|
||||
LOG_PRINT_L2("[is_reorganize_required]:TRUE, \"by order of memcmp\" main_stake_hash:" << &main_chain_bei.stake_hash << ", alt_stake_hash" << proof_alt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_MES_AND_THROW("Unknown version of block");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::pre_validate_relayed_block(block& bl, block_verification_context& bvc, const crypto::hash& id)const
|
||||
{
|
||||
|
|
@ -2101,7 +2252,7 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU
|
|||
return false;
|
||||
|
||||
//check if transaction is unlocked
|
||||
if (!is_tx_spendtime_unlocked(get_tx_unlock_time(tx)))
|
||||
if (!is_tx_spendtime_unlocked(get_tx_unlock_time(tx, out_ptr->out_no)))
|
||||
return false;
|
||||
|
||||
//use appropriate mix_attr out
|
||||
|
|
@ -2364,7 +2515,7 @@ bool blockchain_storage::forecast_difficulty(std::vector<std::pair<uint64_t, wid
|
|||
out_height_2_diff_vector.push_back(std::make_pair(height, last_block_diff_for_this_type)); // the first element corresponds to the last block of this type
|
||||
for (size_t i = 0; i < DIFFICULTY_CUT; ++i)
|
||||
{
|
||||
wide_difficulty_type diff = next_difficulty(timestamps, cumulative_difficulties, target_seconds);
|
||||
wide_difficulty_type diff = next_difficulty_1(timestamps, cumulative_difficulties, target_seconds);
|
||||
height += avg_interval;
|
||||
out_height_2_diff_vector.push_back(std::make_pair(height, diff));
|
||||
|
||||
|
|
@ -2524,6 +2675,46 @@ void blockchain_storage::print_db_cache_perfeormance_data() const
|
|||
);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void blockchain_storage::get_last_n_x_blocks(uint64_t n, bool pos_blocks, std::list<std::shared_ptr<const block_extended_info>>& blocks) const
|
||||
{
|
||||
uint64_t count = 0;
|
||||
bool looking_for_a_pos = true;
|
||||
for (uint64_t i = m_db_blocks.size() - 1; i != 0; --i)
|
||||
{
|
||||
auto block_ptr = m_db_blocks[i];
|
||||
if (is_pos_block(block_ptr->bl) == pos_blocks)
|
||||
{
|
||||
blocks.push_back(block_ptr);
|
||||
++count;
|
||||
if (count >= n)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void blockchain_storage::print_last_n_difficulty_numbers(uint64_t n) const
|
||||
{
|
||||
|
||||
std::stringstream ss;
|
||||
std::list<std::shared_ptr<const block_extended_info>> pos_blocks;
|
||||
std::list<std::shared_ptr<const block_extended_info>> pow_blocks;
|
||||
|
||||
get_last_n_x_blocks(n, true, pos_blocks);
|
||||
get_last_n_x_blocks(n, false, pow_blocks);
|
||||
ss << "PoS blocks difficulty:" << ENDL;
|
||||
for (auto& bl_ptr : pos_blocks)
|
||||
{
|
||||
ss << bl_ptr->difficulty << ENDL;
|
||||
}
|
||||
|
||||
ss << "PoW blocks difficulty:" << ENDL;
|
||||
for (auto& bl_ptr : pow_blocks)
|
||||
{
|
||||
ss << bl_ptr->difficulty << ENDL;
|
||||
}
|
||||
LOG_PRINT_L0("LAST BLOCKS:" << ss.str());
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void blockchain_storage::print_blockchain_outs_stat() const
|
||||
{
|
||||
LOG_ERROR("NOT IMPLEMENTED YET");
|
||||
|
|
@ -3268,6 +3459,8 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const
|
|||
TIME_MEASURE_START_PD(tx_append_is_expired);
|
||||
CHECK_AND_ASSERT_MES(!is_tx_expired(tx), false, "Transaction can't be added to the blockchain since it's already expired. tx expiration time: " << get_tx_expiration_time(tx) << ", blockchain median time: " << get_tx_expiration_median());
|
||||
TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_append_is_expired);
|
||||
|
||||
CHECK_AND_ASSERT_MES(validate_tx_for_hardfork_specific_terms(tx, tx_id, bl_height), false, "tx " << tx_id << ": hardfork-specific validation failed");
|
||||
|
||||
TIME_MEASURE_START_PD(tx_process_extra);
|
||||
bool r = process_blockchain_tx_extra(tx);
|
||||
|
|
@ -3280,7 +3473,7 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const
|
|||
|
||||
|
||||
TIME_MEASURE_START_PD(tx_process_inputs);
|
||||
BOOST_FOREACH(const txin_v& in, tx.vin)
|
||||
for(const txin_v& in : tx.vin)
|
||||
{
|
||||
if(!boost::apply_visitor(add_transaction_input_visitor(*this, m_db_spent_keys, tx_id, bl_id, bl_height), in))
|
||||
{
|
||||
|
|
@ -3360,7 +3553,7 @@ bool blockchain_storage::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::
|
|||
bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
bool res = check_tx_inputs(tx, tx_prefix_hash, &max_used_block_height);
|
||||
bool res = check_tx_inputs(tx, tx_prefix_hash, max_used_block_height);
|
||||
if(!res) return false;
|
||||
CHECK_AND_ASSERT_MES(max_used_block_height < m_db_blocks.size(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db_blocks.size());
|
||||
get_block_hash(m_db_blocks[max_used_block_height]->bl, max_used_block_id);
|
||||
|
|
@ -3604,19 +3797,16 @@ bool blockchain_storage::have_tx_keyimges_as_spent(const transaction &tx) const
|
|||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
// bool blockchain_storage::check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height) const
|
||||
// {
|
||||
// TIME_MEASURE_START_PD(tx_check_inputs_prefix_hash);
|
||||
// crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
|
||||
// TIME_MEASURE_FINISH_PD(tx_check_inputs_prefix_hash);
|
||||
// return check_tx_inputs(tx, tx_prefix_hash, pmax_used_block_height);
|
||||
// }
|
||||
bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash) const
|
||||
{
|
||||
uint64_t stub = 0;
|
||||
return check_tx_inputs(tx, tx_prefix_hash, stub);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height) const
|
||||
bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height) const
|
||||
{
|
||||
size_t sig_index = 0;
|
||||
if(pmax_used_block_height)
|
||||
*pmax_used_block_height = 0;
|
||||
max_used_block_height = 0;
|
||||
|
||||
std::vector<crypto::signature> sig_stub;
|
||||
const std::vector<crypto::signature>* psig = &sig_stub;
|
||||
|
|
@ -3642,7 +3832,8 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
|
|||
return false;
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_kimage_check);
|
||||
if (!check_tx_input(tx, sig_index, in_to_key, tx_prefix_hash, *psig, pmax_used_block_height))
|
||||
uint64_t max_unlock_time = 0;
|
||||
if (!check_tx_input(tx, sig_index, in_to_key, tx_prefix_hash, *psig, max_used_block_height, max_unlock_time))
|
||||
{
|
||||
LOG_ERROR("Failed to validate input #" << sig_index << " tx: " << tx_prefix_hash);
|
||||
return false;
|
||||
|
|
@ -3651,7 +3842,7 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
|
|||
else if (txin.type() == typeid(txin_multisig))
|
||||
{
|
||||
const txin_multisig& in_ms = boost::get<txin_multisig>(txin);
|
||||
if (!check_tx_input(tx, sig_index, in_ms, tx_prefix_hash, *psig, pmax_used_block_height))
|
||||
if (!check_tx_input(tx, sig_index, in_ms, tx_prefix_hash, *psig, max_used_block_height))
|
||||
{
|
||||
LOG_ERROR("Failed to validate multisig input #" << sig_index << " (ms out id: " << in_ms.multisig_out_id << ") in tx: " << tx_prefix_hash);
|
||||
return false;
|
||||
|
|
@ -3682,14 +3873,14 @@ bool blockchain_storage::is_tx_spendtime_unlocked(uint64_t unlock_time) const
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t* pmax_related_block_height) const
|
||||
bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height, uint64_t& max_unlock_time) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
//TIME_MEASURE_START_PD(tx_check_inputs_loop_ch_in_get_keys_loop);
|
||||
|
||||
std::vector<crypto::public_key> output_keys;
|
||||
if(!get_output_keys_for_input_with_checks(txin, output_keys, pmax_related_block_height))
|
||||
if(!get_output_keys_for_input_with_checks(tx, txin, output_keys, max_related_block_height, max_unlock_time))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << ")");
|
||||
return false;
|
||||
|
|
@ -3708,7 +3899,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
|
|||
// 1) source tx unlock time validity
|
||||
// 2) mixin restrictions
|
||||
// 3) general gindex/ref_by_id corectness
|
||||
bool blockchain_storage::get_output_keys_for_input_with_checks(const txin_to_key& txin, std::vector<crypto::public_key>& output_keys, uint64_t* pmax_related_block_height /* = NULL */) const
|
||||
bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction& tx, const txin_to_key& txin, std::vector<crypto::public_key>& output_keys, uint64_t& max_related_block_height, uint64_t& max_unlock_time) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
|
|
@ -3716,17 +3907,30 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const txin_to_key
|
|||
{
|
||||
std::vector<crypto::public_key >& m_results_collector;
|
||||
const blockchain_storage& m_bch;
|
||||
uint64_t& m_max_unlock_time;
|
||||
outputs_visitor(std::vector<crypto::public_key>& results_collector,
|
||||
const blockchain_storage& bch) :m_results_collector(results_collector), m_bch(bch)
|
||||
const blockchain_storage& bch,
|
||||
uint64_t& max_unlock_time) :m_results_collector(results_collector), m_bch(bch), m_max_unlock_time(max_unlock_time)
|
||||
{}
|
||||
bool handle_output(const transaction& tx, const tx_out& out)
|
||||
bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out& out, uint64_t out_i)
|
||||
{
|
||||
//check tx unlock time
|
||||
if (!m_bch.is_tx_spendtime_unlocked(get_tx_unlock_time(tx)))
|
||||
uint64_t source_out_unlock_time = get_tx_unlock_time(source_tx, out_i);
|
||||
//let coinbase sources for PoS block to have locked inputs, the outputs supposed to be locked same way, except the reward
|
||||
if (is_coinbase(validated_tx) && is_pos_block(validated_tx))
|
||||
{
|
||||
LOG_PRINT_L0("One of outputs for one of inputs have wrong tx.unlock_time = " << get_tx_unlock_time(tx));
|
||||
return false;
|
||||
if (source_out_unlock_time > m_max_unlock_time)
|
||||
m_max_unlock_time = source_out_unlock_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_bch.is_tx_spendtime_unlocked(source_out_unlock_time))
|
||||
{
|
||||
LOG_PRINT_L0("One of outputs for one of inputs have wrong tx.unlock_time = " << get_tx_unlock_time(source_tx, out_i));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(out.target.type() != typeid(txout_to_key))
|
||||
{
|
||||
|
|
@ -3739,8 +3943,8 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const txin_to_key
|
|||
}
|
||||
};
|
||||
|
||||
outputs_visitor vi(output_keys, *this);
|
||||
return scan_outputkeys_for_indexes(txin, vi, pmax_related_block_height);
|
||||
outputs_visitor vi(output_keys, *this, max_unlock_time);
|
||||
return scan_outputkeys_for_indexes(tx, txin, vi, max_related_block_height);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
// Note: this function can be used for checking to_key inputs against either main chain or alt chain, that's why it has output_keys_ptrs parameter
|
||||
|
|
@ -3813,7 +4017,7 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index,
|
|||
#define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, "ms input check failed: ms_id: " << txin.multisig_out_id << ", input #" << in_index << " in tx " << tx_prefix_hash << ", refers to ms output #" << out_n << " in source tx " << get_transaction_hash(source_tx) << ENDL << msg)
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
uint64_t unlock_time = get_tx_unlock_time(source_tx);
|
||||
uint64_t unlock_time = get_tx_unlock_time(source_tx, out_n);
|
||||
LOC_CHK(is_tx_spendtime_unlocked(unlock_time), "Source transaction is LOCKED! unlock_time: " << unlock_time << ", now is " << m_core_runtime_config.get_core_time() << ", blockchain size is " << get_current_blockchain_size());
|
||||
|
||||
LOC_CHK(source_tx.vout.size() > out_n, "internal error: out_n==" << out_n << " is out-of-bounds of source_tx.vout, size=" << source_tx.vout.size());
|
||||
|
|
@ -3893,7 +4097,7 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index,
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t* pmax_related_block_height) const
|
||||
bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
|
|
@ -3917,8 +4121,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
|
|||
if (!check_ms_input(tx, in_index, txin, tx_prefix_hash, sig, source_tx_ptr->tx, n))
|
||||
return false;
|
||||
|
||||
if (pmax_related_block_height != nullptr)
|
||||
*pmax_related_block_height = source_tx_ptr->m_keeper_block_height;
|
||||
max_related_block_height = source_tx_ptr->m_keeper_block_height;
|
||||
|
||||
return true;
|
||||
#undef LOC_CHK
|
||||
|
|
@ -4066,6 +4269,12 @@ bool blockchain_storage::prune_aged_alt_blocks()
|
|||
CRITICAL_REGION_LOCAL1(m_alternative_chains_lock);
|
||||
uint64_t current_height = get_current_blockchain_size();
|
||||
|
||||
size_t count_to_delete = 0;
|
||||
if(m_alternative_chains.size() > m_core_runtime_config.max_alt_blocks)
|
||||
count_to_delete = m_alternative_chains.size() - m_core_runtime_config.max_alt_blocks;
|
||||
|
||||
std::map<uint64_t, alt_chain_container::iterator> alts_to_delete;
|
||||
|
||||
for(auto it = m_alternative_chains.begin(); it != m_alternative_chains.end();)
|
||||
{
|
||||
if (current_height > it->second.height && current_height - it->second.height > CURRENCY_ALT_BLOCK_LIVETIME_COUNT)
|
||||
|
|
@ -4074,9 +4283,28 @@ bool blockchain_storage::prune_aged_alt_blocks()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (count_to_delete)
|
||||
{
|
||||
if (!alts_to_delete.size())
|
||||
alts_to_delete[it->second.timestamp] = it;
|
||||
else
|
||||
{
|
||||
if (it->second.timestamp >= alts_to_delete.rbegin()->first)
|
||||
alts_to_delete[it->second.timestamp] = it;
|
||||
|
||||
if (alts_to_delete.size() > count_to_delete)
|
||||
alts_to_delete.erase(alts_to_delete.begin());
|
||||
}
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
//now, if there was count_to_delete we should erase most oldest entries of altblocks
|
||||
for (auto& itd : alts_to_delete)
|
||||
{
|
||||
m_alternative_chains.erase(itd.second);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -4156,6 +4384,58 @@ void blockchain_storage::get_pos_mining_estimate(uint64_t amount_coins,
|
|||
estimate_result = current_amount;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id, uint64_t block_height) const
|
||||
{
|
||||
if (block_height <= m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
{
|
||||
// before hardfork 1
|
||||
|
||||
for (const auto& el : tx.extra)
|
||||
{
|
||||
// etc_tx_details_unlock_time2 is not allowed in txs in blocks prior to hardfork 1
|
||||
CHECK_AND_ASSERT_MES(el.type() != typeid(etc_tx_details_unlock_time2), false, "tx " << tx_id << " contains etc_tx_details_unlock_time2 which is not allowed on height " << block_height);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t max_unlock_time)const
|
||||
{
|
||||
uint64_t major_unlock_time = get_tx_x_detail<etc_tx_details_unlock_time>(miner_tx);
|
||||
if (major_unlock_time)
|
||||
{
|
||||
//if there was etc_tx_details_unlock_time present in tx, then ignore etc_tx_details_unlock_time2
|
||||
if (major_unlock_time < max_unlock_time)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_block_height(miner_tx) > m_core_runtime_config.hard_fork1_starts_after_height, false, "error in block [" << get_block_height(miner_tx) << "] etc_tx_details_unlock_time2 can exist only after hard fork point : " << m_core_runtime_config.hard_fork1_starts_after_height);
|
||||
|
||||
//etc_tx_details_unlock_time2 can be kept only after hard_fork_1 point
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
get_type_in_variant_container(miner_tx.extra, ut2);
|
||||
CHECK_AND_ASSERT_MES(ut2.unlock_time_array.size() == miner_tx.vout.size(), false, "ut2.unlock_time_array.size()<" << ut2.unlock_time_array.size()
|
||||
<< "> != miner_tx.vout.size()<" << miner_tx.vout.size() << ">");
|
||||
|
||||
uint64_t amount_of_coins_in_unlock_in_range = 0;
|
||||
|
||||
for (uint64_t i = 0; i != miner_tx.vout.size(); i++)
|
||||
{
|
||||
if (ut2.unlock_time_array[i] >= max_unlock_time)
|
||||
amount_of_coins_in_unlock_in_range += miner_tx.vout[i].amount;
|
||||
}
|
||||
|
||||
if (amount_of_coins_in_unlock_in_range >= staked_amount)
|
||||
return true;
|
||||
LOG_ERROR("amount_of_coins_in_unlock_in_range<" << amount_of_coins_in_unlock_in_range << "> is less then staked_amount<" << staked_amount);
|
||||
return false;
|
||||
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::validate_pos_block(const block& b,
|
||||
wide_difficulty_type basic_diff,
|
||||
uint64_t& amount,
|
||||
|
|
@ -4185,11 +4465,11 @@ bool blockchain_storage::validate_pos_block(const block& b,
|
|||
|
||||
//check actual time if it there
|
||||
uint64_t actual_ts = get_actual_timestamp(b);
|
||||
if ((actual_ts > b.timestamp && actual_ts - b.timestamp > POS_MAC_ACTUAL_TIMESTAMP_TO_MINED) ||
|
||||
(actual_ts < b.timestamp && b.timestamp - actual_ts > POS_MAC_ACTUAL_TIMESTAMP_TO_MINED)
|
||||
if ((actual_ts > b.timestamp && actual_ts - b.timestamp > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) ||
|
||||
(actual_ts < b.timestamp && b.timestamp - actual_ts > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED)
|
||||
)
|
||||
{
|
||||
LOG_PRINT_L0("PoS block actual timestamp " << actual_ts << " differs from b.timestamp " << b.timestamp << " by " << ((int64_t)actual_ts - (int64_t)b.timestamp) << " s, it's more than allowed " << POS_MAC_ACTUAL_TIMESTAMP_TO_MINED << " s.");
|
||||
LOG_PRINT_L0("PoS block actual timestamp " << actual_ts << " differs from b.timestamp " << b.timestamp << " by " << ((int64_t)actual_ts - (int64_t)b.timestamp) << " s, it's more than allowed " << POS_MAX_ACTUAL_TIMESTAMP_TO_MINED << " s.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -4232,8 +4512,23 @@ bool blockchain_storage::validate_pos_block(const block& b,
|
|||
{
|
||||
// Do coinstake input validation for main chain only.
|
||||
// Txs in alternative PoS blocks (including miner_tx) are validated by validate_alt_block_txs()
|
||||
r = check_tx_input(b.miner_tx, 1, coinstake_in, id, b.miner_tx.signatures[0], &max_related_block_height);
|
||||
uint64_t max_unlock_time = 0;
|
||||
r = check_tx_input(b.miner_tx, 1, coinstake_in, id, b.miner_tx.signatures[0], max_related_block_height, max_unlock_time);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to validate coinstake input in miner tx, block_id = " << get_block_hash(b));
|
||||
|
||||
if (get_block_height(b) > m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
{
|
||||
uint64_t last_pow_h = get_last_x_block_height(false);
|
||||
CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "Failed to failed to validate coinbase in pos block, condition failed: max_related_block_height(" << max_related_block_height << ") < last_pow_h(" << last_pow_h << ")");
|
||||
//let's check that coinbase amount and unlock time
|
||||
r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, max_unlock_time);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to validate_pos_coinbase_outs_unlock_time() in miner tx, block_id = " << get_block_hash(b)
|
||||
<< "max_unlock_time=" << max_unlock_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(is_tx_spendtime_unlocked(max_unlock_time), false, "Failed to failed to validate coinbase in pos block, condition failed: is_tx_spendtime_unlocked(max_unlock_time)(" << max_unlock_time << ")");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t block_height = for_altchain ? split_height + alt_chain.size() : m_db_blocks.size();
|
||||
|
|
@ -4341,13 +4636,23 @@ uint64_t blockchain_storage::get_last_x_block_height(bool pos) const
|
|||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::get_last_alt_x_block_cumulative_precise_difficulty(alt_chain_type& alt_chain, uint64_t block_height, bool pos) const
|
||||
wide_difficulty_type blockchain_storage::get_last_alt_x_block_cumulative_precise_adj_difficulty(const alt_chain_type& alt_chain, uint64_t block_height, bool pos) const
|
||||
{
|
||||
uint64_t main_chain_first_block = block_height - 1;
|
||||
wide_difficulty_type res = 0;
|
||||
get_last_alt_x_block_cumulative_precise_difficulty(alt_chain, block_height, pos, res);
|
||||
return res;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::get_last_alt_x_block_cumulative_precise_difficulty(const alt_chain_type& alt_chain, uint64_t block_height, bool pos, wide_difficulty_type& cumulative_diff_precise_adj) const
|
||||
{
|
||||
uint64_t main_chain_first_block = block_height;
|
||||
for (auto it = alt_chain.rbegin(); it != alt_chain.rend(); it++)
|
||||
{
|
||||
if (is_pos_block((*it)->second.bl) == pos)
|
||||
{
|
||||
cumulative_diff_precise_adj = (*it)->second.cumulative_diff_precise_adjusted;
|
||||
return (*it)->second.cumulative_diff_precise;
|
||||
}
|
||||
main_chain_first_block = (*it)->second.height - 1;
|
||||
}
|
||||
|
||||
|
|
@ -4358,8 +4663,12 @@ wide_difficulty_type blockchain_storage::get_last_alt_x_block_cumulative_precise
|
|||
for (uint64_t i = main_chain_first_block; i != 0; i--)
|
||||
{
|
||||
if (is_pos_block(m_db_blocks[i]->bl) == pos)
|
||||
{
|
||||
cumulative_diff_precise_adj = m_db_blocks[i]->cumulative_diff_precise_adjusted;
|
||||
return m_db_blocks[i]->cumulative_diff_precise;
|
||||
}
|
||||
}
|
||||
cumulative_diff_precise_adj = 0;
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
@ -4415,7 +4724,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
if (is_pos_bl)
|
||||
{
|
||||
bool r = validate_pos_block(bl, current_diffic, pos_coinstake_amount, this_coin_diff, proof_hash, id, false);
|
||||
CHECK_AND_ASSERT_MES_CUSTOM(r, false, bvc.m_verification_failed = true, "validate_pos_block failed!!");
|
||||
CHECK_AND_ASSERT_MES_CUSTOM(r, false, bvc.m_verification_failed = true, "validate_pos_block failed!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -4476,6 +4785,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
|
||||
size_t tx_processed_count = 0;
|
||||
uint64_t fee_summary = 0;
|
||||
uint64_t burned_coins = 0;
|
||||
|
||||
for(const crypto::hash& tx_id : bl.tx_hashes)
|
||||
{
|
||||
|
|
@ -4515,6 +4825,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
return false;
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_time);
|
||||
burned_coins += get_burned_amount(tx);
|
||||
|
||||
TIME_MEASURE_START_PD(tx_prapare_append);
|
||||
uint64_t current_bc_size = get_current_blockchain_size();
|
||||
|
|
@ -4574,6 +4885,12 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
if (is_pos_bl)
|
||||
bei.stake_hash = proof_hash;
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//old style cumulative difficulty collecting
|
||||
|
||||
//precise difficulty - difficulty used to calculate next difficulty
|
||||
uint64_t last_x_h = get_last_x_block_height(is_pos_bl);
|
||||
if (!last_x_h)
|
||||
|
|
@ -4597,11 +4914,10 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
size_t sequence_factor = get_current_sequence_factor(is_pos_bl);
|
||||
if (bei.height >= m_core_runtime_config.pos_minimum_heigh)
|
||||
cumulative_diff_delta = correct_difficulty_with_sequence_factor(sequence_factor, cumulative_diff_delta);
|
||||
|
||||
if (bei.height > BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION && is_pos_bl && sequence_factor > 20)
|
||||
|
||||
if (bei.height > BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION && is_pos_bl && sequence_factor > BLOCK_POS_STRICT_SEQUENCE_LIMIT)
|
||||
{
|
||||
LOG_PRINT_L0("Block with id: " << id
|
||||
<< " has too big sequence_factor = " << sequence_factor);
|
||||
LOG_PRINT_RED_L0("Block " << id << " @ " << bei.height << " has too big sequence factor: " << sequence_factor << ", rejected");
|
||||
purge_block_data_from_blockchain(bl, tx_processed_count);
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
|
|
@ -4609,8 +4925,22 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
|
||||
bei.cumulative_diff_adjusted += cumulative_diff_delta;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// rebuild cumulative_diff_precise_adjusted for whole period
|
||||
wide_difficulty_type diff_precise_adj = correct_difficulty_with_sequence_factor(sequence_factor, current_diffic);
|
||||
bei.cumulative_diff_precise_adjusted = last_x_h ? m_db_blocks[last_x_h]->cumulative_diff_precise_adjusted + diff_precise_adj : diff_precise_adj;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//etc
|
||||
bei.already_generated_coins = already_generated_coins + base_reward;
|
||||
if (already_generated_coins < burned_coins)
|
||||
{
|
||||
LOG_ERROR("Condition failed: already_generated_coins(" << already_generated_coins << ") >= burned_coins(" << burned_coins << ")");
|
||||
purge_block_data_from_blockchain(bl, tx_processed_count);
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
}
|
||||
bei.already_generated_coins = already_generated_coins - burned_coins + base_reward;
|
||||
|
||||
auto blocks_index_ptr = m_db_blocks_index.get(id);
|
||||
if (blocks_index_ptr)
|
||||
|
|
@ -4783,13 +5113,26 @@ bool blockchain_storage::update_next_comulative_size_limit()
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::add_new_block(const block& bl_, block_verification_context& bvc)
|
||||
bool blockchain_storage::prevalidate_block(const block& bl)
|
||||
{
|
||||
if (bl.major_version == BLOCK_MAJOR_VERSION_INITAL && get_block_height(bl) <= m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
return true;
|
||||
if (bl.major_version != CURRENT_BLOCK_MAJOR_VERSION)
|
||||
{
|
||||
LOG_ERROR("prevalidation failed for block " << get_block_hash(bl) << ": major block version " << static_cast<size_t>(bl.major_version) << " is incorrect, " << CURRENT_BLOCK_MAJOR_VERSION << " is expected" << ENDL
|
||||
<< obj_to_json_str(bl));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::add_new_block(const block& bl, block_verification_context& bvc)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_db.begin_transaction();
|
||||
|
||||
block bl = bl_;
|
||||
//block bl = bl_;
|
||||
crypto::hash id = get_block_hash(bl);
|
||||
CRITICAL_REGION_LOCAL(m_tx_pool);
|
||||
//CRITICAL_REGION_LOCAL1(m_read_lock);
|
||||
|
|
@ -4802,7 +5145,18 @@ bool blockchain_storage::add_new_block(const block& bl_, block_verification_cont
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!prevalidate_block(bl))
|
||||
{
|
||||
LOG_PRINT_RED_L0("block with id = " << id << " failed to prevalidate");
|
||||
bvc.m_added_to_main_chain = false;
|
||||
bvc.m_verification_failed = true;
|
||||
m_db.commit_transaction();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//check that block refers to chain tail
|
||||
|
||||
|
||||
if (!(bl.prev_id == get_top_block_id()))
|
||||
{
|
||||
|
|
@ -5584,6 +5938,8 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
|
|||
}
|
||||
update_alt_out_indexes_for_tx_in_block(b.miner_tx, abei);
|
||||
|
||||
CHECK_AND_ASSERT_MES(validate_tx_for_hardfork_specific_terms(b.miner_tx, null_hash, height), false, "miner tx hardfork-specific validation failed");
|
||||
|
||||
for (auto tx_id : b.tx_hashes)
|
||||
{
|
||||
std::shared_ptr<transaction> tx_ptr;
|
||||
|
|
@ -5614,6 +5970,8 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
|
|||
CHECK_AND_ASSERT_MES(false, false, "input #" << n << " has unexpected type (" << tx.vin[n].type().name() << "), tx " << tx_id);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(validate_tx_for_hardfork_specific_terms(tx, tx_id, height), false, "tx " << tx_id << ": hardfork-specific validation failed");
|
||||
|
||||
// Updating abei (and not updating alt_chain) during this cycle is safe because txs in the same block can't reference one another,
|
||||
// so only valid references are either to previous alt blocks (accessed via alt_chain) or to main chain blocks.
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ namespace currency
|
|||
|
||||
// {amount -> pub_keys} map of outputs' pub_keys appeared in this alt block ( index_in_vector == output_gindex - gindex_lookup_table[output_amount] )
|
||||
std::map<uint64_t, std::vector<crypto::public_key> > outputs_pub_keys;
|
||||
|
||||
//date added to alt chain storage
|
||||
uint64_t timestamp;
|
||||
};
|
||||
typedef std::unordered_map<crypto::hash, alt_block_extended_info> alt_chain_container;
|
||||
//typedef std::list<alt_chain_container::iterator> alt_chain_type;
|
||||
|
|
@ -184,6 +187,7 @@ namespace currency
|
|||
|
||||
//------------- modifying members --------------
|
||||
bool add_new_block(const block& bl_, block_verification_context& bvc);
|
||||
bool prevalidate_block(const block& bl);
|
||||
bool clear();
|
||||
bool reset_and_set_genesis_block(const block& b);
|
||||
//debug function
|
||||
|
|
@ -221,8 +225,11 @@ namespace currency
|
|||
bool have_tx_keyimg_as_spent(const crypto::key_image &key_im, uint64_t before_height = UINT64_MAX) const;
|
||||
std::shared_ptr<transaction> get_tx(const crypto::hash &id) const;
|
||||
|
||||
|
||||
template<class visitor_t>
|
||||
bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height = NULL) const ;
|
||||
bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_to_key& tx_in_to_key, visitor_t& vis) { uint64_t stub = 0; return scan_outputkeys_for_indexes(validated_tx, tx_in_to_key, vis, stub); }
|
||||
template<class visitor_t>
|
||||
bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t& max_related_block_height) const ;
|
||||
|
||||
uint64_t get_current_blockchain_size() const;
|
||||
uint64_t get_top_block_height() const;
|
||||
|
|
@ -230,7 +237,7 @@ namespace currency
|
|||
crypto::hash get_top_block_id(uint64_t& height) const;
|
||||
bool get_top_block(block& b) const;
|
||||
wide_difficulty_type get_next_diff_conditional(bool pos) const;
|
||||
wide_difficulty_type get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height) const;
|
||||
wide_difficulty_type get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const;
|
||||
wide_difficulty_type get_cached_next_difficulty(bool pos) const;
|
||||
|
||||
typedef bool fill_block_template_func_t(block &bl, bool pos, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height);
|
||||
|
|
@ -260,13 +267,14 @@ namespace currency
|
|||
uint64_t get_aliases_count()const;
|
||||
uint64_t get_block_h_older_then(uint64_t timestamp) const;
|
||||
bool validate_tx_service_attachmens_in_services(const tx_service_attachment& a, size_t i, const transaction& tx)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t* pmax_related_block_height = NULL)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t* pmax_related_block_height = NULL)const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height = NULL)const;
|
||||
//bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL)const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height, uint64_t& max_unlock_time)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height)const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height)const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash) const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id)const;
|
||||
bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const transaction& source_tx, size_t out_n) const;
|
||||
bool get_output_keys_for_input_with_checks(const txin_to_key& txin, std::vector<crypto::public_key>& output_keys, uint64_t* pmax_related_block_height = NULL) const;
|
||||
bool validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id, uint64_t block_height) const;
|
||||
bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_to_key& txin, std::vector<crypto::public_key>& output_keys, uint64_t& max_related_block_height, uint64_t& max_unlock_time) const;
|
||||
bool check_tokey_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const std::vector<const crypto::public_key*>& output_keys_ptrs) const;
|
||||
uint64_t get_current_comulative_blocksize_limit()const;
|
||||
uint64_t get_current_hashrate(size_t aprox_count)const;
|
||||
|
|
@ -304,6 +312,7 @@ namespace currency
|
|||
bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash *p_last_block_hash = nullptr) const;
|
||||
|
||||
bool scan_pos(const COMMAND_RPC_SCAN_POS::request& sp, COMMAND_RPC_SCAN_POS::response& rsp)const;
|
||||
bool validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t max_unlock_time)const;
|
||||
bool validate_pos_block(const block& b, const crypto::hash& id, bool for_altchain)const;
|
||||
bool validate_pos_block(const block& b, wide_difficulty_type basic_diff, const crypto::hash& id, bool for_altchain)const;
|
||||
bool validate_pos_block(const block& b,
|
||||
|
|
@ -421,6 +430,7 @@ namespace currency
|
|||
void print_blockchain_outs(const std::string& file) const;
|
||||
void print_blockchain_outs_stat() const;
|
||||
void print_db_cache_perfeormance_data() const;
|
||||
void print_last_n_difficulty_numbers(uint64_t n) const;
|
||||
bool calc_tx_cummulative_blob(const block& bl)const;
|
||||
bool get_outs_index_stat(outs_index_stat& outs_stat)const;
|
||||
bool print_lookup_key_image(const crypto::key_image& ki) const;
|
||||
|
|
@ -430,6 +440,7 @@ namespace currency
|
|||
bool rebuild_tx_fee_medians();
|
||||
bool validate_all_aliases_for_new_median_mode();
|
||||
bool print_tx_outputs_lookup(const crypto::hash& tx_id) const;
|
||||
uint64_t get_last_x_block_height(bool pos)const;
|
||||
private:
|
||||
|
||||
//-------------- DB containers --------------
|
||||
|
|
@ -541,7 +552,8 @@ namespace currency
|
|||
bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc);
|
||||
std::string print_alt_chain(alt_chain_type alt_chain);
|
||||
bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc);
|
||||
bool is_reorganize_required(const block_extended_info& main_chain_bei, const block_extended_info& alt_chain_bei, const crypto::hash& proof_alt);
|
||||
bool is_reorganize_required(const block_extended_info& main_chain_bei, const alt_chain_type& alt_chain, const crypto::hash& proof_alt);
|
||||
wide_difficulty_type get_x_difficulty_after_height(uint64_t height, bool is_pos);
|
||||
bool purge_keyimage_from_big_heap(const crypto::key_image& ki, const crypto::hash& id);
|
||||
bool purge_altblock_keyimages_from_big_heap(const block& b, const crypto::hash& id);
|
||||
bool append_altblock_keyimages_to_big_heap(const crypto::hash& block_id, const std::set<crypto::key_image>& alt_block_keyimages);
|
||||
|
|
@ -550,9 +562,8 @@ namespace currency
|
|||
bool validate_alt_block_txs(const block& b, const crypto::hash& id, std::set<crypto::key_image>& collected_keyimages, alt_block_extended_info& abei, const alt_chain_type& alt_chain, uint64_t split_height, uint64_t& ki_lookup_time_total) const;
|
||||
bool update_alt_out_indexes_for_tx_in_block(const transaction& tx, alt_block_extended_info& abei)const;
|
||||
bool get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr<transaction>& tx_ptr, uint64_t min_allowed_block_height = 0) const;
|
||||
|
||||
void get_last_n_x_blocks(uint64_t n, bool pos_blocks, std::list<std::shared_ptr<const block_extended_info>>& blocks) const;
|
||||
bool prevalidate_miner_transaction(const block& b, uint64_t height, bool pos)const;
|
||||
bool validate_transaction(const block& b, uint64_t height, const transaction& tx)const;
|
||||
bool rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height);
|
||||
bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp);
|
||||
bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector<uint64_t>& global_indexes);
|
||||
|
|
@ -608,8 +619,8 @@ namespace currency
|
|||
//POS
|
||||
wide_difficulty_type get_adjusted_cumulative_difficulty_for_next_pos(wide_difficulty_type next_diff)const;
|
||||
wide_difficulty_type get_adjusted_cumulative_difficulty_for_next_alt_pos(alt_chain_type& alt_chain, uint64_t block_height, wide_difficulty_type next_diff, uint64_t connection_height)const;
|
||||
uint64_t get_last_x_block_height(bool pos)const;
|
||||
wide_difficulty_type get_last_alt_x_block_cumulative_precise_difficulty(alt_chain_type& alt_chain, uint64_t block_height, bool pos)const;
|
||||
wide_difficulty_type get_last_alt_x_block_cumulative_precise_difficulty(const alt_chain_type& alt_chain, uint64_t block_height, bool pos, wide_difficulty_type& cumulative_diff_precise_adj)const;
|
||||
wide_difficulty_type get_last_alt_x_block_cumulative_precise_adj_difficulty(const alt_chain_type& alt_chain, uint64_t block_height, bool pos) const;
|
||||
size_t get_current_sequence_factor_for_alt(alt_chain_type& alt_chain, bool pos, uint64_t connection_height)const;
|
||||
};
|
||||
|
||||
|
|
@ -648,7 +659,7 @@ namespace currency
|
|||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
template<class visitor_t>
|
||||
bool blockchain_storage::scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height) const
|
||||
bool blockchain_storage::scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t& max_related_block_height) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_get_item_size);
|
||||
|
|
@ -704,18 +715,16 @@ namespace currency
|
|||
CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx output #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(outtk.mix_attr) << ", key_offsets.size = " << tx_in_to_key.key_offsets.size());
|
||||
|
||||
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
|
||||
if (!vis.handle_output(tx_ptr->tx, tx_ptr->tx.vout[n]))
|
||||
if (!vis.handle_output(tx_ptr->tx, validated_tx, tx_ptr->tx.vout[n], n))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to handle_output for output id = " << tx_id << ", no " << n);
|
||||
return false;
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
|
||||
|
||||
if (pmax_related_block_height)
|
||||
{
|
||||
if (*pmax_related_block_height < tx_ptr->m_keeper_block_height)
|
||||
*pmax_related_block_height = tx_ptr->m_keeper_block_height;
|
||||
}
|
||||
if (max_related_block_height < tx_ptr->m_keeper_block_height)
|
||||
max_related_block_height = tx_ptr->m_keeper_block_height;
|
||||
|
||||
|
||||
++output_index;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ namespace currency
|
|||
uint64_t block_cumulative_size;
|
||||
wide_difficulty_type cumulative_diff_adjusted;
|
||||
wide_difficulty_type cumulative_diff_precise;
|
||||
wide_difficulty_type cumulative_diff_precise_adjusted;
|
||||
wide_difficulty_type difficulty;
|
||||
boost::multiprecision::uint128_t already_generated_coins;
|
||||
crypto::hash stake_hash; //TODO: unused field for PoW blocks, subject for refactoring
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ namespace currency
|
|||
uint64_t pos_minimum_heigh; //height
|
||||
uint64_t tx_pool_min_fee;
|
||||
uint64_t tx_default_fee;
|
||||
uint64_t hard_fork1_starts_after_height;
|
||||
uint64_t max_alt_blocks;
|
||||
crypto::public_key alias_validation_pubkey;
|
||||
core_time_func_t get_core_time;
|
||||
|
||||
|
|
@ -34,6 +36,8 @@ namespace currency
|
|||
pc.pos_minimum_heigh = POS_START_HEIGHT;
|
||||
pc.tx_pool_min_fee = TX_MINIMUM_FEE;
|
||||
pc.tx_default_fee = TX_DEFAULT_FEE;
|
||||
pc.max_alt_blocks = CURRENCY_ALT_BLOCK_MAX_COUNT;
|
||||
pc.hard_fork1_starts_after_height = ZANO_HARDFORK_1_AFTER_HEIGHT;
|
||||
pc.get_core_time = &core_runtime_config::_default_core_time_function;
|
||||
bool r = epee::string_tools::hex_to_pod(ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY, pc.alias_validation_pubkey);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "failed to parse alias_validation_pub_key");
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ namespace currency
|
|||
};
|
||||
|
||||
|
||||
//number of block (or time), used as a limitation: spend this tx not early then block/time
|
||||
//number of block (or timestamp if v bigger then CURRENCY_MAX_BLOCK_NUMBER), used as a limitation: spend this tx not early then block/time
|
||||
struct etc_tx_details_unlock_time
|
||||
{
|
||||
uint64_t v;
|
||||
|
|
@ -345,6 +345,16 @@ namespace currency
|
|||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//number of block (or timestamp if unlock_time_array[i] bigger then CURRENCY_MAX_BLOCK_NUMBER), used as a limitation: spend this tx not early then block/time
|
||||
//unlock_time_array[i], i - index of output, unlock_time_array.size() == vout.size()
|
||||
struct etc_tx_details_unlock_time2
|
||||
{
|
||||
std::vector<uint64_t> unlock_time_array;
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(unlock_time_array)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct etc_tx_details_expiration_time
|
||||
{
|
||||
uint64_t v;
|
||||
|
|
@ -361,7 +371,7 @@ namespace currency
|
|||
uint64_t v;
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(v)
|
||||
END_SERIALIZE()
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct etc_tx_details_flags
|
||||
|
|
@ -380,7 +390,7 @@ namespace currency
|
|||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
typedef boost::mpl::vector<tx_service_attachment, tx_comment, tx_payer, tx_receiver, tx_message, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time, etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry, extra_user_data, extra_padding, etc_tx_derivation_hint> all_payload_types;
|
||||
typedef boost::mpl::vector<tx_service_attachment, tx_comment, tx_payer, tx_receiver, tx_message, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time, etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry, extra_user_data, extra_padding, etc_tx_derivation_hint, etc_tx_details_unlock_time2> all_payload_types;
|
||||
typedef boost::make_variant_over<all_payload_types>::type attachment_v;
|
||||
typedef boost::make_variant_over<all_payload_types>::type extra_v;
|
||||
typedef boost::make_variant_over<all_payload_types>::type payload_items_v;
|
||||
|
|
@ -553,12 +563,14 @@ namespace currency
|
|||
uint64_t index;
|
||||
crypto::key_image keyimage;
|
||||
uint64_t block_timestamp;
|
||||
uint64_t stake_unlock_time;
|
||||
//not for serialization
|
||||
uint64_t wallet_index;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount)
|
||||
KV_SERIALIZE(index)
|
||||
KV_SERIALIZE(stake_unlock_time)
|
||||
KV_SERIALIZE(block_timestamp)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(keyimage)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
|
@ -613,5 +625,6 @@ SET_VARIANT_TAGS(uint64_t, 26, "uint64_t");
|
|||
SET_VARIANT_TAGS(currency::etc_tx_time, 27, "etc_tx_time");
|
||||
SET_VARIANT_TAGS(uint32_t, 28, "uint32_t");
|
||||
SET_VARIANT_TAGS(currency::tx_receiver, 29, "payer");
|
||||
SET_VARIANT_TAGS(currency::etc_tx_details_unlock_time2, 30, "unlock_time2");
|
||||
|
||||
#undef SET_VARIANT_TAGS
|
||||
|
|
|
|||
|
|
@ -190,6 +190,11 @@ namespace boost
|
|||
a & at.v;
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::etc_tx_details_unlock_time2 &at, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & at.unlock_time_array;
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::etc_tx_details_expiration_time &at, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & at.v;
|
||||
|
|
|
|||
|
|
@ -24,10 +24,6 @@
|
|||
#define CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT 60*20
|
||||
|
||||
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW 60
|
||||
|
||||
|
||||
// TOTAL_MONEY_SUPPLY - total number coins to be generated
|
||||
#define TOTAL_MONEY_SUPPLY ((uint64_t)(-1))
|
||||
|
||||
#define POS_START_HEIGHT 0
|
||||
|
||||
|
|
@ -87,8 +83,10 @@
|
|||
|
||||
|
||||
#define CURRENCY_ALT_BLOCK_LIVETIME_COUNT (CURRENCY_BLOCKS_PER_DAY*7)//one week
|
||||
#define CURRENCY_ALT_BLOCK_MAX_COUNT 43200 //30 days
|
||||
#define CURRENCY_MEMPOOL_TX_LIVETIME 345600 //seconds, 4 days
|
||||
|
||||
|
||||
#ifndef TESTNET
|
||||
#define P2P_DEFAULT_PORT 11121
|
||||
#define RPC_DEFAULT_PORT 11211
|
||||
|
|
@ -128,7 +126,7 @@
|
|||
//PoS definitions
|
||||
#define POS_SCAN_WINDOW 60*10 //seconds // 10 minutes
|
||||
#define POS_SCAN_STEP 15 //seconds
|
||||
#define POS_MAC_ACTUAL_TIMESTAMP_TO_MINED (POS_SCAN_WINDOW+100)
|
||||
#define POS_MAX_ACTUAL_TIMESTAMP_TO_MINED (POS_SCAN_WINDOW+100)
|
||||
|
||||
#define POS_STARTER_KERNEL_HASH "00000000000000000006382a8d8f94588ce93a1351924f6ccb9e07dd287c6e4b"
|
||||
#define POS_MODFIFIER_INTERVAL 10
|
||||
|
|
@ -192,10 +190,11 @@
|
|||
#define GUI_INTERNAL_CONFIG "gui_internal_config.bin"
|
||||
|
||||
|
||||
|
||||
#define CURRENT_TRANSACTION_CHAIN_ENTRY_ARCHIVE_VER 3
|
||||
#define CURRENT_BLOCK_EXTENDED_INFO_ARCHIVE_VER 1
|
||||
|
||||
#define BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION CURRENCY_FORMATION_VERSION + 7
|
||||
#define BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION CURRENCY_FORMATION_VERSION + 8
|
||||
#define BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION 1
|
||||
|
||||
|
||||
|
|
@ -203,10 +202,19 @@
|
|||
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
|
||||
|
||||
|
||||
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+64)
|
||||
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+65)
|
||||
|
||||
#define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31)
|
||||
|
||||
//hard forks section
|
||||
#define BLOCK_MAJOR_VERSION_GENESIS 1
|
||||
#define BLOCK_MINOR_VERSION_GENESIS 0
|
||||
#define BLOCK_MAJOR_VERSION_INITAL 0
|
||||
#ifndef TESTNET
|
||||
#define ZANO_HARDFORK_1_AFTER_HEIGHT 166440
|
||||
#else
|
||||
#define ZANO_HARDFORK_1_AFTER_HEIGHT 62102
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -107,21 +107,54 @@ namespace currency
|
|||
out_amounts.resize(out_amounts.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
for (auto a : out_amounts)
|
||||
{
|
||||
tx_destination_entry de;
|
||||
tx_destination_entry de = AUTO_VAL_INIT(de);
|
||||
de.addr.push_back(miner_address);
|
||||
de.amount = a;
|
||||
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
|
||||
{
|
||||
//this means that block is creating after hardfork_1 and unlock_time is needed to set for every destination separately
|
||||
de.unlock_time = height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW;
|
||||
}
|
||||
destinations.push_back(de);
|
||||
}
|
||||
|
||||
if (pos)
|
||||
destinations.push_back(tx_destination_entry(pe.amount, stakeholder_address));
|
||||
{
|
||||
uint64_t stake_lock_time = 0;
|
||||
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
|
||||
stake_lock_time = pe.stake_unlock_time;
|
||||
destinations.push_back(tx_destination_entry(pe.amount, stakeholder_address, stake_lock_time));
|
||||
}
|
||||
|
||||
|
||||
return construct_miner_tx(height, median_size, already_generated_coins, current_block_size, fee, destinations, tx, extra_nonce, max_outs, pos, pe);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool apply_unlock_time(const std::vector<tx_destination_entry>& destinations, transaction& tx)
|
||||
{
|
||||
currency::etc_tx_details_unlock_time2 unlock_time2 = AUTO_VAL_INIT(unlock_time2);
|
||||
unlock_time2.unlock_time_array.resize(destinations.size());
|
||||
bool found_unlock_time = false;
|
||||
for (size_t i = 0; i != unlock_time2.unlock_time_array.size(); i++)
|
||||
{
|
||||
if (destinations[i].unlock_time)
|
||||
{
|
||||
found_unlock_time = true;
|
||||
unlock_time2.unlock_time_array[i] = destinations[i].unlock_time;
|
||||
}
|
||||
}
|
||||
if (found_unlock_time)
|
||||
{
|
||||
tx.extra.push_back(unlock_time2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
size_t current_block_size,
|
||||
uint64_t fee,
|
||||
|
|
@ -144,9 +177,12 @@ namespace currency
|
|||
if (!add_tx_extra_userdata(tx, extra_nonce))
|
||||
return false;
|
||||
|
||||
//at this moment we do apply_unlock_time only for coin_base transactions
|
||||
apply_unlock_time(destinations, tx);
|
||||
//we always add extra_padding with 2 bytes length to make possible for get_block_template to adjust cumulative size
|
||||
tx.extra.push_back(extra_padding());
|
||||
|
||||
|
||||
txin_gen in;
|
||||
in.height = height;
|
||||
tx.vin.push_back(in);
|
||||
|
|
@ -171,10 +207,15 @@ namespace currency
|
|||
CHECK_AND_ASSERT_MES(r, false, "Failed to contruct miner tx out");
|
||||
no++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
tx.version = CURRENT_TRANSACTION_VERSION;
|
||||
set_tx_unlock_time(tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
if (!have_type_in_variant_container<etc_tx_details_unlock_time2>(tx.extra))
|
||||
{
|
||||
//if stake unlock time was not set, then we can use simple "whole transaction" lock scheme
|
||||
set_tx_unlock_time(tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
|
@ -891,16 +932,7 @@ namespace currency
|
|||
}
|
||||
return n;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
account_public_address get_crypt_address_from_destinations(const account_keys& sender_account_keys, const std::vector<tx_destination_entry>& destinations)
|
||||
{
|
||||
for (const auto& de : destinations)
|
||||
{
|
||||
if (de.addr.size() == 1 && sender_account_keys.m_account_address != de.addr.back())
|
||||
return de.addr.back(); // return the first destination address that is non-multisig and not equal to the sender's address
|
||||
}
|
||||
return sender_account_keys.m_account_address; // otherwise, fallback to sender's address
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx(const account_keys& sender_account_keys,
|
||||
const std::vector<tx_source_entry>& sources,
|
||||
|
|
@ -1304,7 +1336,7 @@ namespace currency
|
|||
bool get_inputs_money_amount(const transaction& tx, uint64_t& money)
|
||||
{
|
||||
money = 0;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
for(const auto& in : tx.vin)
|
||||
{
|
||||
uint64_t this_amount = get_amount_from_variant(in);
|
||||
if (!this_amount)
|
||||
|
|
@ -1328,7 +1360,7 @@ namespace currency
|
|||
//---------------------------------------------------------------
|
||||
bool check_inputs_types_supported(const transaction& tx)
|
||||
{
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
for(const auto& in : tx.vin)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_multisig), false, "wrong variant type: "
|
||||
<< in.type().name() << ", expected " << typeid(txin_to_key).name()
|
||||
|
|
@ -1828,9 +1860,7 @@ namespace currency
|
|||
//for future forks
|
||||
|
||||
std::cout << "Currency name: \t\t" << CURRENCY_NAME << "(" << CURRENCY_NAME_SHORT << ")" << std::endl;
|
||||
std::cout << "Money supply: \t\t" << print_money(TOTAL_MONEY_SUPPLY) << " coins"
|
||||
<< "(" << print_money(TOTAL_MONEY_SUPPLY) << "), dev bounties is ???" << std::endl;
|
||||
|
||||
std::cout << "Money supply: \t\t " << CURRENCY_BLOCK_REWARD * CURRENCY_BLOCKS_PER_DAY * 365 << " coins per year" << std::endl;
|
||||
std::cout << "PoS block interval: \t" << DIFFICULTY_POS_TARGET << " seconds" << std::endl;
|
||||
std::cout << "PoW block interval: \t" << DIFFICULTY_POW_TARGET << " seconds" << std::endl;
|
||||
std::cout << "Total blocks per day: \t" << CURRENCY_BLOCKS_PER_DAY << " seconds" << std::endl;
|
||||
|
|
@ -1874,8 +1904,8 @@ namespace currency
|
|||
//string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl);
|
||||
bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
|
||||
bl.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
|
||||
bl.major_version = BLOCK_MAJOR_VERSION_GENESIS;
|
||||
bl.minor_version = BLOCK_MINOR_VERSION_GENESIS;
|
||||
bl.timestamp = 0;
|
||||
bl.nonce = CURRENCY_GENESIS_NONCE;
|
||||
LOG_PRINT_GREEN("Generated genesis: " << get_block_hash(bl), LOG_LEVEL_0);
|
||||
|
|
@ -2081,6 +2111,20 @@ namespace currency
|
|||
|
||||
return true;
|
||||
}
|
||||
bool operator()(const etc_tx_details_unlock_time2& ee)
|
||||
{
|
||||
tv.type = "unlock_time";
|
||||
std::stringstream ss;
|
||||
ss << "[";
|
||||
for (auto v : ee.unlock_time_array)
|
||||
{
|
||||
ss << " " << v;
|
||||
}
|
||||
ss << "]";
|
||||
tv.short_view = ss.str();
|
||||
|
||||
return true;
|
||||
}
|
||||
bool operator()(const etc_tx_details_expiration_time& ee)
|
||||
{
|
||||
tv.type = "expiration_time";
|
||||
|
|
@ -2524,16 +2568,6 @@ namespace currency
|
|||
{
|
||||
return epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median)
|
||||
{
|
||||
/// tx expiration condition (tx is ok if the following is true)
|
||||
/// tx_expiration_time - TX_EXPIRATION_MEDIAN_SHIFT > get_last_n_blocks_timestamps_median(TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW)
|
||||
uint64_t expiration_time = get_tx_expiration_time(tx);
|
||||
if (expiration_time == 0)
|
||||
return false; // 0 means it never expires
|
||||
return expiration_time <= expiration_ts_median + TX_EXPIRATION_MEDIAN_SHIFT;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
crypto::hash prepare_prefix_hash_for_sign(const transaction& tx, uint64_t in_index, const crypto::hash& tx_id)
|
||||
{
|
||||
|
|
@ -2667,4 +2701,41 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
wide_difficulty_type get_a_to_b_relative_cumulative_difficulty(const wide_difficulty_type& difficulty_pos_at_split_point,
|
||||
const wide_difficulty_type& difficulty_pow_at_split_point,
|
||||
const difficulties& a_diff,
|
||||
const difficulties& b_diff )
|
||||
{
|
||||
static const wide_difficulty_type difficulty_starter = DIFFICULTY_STARTER;
|
||||
const wide_difficulty_type& a_pos_cumulative_difficulty = a_diff.pos_diff > 0 ? a_diff.pos_diff : difficulty_starter;
|
||||
const wide_difficulty_type& b_pos_cumulative_difficulty = b_diff.pos_diff > 0 ? b_diff.pos_diff : difficulty_starter;
|
||||
const wide_difficulty_type& a_pow_cumulative_difficulty = a_diff.pow_diff > 0 ? a_diff.pow_diff : difficulty_starter;
|
||||
const wide_difficulty_type& b_pow_cumulative_difficulty = b_diff.pow_diff > 0 ? b_diff.pow_diff : difficulty_starter;
|
||||
|
||||
boost::multiprecision::uint1024_t basic_sum = boost::multiprecision::uint1024_t(a_pow_cumulative_difficulty) + (boost::multiprecision::uint1024_t(a_pos_cumulative_difficulty)*difficulty_pow_at_split_point) / difficulty_pos_at_split_point;
|
||||
boost::multiprecision::uint1024_t res =
|
||||
(basic_sum * a_pow_cumulative_difficulty * a_pos_cumulative_difficulty) / (boost::multiprecision::uint1024_t(a_pow_cumulative_difficulty)*a_pos_cumulative_difficulty);
|
||||
|
||||
if (res > boost::math::tools::max_value<wide_difficulty_type>())
|
||||
{
|
||||
ASSERT_MES_AND_THROW("[INTERNAL ERROR]: Failed to get_a_to_b_relative_cumulative_difficulty, res = " << res << ENDL
|
||||
<< ", difficulty_pos_at_split_point: " << difficulty_pos_at_split_point << ENDL
|
||||
<< ", difficulty_pow_at_split_point:" << difficulty_pow_at_split_point << ENDL
|
||||
<< ", a_pos_cumulative_difficulty:" << a_pos_cumulative_difficulty << ENDL
|
||||
<< ", b_pos_cumulative_difficulty:" << b_pos_cumulative_difficulty << ENDL
|
||||
<< ", a_pow_cumulative_difficulty:" << a_pow_cumulative_difficulty << ENDL
|
||||
<< ", b_pow_cumulative_difficulty:" << b_pow_cumulative_difficulty << ENDL
|
||||
);
|
||||
}
|
||||
TRY_ENTRY();
|
||||
wide_difficulty_type short_res = res.convert_to<wide_difficulty_type>();
|
||||
return short_res;
|
||||
CATCH_ENTRY_WITH_FORWARDING_EXCEPTION();
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace currency
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -59,55 +59,7 @@ namespace currency
|
|||
|
||||
|
||||
typedef boost::multiprecision::uint128_t uint128_tl;
|
||||
struct tx_source_entry
|
||||
{
|
||||
typedef serializable_pair<txout_v, crypto::public_key> output_entry; // txout_v is either global output index or ref_by_id; public_key - is output ephemeral pub key
|
||||
|
||||
std::vector<output_entry> outputs; //index + key
|
||||
uint64_t real_output; //index in outputs vector of real output_entry
|
||||
crypto::public_key real_out_tx_key; //real output's transaction's public key
|
||||
size_t real_output_in_tx_index; //index in transaction outputs vector
|
||||
uint64_t amount; //money
|
||||
uint64_t transfer_index; //money
|
||||
crypto::hash multisig_id; //if txin_multisig: multisig output id
|
||||
size_t ms_sigs_count; //if txin_multisig: must be equal to output's minimum_sigs
|
||||
size_t ms_keys_count; //if txin_multisig: must be equal to size of output's keys container
|
||||
bool separately_signed_tx_complete; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation
|
||||
|
||||
bool is_multisig() const { return ms_sigs_count > 0; }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(outputs)
|
||||
FIELD(real_output)
|
||||
FIELD(real_out_tx_key)
|
||||
FIELD(real_output_in_tx_index)
|
||||
FIELD(amount)
|
||||
FIELD(transfer_index)
|
||||
FIELD(multisig_id)
|
||||
FIELD(ms_sigs_count)
|
||||
FIELD(ms_keys_count)
|
||||
FIELD(separately_signed_tx_complete)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_destination_entry
|
||||
{
|
||||
uint64_t amount; //money
|
||||
std::list<account_public_address> addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig
|
||||
size_t minimum_sigs; // if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used
|
||||
uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions
|
||||
|
||||
tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0){}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0){}
|
||||
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0){}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(amount)
|
||||
FIELD(addr)
|
||||
FIELD(minimum_sigs)
|
||||
FIELD(amount_to_provide)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
struct tx_extra_info
|
||||
{
|
||||
|
|
@ -208,32 +160,6 @@ namespace currency
|
|||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
template<class extra_type_t>
|
||||
uint64_t get_tx_x_detail(const transaction& tx)
|
||||
{
|
||||
extra_type_t e = AUTO_VAL_INIT(e);
|
||||
get_type_in_variant_container(tx.extra, e);
|
||||
return e.v;
|
||||
}
|
||||
template<class extra_type_t>
|
||||
void set_tx_x_detail(transaction& tx, uint64_t v)
|
||||
{
|
||||
extra_type_t e = AUTO_VAL_INIT(e);
|
||||
e.v = v;
|
||||
update_or_add_field_to_extra(tx.extra, e);
|
||||
}
|
||||
|
||||
inline uint64_t get_tx_unlock_time(const transaction& tx){ return get_tx_x_detail<etc_tx_details_unlock_time>(tx);}
|
||||
inline uint64_t get_tx_flags(const transaction& tx){ return get_tx_x_detail<etc_tx_details_flags>(tx); }
|
||||
inline uint64_t get_tx_expiration_time(const transaction& tx){ return get_tx_x_detail<etc_tx_details_expiration_time>(tx); }
|
||||
inline void set_tx_unlock_time(transaction& tx, uint64_t v){ set_tx_x_detail<etc_tx_details_unlock_time>(tx, v); }
|
||||
inline void set_tx_flags(transaction& tx, uint64_t v){ set_tx_x_detail<etc_tx_details_flags>(tx, v); }
|
||||
inline void set_tx_expiration_time(transaction& tx, uint64_t v){ set_tx_x_detail<etc_tx_details_expiration_time>(tx, v); }
|
||||
account_public_address get_crypt_address_from_destinations(const account_keys& sender_account_keys, const std::vector<tx_destination_entry>& destinations);
|
||||
|
||||
bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median);
|
||||
|
||||
|
||||
uint64_t get_string_uint64_hash(const std::string& str);
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
|
||||
bool validate_alias_name(const std::string& al);
|
||||
|
|
@ -317,6 +243,7 @@ namespace currency
|
|||
bool parse_amount(uint64_t& amount, const std::string& str_amount);
|
||||
|
||||
|
||||
|
||||
bool unserialize_block_complete_entry(const COMMAND_RPC_GET_BLOCKS_FAST::response& serialized,
|
||||
COMMAND_RPC_GET_BLOCKS_DIRECT::response& unserialized);
|
||||
|
||||
|
|
@ -670,6 +597,19 @@ namespace currency
|
|||
std::string utf8_to_upper(const std::string& s);
|
||||
std::string utf8_to_lower(const std::string& s);
|
||||
bool utf8_substring_test_case_insensitive(const std::string& match, const std::string& s); // Returns true is 's' contains 'match' (case-insensitive)
|
||||
|
||||
struct difficulties
|
||||
{
|
||||
wide_difficulty_type pos_diff;
|
||||
wide_difficulty_type pow_diff;
|
||||
};
|
||||
|
||||
wide_difficulty_type get_a_to_b_relative_cumulative_difficulty(const wide_difficulty_type& difficulty_pos_at_split_point,
|
||||
const wide_difficulty_type& difficulty_pow_at_split_point,
|
||||
const difficulties& a_diff,
|
||||
const difficulties& b_diff
|
||||
);
|
||||
|
||||
|
||||
} // namespace currency
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "currency_format_utils_blocks.h"
|
||||
#include "serialization/serialization.h"
|
||||
#include "currency_format_utils.h"
|
||||
#include "currency_format_utils_abstract.h"
|
||||
#include "currency_format_utils_transactions.h"
|
||||
namespace currency
|
||||
|
|
|
|||
|
|
@ -6,11 +6,127 @@
|
|||
|
||||
#include "currency_format_utils_transactions.h"
|
||||
#include "serialization/serialization.h"
|
||||
#include "currency_format_utils_abstract.h"
|
||||
#include "currency_format_utils.h"
|
||||
#include "currency_format_utils_abstract.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
account_public_address get_crypt_address_from_destinations(const account_keys& sender_account_keys, const std::vector<tx_destination_entry>& destinations)
|
||||
{
|
||||
for (const auto& de : destinations)
|
||||
{
|
||||
if (de.addr.size() == 1 && sender_account_keys.m_account_address != de.addr.back())
|
||||
return de.addr.back(); // return the first destination address that is non-multisig and not equal to the sender's address
|
||||
}
|
||||
return sender_account_keys.m_account_address; // otherwise, fallback to sender's address
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median)
|
||||
{
|
||||
/// tx expiration condition (tx is ok if the following is true)
|
||||
/// tx_expiration_time - TX_EXPIRATION_MEDIAN_SHIFT > get_last_n_blocks_timestamps_median(TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW)
|
||||
uint64_t expiration_time = get_tx_expiration_time(tx);
|
||||
if (expiration_time == 0)
|
||||
return false; // 0 means it never expires
|
||||
return expiration_time <= expiration_ts_median + TX_EXPIRATION_MEDIAN_SHIFT;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_burned_amount(const transaction& tx)
|
||||
{
|
||||
uint64_t res = 0;
|
||||
for (auto& o : tx.vout)
|
||||
{
|
||||
if (o.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
if (boost::get<txout_to_key>(o.target).key == null_pkey)
|
||||
res += o.amount;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_tx_max_unlock_time(const transaction& tx)
|
||||
{
|
||||
// etc_tx_details_unlock_time have priority over etc_tx_details_unlock_time2
|
||||
uint64_t v = get_tx_x_detail<etc_tx_details_unlock_time>(tx);
|
||||
if (v)
|
||||
return v;
|
||||
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
get_type_in_variant_container(tx.extra, ut2);
|
||||
if (!ut2.unlock_time_array.size())
|
||||
return 0;
|
||||
|
||||
uint64_t max_unlock_time = 0;
|
||||
CHECK_AND_ASSERT_THROW_MES(ut2.unlock_time_array.size() == tx.vout.size(), "unlock_time_array.size=" << ut2.unlock_time_array.size()
|
||||
<< " is not the same as tx.vout.size =" << tx.vout.size() << " in tx: " << get_transaction_hash(tx));
|
||||
for (size_t i = 0; i != tx.vout.size(); i++)
|
||||
{
|
||||
if (ut2.unlock_time_array[i] > max_unlock_time)
|
||||
max_unlock_time = ut2.unlock_time_array[i];
|
||||
}
|
||||
|
||||
return max_unlock_time;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_tx_unlock_time(const transaction& tx, uint64_t o_i)
|
||||
{
|
||||
// etc_tx_details_expiration_time have priority over etc_tx_details_expiration_time2
|
||||
uint64_t v = get_tx_x_detail<etc_tx_details_unlock_time>(tx);
|
||||
if (v)
|
||||
return v;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(tx.vout.size() > o_i, "tx.vout.size=" << tx.vout.size()
|
||||
<< " is not bigger then o_i=" << o_i << " in tx: " << get_transaction_hash(tx));
|
||||
|
||||
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
get_type_in_variant_container(tx.extra, ut2);
|
||||
if (!ut2.unlock_time_array.size())
|
||||
return 0;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(ut2.unlock_time_array.size() > o_i, "unlock_time_array.size=" << ut2.unlock_time_array.size()
|
||||
<< " is less then o_i=" << o_i << " in tx: " << get_transaction_hash(tx));
|
||||
|
||||
return ut2.unlock_time_array[o_i];
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_tx_max_min_unlock_time(const transaction& tx, uint64_t& max_unlock_time, uint64_t& min_unlock_time)
|
||||
{
|
||||
max_unlock_time = min_unlock_time = 0;
|
||||
// etc_tx_details_expiration_time have priority over etc_tx_details_expiration_time2
|
||||
uint64_t v = get_tx_x_detail<etc_tx_details_unlock_time>(tx);
|
||||
if (v)
|
||||
{
|
||||
max_unlock_time = min_unlock_time = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
get_type_in_variant_container(tx.extra, ut2);
|
||||
if (!ut2.unlock_time_array.size())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(ut2.unlock_time_array.size() == tx.vout.size(), "unlock_time_array.size=" << ut2.unlock_time_array.size()
|
||||
<< " is not equal tx.vout.size()=" << tx.vout.size() << " in tx: " << get_transaction_hash(tx));
|
||||
if (ut2.unlock_time_array.size())
|
||||
{
|
||||
max_unlock_time = min_unlock_time = ut2.unlock_time_array[0];
|
||||
for (size_t i = 1; i != ut2.unlock_time_array.size(); i++)
|
||||
{
|
||||
if (ut2.unlock_time_array[i] > max_unlock_time)
|
||||
max_unlock_time = ut2.unlock_time_array[i];
|
||||
if (ut2.unlock_time_array[i] < min_unlock_time)
|
||||
min_unlock_time = ut2.unlock_time_array[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,10 +9,92 @@
|
|||
#include "crypto/crypto.h"
|
||||
#include "currency_core/currency_basic.h"
|
||||
#include "currency_protocol/blobdatatype.h"
|
||||
#include "currency_core/account.h"
|
||||
|
||||
|
||||
namespace currency
|
||||
{
|
||||
struct tx_source_entry
|
||||
{
|
||||
typedef serializable_pair<txout_v, crypto::public_key> output_entry; // txout_v is either global output index or ref_by_id; public_key - is output ephemeral pub key
|
||||
|
||||
std::vector<output_entry> outputs; //index + key
|
||||
uint64_t real_output; //index in outputs vector of real output_entry
|
||||
crypto::public_key real_out_tx_key; //real output's transaction's public key
|
||||
size_t real_output_in_tx_index; //index in transaction outputs vector
|
||||
uint64_t amount; //money
|
||||
uint64_t transfer_index; //money
|
||||
crypto::hash multisig_id; //if txin_multisig: multisig output id
|
||||
size_t ms_sigs_count; //if txin_multisig: must be equal to output's minimum_sigs
|
||||
size_t ms_keys_count; //if txin_multisig: must be equal to size of output's keys container
|
||||
bool separately_signed_tx_complete; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation
|
||||
|
||||
bool is_multisig() const { return ms_sigs_count > 0; }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(outputs)
|
||||
FIELD(real_output)
|
||||
FIELD(real_out_tx_key)
|
||||
FIELD(real_output_in_tx_index)
|
||||
FIELD(amount)
|
||||
FIELD(transfer_index)
|
||||
FIELD(multisig_id)
|
||||
FIELD(ms_sigs_count)
|
||||
FIELD(ms_keys_count)
|
||||
FIELD(separately_signed_tx_complete)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_destination_entry
|
||||
{
|
||||
uint64_t amount; //money
|
||||
std::list<account_public_address> addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig
|
||||
size_t minimum_sigs; // if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used
|
||||
uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions
|
||||
uint64_t unlock_time;
|
||||
|
||||
tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0), unlock_time(0){}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(0){}
|
||||
tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(ut) {}
|
||||
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0), unlock_time(0){}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(amount)
|
||||
FIELD(addr)
|
||||
FIELD(minimum_sigs)
|
||||
FIELD(amount_to_provide)
|
||||
FIELD(unlock_time)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
template<class extra_type_t>
|
||||
uint64_t get_tx_x_detail(const transaction& tx)
|
||||
{
|
||||
extra_type_t e = AUTO_VAL_INIT(e);
|
||||
get_type_in_variant_container(tx.extra, e);
|
||||
return e.v;
|
||||
}
|
||||
template<class extra_type_t>
|
||||
void set_tx_x_detail(transaction& tx, uint64_t v)
|
||||
{
|
||||
extra_type_t e = AUTO_VAL_INIT(e);
|
||||
e.v = v;
|
||||
update_or_add_field_to_extra(tx.extra, e);
|
||||
}
|
||||
|
||||
uint64_t get_tx_unlock_time(const transaction& tx, uint64_t o_i);
|
||||
uint64_t get_tx_max_unlock_time(const transaction& tx);
|
||||
bool get_tx_max_min_unlock_time(const transaction& tx, uint64_t& max_unlock_time, uint64_t& min_unlock_time);
|
||||
inline uint64_t get_tx_flags(const transaction& tx) { return get_tx_x_detail<etc_tx_details_flags>(tx); }
|
||||
inline uint64_t get_tx_expiration_time(const transaction& tx) {return get_tx_x_detail<etc_tx_details_expiration_time>(tx); }
|
||||
inline void set_tx_unlock_time(transaction& tx, uint64_t v) { set_tx_x_detail<etc_tx_details_unlock_time>(tx, v); }
|
||||
inline void set_tx_flags(transaction& tx, uint64_t v) { set_tx_x_detail<etc_tx_details_flags>(tx, v); }
|
||||
inline void set_tx_expiration_time(transaction& tx, uint64_t v) { set_tx_x_detail<etc_tx_details_expiration_time>(tx, v); }
|
||||
account_public_address get_crypt_address_from_destinations(const account_keys& sender_account_keys, const std::vector<tx_destination_entry>& destinations);
|
||||
|
||||
|
||||
bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median);
|
||||
uint64_t get_burned_amount(const transaction& tx);
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash);
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ namespace currency {
|
|||
return res.convert_to<wide_difficulty_type>();
|
||||
}
|
||||
|
||||
wide_difficulty_type next_difficulty(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
|
||||
wide_difficulty_type next_difficulty_1(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
|
||||
{
|
||||
|
||||
// timestamps - first is latest, back - is oldest timestamps
|
||||
|
|
@ -220,4 +220,40 @@ namespace currency {
|
|||
}
|
||||
return summ / devider;
|
||||
}
|
||||
|
||||
wide_difficulty_type next_difficulty_2(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
|
||||
{
|
||||
|
||||
// timestamps - first is latest, back - is oldest timestamps
|
||||
if (timestamps.size() > DIFFICULTY_WINDOW)
|
||||
{
|
||||
timestamps.resize(DIFFICULTY_WINDOW);
|
||||
cumulative_difficulties.resize(DIFFICULTY_WINDOW);
|
||||
}
|
||||
|
||||
|
||||
size_t length = timestamps.size();
|
||||
CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed");
|
||||
if (length <= 1)
|
||||
{
|
||||
return DIFFICULTY_STARTER;
|
||||
}
|
||||
static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small");
|
||||
|
||||
CHECK_AND_ASSERT_MES(length <= DIFFICULTY_WINDOW, 0, "length <= DIFFICULTY_WINDOW check failed, length=" << length);
|
||||
|
||||
sort(timestamps.begin(), timestamps.end(), std::greater<uint64_t>());
|
||||
|
||||
static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Cut length is too large");
|
||||
wide_difficulty_type dif_slow = get_adjustment_for_zone(timestamps, cumulative_difficulties, target_seconds, DIFFICULTY_WINDOW, DIFFICULTY_CUT / 2, DIFFICULTY_CUT / 2);
|
||||
wide_difficulty_type dif_medium = get_adjustment_for_zone(timestamps, cumulative_difficulties, target_seconds, DIFFICULTY_WINDOW / 3, DIFFICULTY_CUT / 8, DIFFICULTY_CUT / 12);
|
||||
uint64_t devider = 1;
|
||||
wide_difficulty_type summ = dif_slow;
|
||||
if (dif_medium != 0)
|
||||
{
|
||||
summ += dif_medium;
|
||||
++devider;
|
||||
}
|
||||
return summ / devider;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ namespace currency
|
|||
typedef boost::multiprecision::uint128_t wide_difficulty_type;
|
||||
|
||||
bool check_hash(const crypto::hash &hash, wide_difficulty_type difficulty);
|
||||
wide_difficulty_type next_difficulty(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds);
|
||||
wide_difficulty_type next_difficulty_1(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds);
|
||||
wide_difficulty_type next_difficulty_2(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds);
|
||||
uint64_t difficulty_to_boundary(wide_difficulty_type difficulty);
|
||||
void difficulty_to_boundary_long(wide_difficulty_type difficulty, crypto::hash& result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ int main(int argc, char* argv[])
|
|||
#endif
|
||||
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
|
||||
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
|
||||
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet");
|
||||
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet,lmdb");
|
||||
LOG_PRINT_L0("Starting...");
|
||||
|
||||
tools::signal_handler::install_fatal([](int sig_number, void* address) {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public:
|
|||
m_cmd_binder.set_handler("print_block_from_hex_blob", boost::bind(&daemon_commands_handler::print_block_from_hex_blob, this, _1), "Unserialize block from hex binary data to json-like representation");
|
||||
m_cmd_binder.set_handler("print_tx_from_hex_blob", boost::bind(&daemon_commands_handler::print_tx_from_hex_blob, this, _1), "Unserialize transaction from hex binary data to json-like representation");
|
||||
m_cmd_binder.set_handler("print_tx_outputs_usage", boost::bind(&daemon_commands_handler::print_tx_outputs_usage, this, _1), "Analyse if tx outputs for involved in subsequent transactions");
|
||||
m_cmd_binder.set_handler("print_difficulties_of_last_n_blocks", boost::bind(&daemon_commands_handler::print_difficulties_of_last_n_blocks, this, _1), "Print difficulties of last n blocks");
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -696,8 +697,26 @@ private:
|
|||
m_srv.get_payload_object().get_core().get_blockchain_storage().print_tx_outputs_lookup(tx_hash);
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool print_difficulties_of_last_n_blocks(const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty())
|
||||
{
|
||||
std::cout << "expected: n - number of blocks to read" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string& amount = args.front();
|
||||
uint64_t n = 0;
|
||||
if (!epee::string_tools::get_xtype_from_string(n, amount))
|
||||
{
|
||||
std::cout << "unable to convert to number '" << amount << "'" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_srv.get_payload_object().get_core().get_blockchain_storage().print_last_n_difficulty_numbers(n);
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool print_pool(const std::vector<std::string>& args)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -798,6 +798,7 @@ namespace currency
|
|||
currency::pos_entry pe = AUTO_VAL_INIT(pe);
|
||||
pe.amount = req.pos_amount;
|
||||
pe.index = req.pos_index;
|
||||
pe.stake_unlock_time = req.stake_unlock_time;
|
||||
//pe.keyimage key image will be set in the wallet
|
||||
//pe.wallet_index is not included in serialization map, TODO: refactoring here
|
||||
|
||||
|
|
|
|||
|
|
@ -778,6 +778,7 @@ namespace currency
|
|||
bool pos_block; //is pos block
|
||||
uint64_t pos_amount; //
|
||||
uint64_t pos_index; //
|
||||
uint64_t stake_unlock_time;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(extra_text)
|
||||
|
|
@ -786,6 +787,7 @@ namespace currency
|
|||
KV_SERIALIZE(pos_block)
|
||||
KV_SERIALIZE(pos_amount)
|
||||
KV_SERIALIZE(pos_index)
|
||||
KV_SERIALIZE(stake_unlock_time)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ namespace
|
|||
#define HR_TO_STREAM_IN_MHS_3P(hr) std::fixed << std::setprecision(3) << hr / 1000000.0
|
||||
|
||||
// debug stuff
|
||||
#define DBG_NETWORK_DIFFICULTY 0 // if non-zero: use this value as net difficulty when checking shares (useful for debugging on testnet, recommended value is 1600000000ull)
|
||||
#define DBG_NETWORK_DIFFICULTY 0 // if non-zero: use this value as net difficulty when checking shares (useful for debugging on testnet, recommended value is 3000000000ull)
|
||||
#define DBG_CORE_ALWAYS_SYNCRONIZED 0 // if set to 1: allows the server to start even if the core is not syncronized, useful for debugging with --offline-mode
|
||||
#define STRINGIZE_DETAIL(x) #x
|
||||
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,35 @@ using namespace currency;
|
|||
ENABLE_CHANNEL_BY_DEFAULT("wallet")
|
||||
namespace tools
|
||||
{
|
||||
|
||||
//---------------------------------------------------------------
|
||||
uint64_t wallet2::get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const money_transfer2_details& td)
|
||||
{
|
||||
uint64_t max_unlock_time = 0;
|
||||
// etc_tx_details_expiration_time have priority over etc_tx_details_expiration_time2
|
||||
uint64_t major_unlock_time = get_tx_x_detail<etc_tx_details_unlock_time>(tx);
|
||||
if (major_unlock_time)
|
||||
return major_unlock_time;
|
||||
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
get_type_in_variant_container(tx.extra, ut2);
|
||||
if (!ut2.unlock_time_array.size())
|
||||
return 0;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(ut2.unlock_time_array.size() == tx.vout.size(), "Internal error: wrong tx transfer details: ut2.unlock_time_array.size()" << ut2.unlock_time_array.size() << " is not equal transaction outputs vector size=" << tx.vout.size());
|
||||
|
||||
for (auto ri : td.receive_indices)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(ri < tx.vout.size(), "Internal error: wrong tx transfer details: reciev index=" << ri << " is greater than transaction outputs vector " << tx.vout.size());
|
||||
if (tx.vout[ri].target.type() == typeid(currency::txout_to_key))
|
||||
{
|
||||
//update unlock_time if needed
|
||||
if (ut2.unlock_time_array[ri] > max_unlock_time)
|
||||
max_unlock_time = ut2.unlock_time_array[ri];
|
||||
}
|
||||
}
|
||||
return max_unlock_time;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::fill_transfer_details(const currency::transaction& tx, const tools::money_transfer2_details& td, tools::wallet_rpc::wallet_transfer_info_details& res_td) const
|
||||
{
|
||||
|
|
@ -48,7 +77,9 @@ void wallet2::fill_transfer_details(const currency::transaction& tx, const tools
|
|||
{
|
||||
WLT_CHECK_AND_ASSERT_MES(ri < tx.vout.size(), void(), "Internal error: wrong tx transfer details: reciev index=" << ri << " is greater than transaction outputs vector " << tx.vout.size());
|
||||
if (tx.vout[ri].target.type() == typeid(currency::txout_to_key))
|
||||
{
|
||||
res_td.rcv.push_back(tx.vout[ri].amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -258,8 +289,14 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
i++;
|
||||
}
|
||||
|
||||
//check for transaction income
|
||||
/*
|
||||
collect unlock_time from every output that transfered coins to this account and use maximum of
|
||||
all values m_payments entry, use this strict policy is required to protect exchanges from being feeded with
|
||||
useless outputs
|
||||
*/
|
||||
uint64_t max_out_unlock_time = 0;
|
||||
|
||||
//check for transaction income
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs, derivation);
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys());
|
||||
|
|
@ -355,6 +392,10 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
if (td.m_key_image != currency::null_ki)
|
||||
m_key_images[td.m_key_image] = transfer_index;
|
||||
add_transfer_to_transfers_cache(tx.vout[o].amount, transfer_index);
|
||||
|
||||
if (max_out_unlock_time < get_tx_unlock_time(tx, o))
|
||||
max_out_unlock_time = get_tx_unlock_time(tx, o);
|
||||
|
||||
WLT_LOG_L0("Received money, transfer #" << transfer_index << ", amount: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height);
|
||||
}
|
||||
else if (tx.vout[o].target.type() == typeid(txout_multisig))
|
||||
|
|
@ -379,7 +420,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
payment.m_tx_hash = currency::get_transaction_hash(tx);
|
||||
payment.m_amount = received;
|
||||
payment.m_block_height = height;
|
||||
payment.m_unlock_time = currency::get_tx_unlock_time(tx);
|
||||
payment.m_unlock_time = max_out_unlock_time;
|
||||
m_payments.emplace(payment_id, payment);
|
||||
WLT_LOG_L2("Payment found, id (hex): " << epee::string_tools::buff_to_hex_nodelimer(payment_id) << ", tx: " << payment.m_tx_hash << ", amount: " << print_money_brief(payment.m_amount));
|
||||
}
|
||||
|
|
@ -919,9 +960,9 @@ void wallet2::prepare_wti(wallet_rpc::wallet_transfer_info& wti, uint64_t height
|
|||
wti.amount = amount;
|
||||
wti.height = height;
|
||||
fill_transfer_details(tx, td, wti.td);
|
||||
wti.unlock_time = get_max_unlock_time_from_receive_indices(tx, td);
|
||||
wti.timestamp = timestamp;
|
||||
wti.fee = currency::is_coinbase(tx) ? 0:currency::get_tx_fee(tx);
|
||||
wti.unlock_time = get_tx_unlock_time(tx);
|
||||
wti.tx_blob_size = static_cast<uint32_t>(currency::get_object_blobsize(wti.tx));
|
||||
wti.tx_hash = currency::get_transaction_hash(tx);
|
||||
wti.is_service = currency::is_service_tx(tx);
|
||||
|
|
@ -1027,6 +1068,8 @@ void wallet2::process_new_blockchain_entry(const currency::block& b, const curre
|
|||
m_blockchain.push_back(bl_id);
|
||||
++m_local_bc_height;
|
||||
m_last_bc_timestamp = b.timestamp;
|
||||
if (!is_pos_block(b))
|
||||
m_last_pow_block_h = height;
|
||||
|
||||
m_wcallback->on_new_block(height, b);
|
||||
}
|
||||
|
|
@ -1762,6 +1805,7 @@ bool wallet2::reset_all()
|
|||
m_last_bc_timestamp = 0;
|
||||
m_height_of_start_sync = 0;
|
||||
m_last_sync_percent = 0;
|
||||
m_last_pow_block_h = 0;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -2396,17 +2440,22 @@ bool wallet2::get_transfer_address(const std::string& adr_str, currency::account
|
|||
return m_core_proxy->get_transfer_address(adr_str, addr, payment_id);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_okay_for_pos(const transfer_details& tr)
|
||||
bool wallet2::is_transfer_okay_for_pos(const transfer_details& tr, uint64_t& stake_unlock_time)
|
||||
{
|
||||
if (!tr.is_spendable())
|
||||
return false;
|
||||
|
||||
//blockchain conditions
|
||||
if (!is_transfer_unlocked(tr))
|
||||
if (!is_transfer_unlocked(tr, true, stake_unlock_time))
|
||||
return false;
|
||||
|
||||
//prevent staking of after-last-pow-coins
|
||||
if (m_blockchain.size() - tr.m_ptx_wallet_info->m_block_height <= m_core_runtime_config.min_coinstake_age)
|
||||
return false;
|
||||
|
||||
if (tr.m_ptx_wallet_info->m_block_height > m_last_pow_block_h)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -2430,13 +2479,15 @@ bool wallet2::get_pos_entries(currency::COMMAND_RPC_SCAN_POS::request& req)
|
|||
for (size_t i = 0; i != m_transfers.size(); i++)
|
||||
{
|
||||
auto& tr = m_transfers[i];
|
||||
if (!is_transfer_okay_for_pos(tr))
|
||||
uint64_t stake_unlock_time = 0;
|
||||
if (!is_transfer_okay_for_pos(tr, stake_unlock_time))
|
||||
continue;
|
||||
currency::pos_entry pe = AUTO_VAL_INIT(pe);
|
||||
pe.amount = tr.amount();
|
||||
pe.index = tr.m_global_output_index;
|
||||
pe.keyimage = tr.m_key_image;
|
||||
pe.wallet_index = i;
|
||||
pe.stake_unlock_time = stake_unlock_time;
|
||||
pe.block_timestamp = tr.m_ptx_wallet_info->m_block_timestamp;
|
||||
req.pos_entries.push_back(pe);
|
||||
}
|
||||
|
|
@ -2613,6 +2664,7 @@ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request&
|
|||
tmpl_req.pos_amount = req.pos_entries[rsp.index].amount;
|
||||
tmpl_req.pos_index = req.pos_entries[rsp.index].index;
|
||||
tmpl_req.extra_text = m_miner_text_info;
|
||||
tmpl_req.stake_unlock_time = req.pos_entries[rsp.index].stake_unlock_time;
|
||||
m_core_proxy->call_COMMAND_RPC_GETBLOCKTEMPLATE(tmpl_req, tmpl_rsp);
|
||||
WLT_CHECK_AND_ASSERT_MES(tmpl_rsp.status == CORE_RPC_STATUS_OK, false, "Failed to create block template after kernel hash found!");
|
||||
|
||||
|
|
@ -2695,16 +2747,32 @@ currency::core_runtime_config& wallet2::get_core_runtime_config()
|
|||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_unlocked(const transfer_details& td) const
|
||||
{
|
||||
uint64_t stub = 0;
|
||||
return is_transfer_unlocked(td, false, stub);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_transfer_unlocked(const transfer_details& td, bool for_pos_mining, uint64_t& stake_lock_time) const
|
||||
{
|
||||
if (td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_BLOCKED)
|
||||
return false;
|
||||
|
||||
if (!currency::is_tx_spendtime_unlocked(get_tx_unlock_time(td.m_ptx_wallet_info->m_tx), m_blockchain.size(), m_core_runtime_config.get_core_time()))
|
||||
if (td.m_ptx_wallet_info->m_block_height + WALLET_DEFAULT_TX_SPENDABLE_AGE > m_blockchain.size())
|
||||
return false;
|
||||
|
||||
if(td.m_ptx_wallet_info->m_block_height + WALLET_DEFAULT_TX_SPENDABLE_AGE > m_blockchain.size())
|
||||
return false;
|
||||
|
||||
|
||||
uint64_t unlock_time = get_tx_unlock_time(td.m_ptx_wallet_info->m_tx, td.m_internal_output_index);
|
||||
if (for_pos_mining && m_blockchain.size() > m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
{
|
||||
//allowed of staking locked coins with
|
||||
stake_lock_time = unlock_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!currency::is_tx_spendtime_unlocked(unlock_time, m_blockchain.size(), m_core_runtime_config.get_core_time()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ ENABLE_CHANNEL_BY_DEFAULT("wallet");
|
|||
#define WLT_CHECK_AND_ASSERT_MES_NO_RET(expr, msg) CHECK_AND_ASSERT_MES_NO_RET(expr, "[W:" << m_log_prefix << "]" << msg)
|
||||
#define WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, msg) THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, "[W:" << m_log_prefix << "]" << msg)
|
||||
|
||||
class test_generator;
|
||||
|
||||
namespace tools
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
|
|
@ -310,7 +312,8 @@ namespace tools
|
|||
m_height_of_start_sync(0),
|
||||
m_last_sync_percent(0),
|
||||
m_do_rise_transfer(false),
|
||||
m_watch_only(false)
|
||||
m_watch_only(false),
|
||||
m_last_pow_block_h(0)
|
||||
{};
|
||||
public:
|
||||
wallet2() : m_stop(false),
|
||||
|
|
@ -322,7 +325,8 @@ namespace tools
|
|||
m_fake_outputs_count(0),
|
||||
m_do_rise_transfer(false),
|
||||
m_log_prefix("???"),
|
||||
m_watch_only(false)
|
||||
m_watch_only(false),
|
||||
m_last_pow_block_h(0)
|
||||
{
|
||||
m_core_runtime_config = currency::get_default_core_runtime_config();
|
||||
};
|
||||
|
|
@ -615,7 +619,7 @@ namespace tools
|
|||
return;
|
||||
}
|
||||
|
||||
if (ver < 147)
|
||||
if (ver < 149)
|
||||
{
|
||||
LOG_PRINT_MAGENTA("Wallet file truncated due to old version", LOG_LEVEL_0);
|
||||
return;
|
||||
|
|
@ -650,6 +654,7 @@ namespace tools
|
|||
a & m_money_expirations;
|
||||
a & m_pending_key_images;
|
||||
a & m_tx_keys;
|
||||
a & m_last_pow_block_h;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -661,7 +666,7 @@ namespace tools
|
|||
//synchronous version of function
|
||||
bool try_mint_pos();
|
||||
//for unit tests
|
||||
friend class test_generator;
|
||||
friend class ::test_generator;
|
||||
|
||||
//next functions in public area only because of test_generator
|
||||
//TODO: Need refactoring - remove it back to private zone
|
||||
|
|
@ -680,6 +685,7 @@ namespace tools
|
|||
bool build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& req, const currency::COMMAND_RPC_SCAN_POS::response& rsp, const currency::account_public_address& miner_address, uint64_t new_block_expected_height = UINT64_MAX);
|
||||
bool reset_history();
|
||||
bool is_transfer_unlocked(const transfer_details& td) const;
|
||||
bool is_transfer_unlocked(const transfer_details& td, bool for_pos_mining, uint64_t& stake_lock_time) const;
|
||||
void get_mining_history(wallet_rpc::mining_history& hist);
|
||||
void set_core_runtime_config(const currency::core_runtime_config& pc);
|
||||
currency::core_runtime_config& get_core_runtime_config();
|
||||
|
|
@ -717,7 +723,7 @@ namespace tools
|
|||
void finalize_transaction(const finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx);
|
||||
|
||||
std::string get_log_prefix() const { return m_log_prefix; }
|
||||
|
||||
static uint64_t get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const money_transfer2_details& td);
|
||||
private:
|
||||
void add_transfers_to_expiration_list(const std::vector<uint64_t>& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id);
|
||||
void remove_transfer_from_expiration_list(uint64_t transfer_index);
|
||||
|
|
@ -765,7 +771,7 @@ private:
|
|||
std::string get_alias_for_address(const std::string& addr);
|
||||
static bool build_kernel(const currency::pos_entry& pe, const currency::stake_modifier_type& stake_modifier, currency::stake_kernel& kernel, uint64_t& coindays_weight, uint64_t timestamp);
|
||||
bool is_connected_to_net();
|
||||
bool is_transfer_okay_for_pos(const transfer_details& tr);
|
||||
bool is_transfer_okay_for_pos(const transfer_details& tr, uint64_t& stake_unlock_time);
|
||||
bool scan_unconfirmed_outdate_tx();
|
||||
const currency::transaction& get_transaction_by_id(const crypto::hash& tx_hash);
|
||||
void rise_on_transfer2(const wallet_rpc::wallet_transfer_info& wti);
|
||||
|
|
@ -812,6 +818,7 @@ private:
|
|||
const std::vector<currency::payload_items_v>& decrypted_items, crypto::hash& ms_id, bc_services::contract_private_details& cpd,
|
||||
const currency::transaction& proposal_template_tx);
|
||||
|
||||
|
||||
void fill_transfer_details(const currency::transaction& tx, const tools::money_transfer2_details& td, tools::wallet_rpc::wallet_transfer_info_details& res_td) const;
|
||||
void print_source_entry(const currency::tx_source_entry& src) const;
|
||||
|
||||
|
|
@ -862,6 +869,7 @@ private:
|
|||
std::shared_ptr<i_wallet2_callback> m_wcallback;
|
||||
uint64_t m_height_of_start_sync;
|
||||
uint64_t m_last_sync_percent;
|
||||
uint64_t m_last_pow_block_h;
|
||||
currency::core_runtime_config m_core_runtime_config;
|
||||
escrow_contracts_container m_contracts;
|
||||
std::list<expiration_entry_info> m_money_expirations;
|
||||
|
|
@ -871,6 +879,8 @@ private:
|
|||
uint64_t m_fake_outputs_count;
|
||||
std::string m_miner_text_info;
|
||||
|
||||
//this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions
|
||||
friend class test_generator;
|
||||
|
||||
}; // class wallet2
|
||||
|
||||
|
|
@ -947,10 +957,11 @@ namespace boost
|
|||
a & x.contract;
|
||||
a & x.selected_indicies;
|
||||
a & x.srv_attachments;
|
||||
a & x.unlock_time;
|
||||
//do not store this items in the file since it's quite easy to restore it from original tx
|
||||
if (Archive::is_loading::value)
|
||||
{
|
||||
x.unlock_time = currency::get_tx_unlock_time(x.tx);
|
||||
|
||||
x.is_service = currency::is_service_tx(x.tx);
|
||||
x.is_mixing = currency::is_mixin_tx(x.tx);
|
||||
x.is_mining = currency::is_coinbase(x.tx);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ bool wallet2::validate_escrow_proposal(const wallet_rpc::wallet_transfer_info& w
|
|||
|
||||
// I. validate escrow proposal tx
|
||||
const transaction& escrow_proposal_tx = wti.tx;
|
||||
uint64_t escrow_proposal_tx_unlock_time = get_tx_unlock_time(escrow_proposal_tx);
|
||||
uint64_t escrow_proposal_tx_unlock_time = get_tx_max_unlock_time(escrow_proposal_tx);
|
||||
LOC_CHK(escrow_proposal_tx_unlock_time == 0, "proposal tx unlock time is non-zero: " << escrow_proposal_tx_unlock_time);
|
||||
|
||||
uint64_t escrow_proposal_expiration_time = get_tx_expiration_time(escrow_proposal_tx);
|
||||
|
|
@ -66,7 +66,7 @@ bool wallet2::validate_escrow_proposal(const wallet_rpc::wallet_transfer_info& w
|
|||
uint64_t template_expiration_time = get_tx_expiration_time(prop.tx_template);
|
||||
LOC_CHK(template_expiration_time != 0, "template has no expiration time");
|
||||
|
||||
uint64_t template_unlock_time = get_tx_unlock_time(prop.tx_template);
|
||||
uint64_t template_unlock_time = get_tx_max_unlock_time(prop.tx_template);
|
||||
LOC_CHK(template_unlock_time == 0, "template has non-zero unlock time: " << template_unlock_time);
|
||||
|
||||
// (3/5) outputs
|
||||
|
|
@ -156,7 +156,7 @@ bool wallet2::validate_escrow_release(const transaction& tx, bool release_type_n
|
|||
uint64_t expiration_time = get_tx_expiration_time(tx);
|
||||
LOC_CHK(expiration_time == 0, "tx has non-zero expiration time: " << expiration_time);
|
||||
|
||||
uint64_t unlock_time = get_tx_unlock_time(tx);
|
||||
uint64_t unlock_time = get_tx_max_unlock_time(tx);
|
||||
LOC_CHK(unlock_time == 0, "tx has non-zero unlock time: " << unlock_time);
|
||||
|
||||
tx_service_attachment tsa = AUTO_VAL_INIT(tsa);
|
||||
|
|
@ -285,7 +285,7 @@ bool wallet2::validate_escrow_contract(const wallet_rpc::wallet_transfer_info& w
|
|||
uint64_t tx_expiration_time = get_tx_expiration_time(wti.tx);
|
||||
LOC_CHK(tx_expiration_time != 0, "no or zero expiration time specified");
|
||||
|
||||
uint64_t tx_unlock_time = get_tx_unlock_time(wti.tx);
|
||||
uint64_t tx_unlock_time = get_tx_max_unlock_time(wti.tx);
|
||||
LOC_CHK(tx_unlock_time == 0, "non-zero unlock time: " << tx_unlock_time);
|
||||
|
||||
#undef LOC_CHK
|
||||
|
|
@ -341,7 +341,7 @@ bool wallet2::validate_escrow_cancel_release(const currency::transaction& tx, co
|
|||
uint64_t expiration_time = get_tx_expiration_time(tx);
|
||||
LOC_CHK(expiration_time != 0, "tx has zero or not specified expiration time");
|
||||
|
||||
uint64_t unlock_time = get_tx_unlock_time(tx);
|
||||
uint64_t unlock_time = get_tx_max_unlock_time(tx);
|
||||
LOC_CHK(unlock_time == 0, "tx has non-zero unlock time: " << unlock_time);
|
||||
|
||||
tx_service_attachment tsa = AUTO_VAL_INIT(tsa);
|
||||
|
|
@ -430,7 +430,7 @@ bool wallet2::validate_escrow_cancel_proposal(const wallet_rpc::wallet_transfer_
|
|||
uint64_t flags = get_tx_flags(wti.tx);
|
||||
LOC_CHK(flags == 0, "invalid tx flags: " << flags);
|
||||
|
||||
uint64_t unlock_time = get_tx_unlock_time(cancellation_request_tx);
|
||||
uint64_t unlock_time = get_tx_max_unlock_time(cancellation_request_tx);
|
||||
LOC_CHK(unlock_time == 0, "invalid unlock time: " << unlock_time);
|
||||
|
||||
uint64_t expiration_time = get_tx_expiration_time(cancellation_request_tx);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace
|
|||
for (size_t i = 0; i < new_block_count; ++i)
|
||||
{
|
||||
block blk_next;
|
||||
wide_difficulty_type diffic = next_difficulty(timestamps, cummulative_difficulties, DIFFICULTY_POW_TARGET);
|
||||
wide_difficulty_type diffic = next_difficulty_1(timestamps, cummulative_difficulties, DIFFICULTY_POW_TARGET);
|
||||
if (!generator.construct_block_manually(blk_next, blk_prev, miner_account,
|
||||
test_generator::bf_timestamp | test_generator::bf_diffic, 0, 0, blk_prev.timestamp, crypto::hash(), diffic))
|
||||
return false;
|
||||
|
|
@ -152,7 +152,7 @@ bool gen_block_invalid_nonce::generate(std::vector<test_event_entry>& events) co
|
|||
return false;
|
||||
|
||||
// Create invalid nonce
|
||||
wide_difficulty_type diffic = next_difficulty(timestamps, commulative_difficulties, DIFFICULTY_POW_TARGET);
|
||||
wide_difficulty_type diffic = next_difficulty_1(timestamps, commulative_difficulties, DIFFICULTY_POW_TARGET);
|
||||
CHECK_AND_ASSERT_MES(diffic > 1, false, "diffic > 1 validation failed");
|
||||
const block& blk_last = boost::get<block>(events.back());
|
||||
uint64_t timestamp = blk_last.timestamp;
|
||||
|
|
@ -193,7 +193,7 @@ bool gen_block_unlock_time_is_low::generate(std::vector<test_event_entry>& event
|
|||
BLOCK_VALIDATION_INIT_GENERATE();
|
||||
|
||||
MAKE_MINER_TX_MANUALLY(miner_tx, blk_0);
|
||||
currency::set_tx_unlock_time(miner_tx, currency::get_tx_unlock_time(miner_tx) - 1);
|
||||
currency::set_tx_unlock_time(miner_tx, currency::get_tx_max_unlock_time(miner_tx) - 1);
|
||||
|
||||
block blk_1;
|
||||
generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx);
|
||||
|
|
@ -209,7 +209,7 @@ bool gen_block_unlock_time_is_high::generate(std::vector<test_event_entry>& even
|
|||
BLOCK_VALIDATION_INIT_GENERATE();
|
||||
|
||||
MAKE_MINER_TX_MANUALLY(miner_tx, blk_0);
|
||||
set_tx_unlock_time(miner_tx, get_tx_unlock_time(miner_tx) + 1);
|
||||
set_tx_unlock_time(miner_tx, get_tx_max_unlock_time(miner_tx) + 1);
|
||||
|
||||
block blk_1;
|
||||
generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx);
|
||||
|
|
|
|||
|
|
@ -46,10 +46,19 @@ crypto::signature create_invalid_signature()
|
|||
const crypto::signature invalid_signature = create_invalid_signature();
|
||||
|
||||
test_generator::test_generator()
|
||||
: m_wallet_test_core_proxy(new wallet_test_core_proxy())
|
||||
: m_wallet_test_core_proxy(new wallet_test_core_proxy()),
|
||||
m_do_pos_to_low_timestamp(false),
|
||||
m_ignore_last_pow_in_wallets(false),
|
||||
m_last_found_timestamp(0),
|
||||
m_hardfork_after_heigh(CURRENCY_MAX_BLOCK_NUMBER)
|
||||
{
|
||||
}
|
||||
|
||||
void test_generator::set_hardfork_height(uint64_t h)
|
||||
{
|
||||
m_hardfork_after_heigh = h;
|
||||
}
|
||||
|
||||
void test_generator::get_block_chain(std::vector<const block_info*>& blockchain, const crypto::hash& head, size_t n) const
|
||||
{
|
||||
crypto::hash curr = head;
|
||||
|
|
@ -142,6 +151,7 @@ void test_generator::add_block(const currency::block& blk,
|
|||
get_block_reward(is_pos_block(blk), misc_utils::median(block_sizes), block_size, already_generated_coins, block_reward, currency::get_block_height(blk));
|
||||
|
||||
m_blocks_info[get_block_hash(blk)] = block_info(blk, already_generated_coins + block_reward, block_size, cum_diff, tx_list, ks_hash);
|
||||
LOG_PRINT_MAGENTA("ADDED_BLOCK[" << get_block_hash(blk) << "][" << (is_pos_block(blk)? "PoS":"PoW") <<"][" << get_block_height(blk) << "][cumul_diff:" << cum_diff << "]", LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
void test_generator::add_block_info(const block_info& bi)
|
||||
|
|
@ -191,7 +201,11 @@ bool test_generator::construct_block(currency::block& blk,
|
|||
const std::list<currency::transaction>& tx_list,
|
||||
const std::list<currency::account_base>& coin_stake_sources)//in case of PoS block
|
||||
{
|
||||
blk.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
if (height > m_hardfork_after_heigh)
|
||||
blk.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
else
|
||||
blk.major_version = BLOCK_MAJOR_VERSION_INITAL;
|
||||
|
||||
blk.minor_version = CURRENT_BLOCK_MINOR_VERSION;
|
||||
blk.timestamp = timestamp;
|
||||
blk.prev_id = prev_id;
|
||||
|
|
@ -305,11 +319,13 @@ bool test_generator::construct_block(currency::block& blk,
|
|||
CHECK_AND_ASSERT_MES(r, false, "Failed to find_kernel_and_sign()");
|
||||
}
|
||||
|
||||
uint64_t last_x = get_last_block_of_type(is_pos_block(blk), blocks);
|
||||
|
||||
add_block(blk,
|
||||
txs_size,
|
||||
block_sizes,
|
||||
already_generated_coins,
|
||||
blocks.size() ? blocks.back()->cumul_difficulty + a_diffic: a_diffic,
|
||||
last_x ? blocks[last_x]->cumul_difficulty + a_diffic: a_diffic,
|
||||
tx_list,
|
||||
kernerl_hash);
|
||||
|
||||
|
|
@ -382,6 +398,7 @@ bool test_generator::build_wallets(const blockchain_vector& blocks,
|
|||
currency::core_runtime_config pc = cc;
|
||||
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE;
|
||||
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH;
|
||||
pc.hard_fork1_starts_after_height = m_hardfork_after_heigh;
|
||||
wallets.back()->set_core_runtime_config(pc);
|
||||
}
|
||||
|
||||
|
|
@ -466,33 +483,52 @@ bool test_generator::find_kernel(const std::list<currency::account_base>& accs,
|
|||
uint64_t& found_timestamp,
|
||||
crypto::hash& found_kh)
|
||||
{
|
||||
bool is_after_hardfork = blck_chain.size() > m_hardfork_after_heigh ? true : false;
|
||||
uint64_t median_timestamp = get_timestamps_median(blck_chain);
|
||||
wide_difficulty_type basic_diff = 0;
|
||||
|
||||
uint64_t i_last_pow_block = get_last_block_of_type(false, blck_chain);
|
||||
uint64_t expected_avr_timestamp = blck_chain[i_last_pow_block]->b.timestamp + (blck_chain.size() - i_last_pow_block - 1)*DIFFICULTY_POW_TARGET;
|
||||
uint64_t starter_timestamp = expected_avr_timestamp - POS_SCAN_WINDOW;
|
||||
uint64_t i_last_pos_block = get_last_block_of_type(true, blck_chain);
|
||||
|
||||
uint64_t last_pos_block_timestamp = 0;
|
||||
if(i_last_pos_block)
|
||||
last_pos_block_timestamp = blck_chain[i_last_pos_block]->b.timestamp;
|
||||
else
|
||||
last_pos_block_timestamp = blck_chain.back()->b.timestamp - DIFFICULTY_POS_TARGET/2;
|
||||
|
||||
uint64_t starter_timestamp = last_pos_block_timestamp + DIFFICULTY_POS_TARGET;
|
||||
|
||||
if (starter_timestamp < median_timestamp)
|
||||
starter_timestamp = median_timestamp;
|
||||
|
||||
|
||||
m_last_found_timestamp = 0;
|
||||
basic_diff = get_difficulty_for_next_block(blck_chain, false);
|
||||
|
||||
//lets try to find block
|
||||
for (auto& w : wallets)
|
||||
if (basic_diff < 10)
|
||||
{
|
||||
currency::COMMAND_RPC_SCAN_POS::request scan_pos_entries;
|
||||
bool r = w->get_pos_entries(scan_pos_entries);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get_pos_entries");
|
||||
starter_timestamp -= 90;
|
||||
}
|
||||
if (m_do_pos_to_low_timestamp)
|
||||
starter_timestamp += 60;
|
||||
|
||||
for (size_t i = 0; i != scan_pos_entries.pos_entries.size(); i++)
|
||||
//adjust timestamp starting from timestamp%POS_SCAN_STEP = 0
|
||||
//starter_timestamp = starter_timestamp - POS_SCAN_WINDOW;
|
||||
starter_timestamp = POS_SCAN_STEP - (starter_timestamp%POS_SCAN_STEP) + starter_timestamp;
|
||||
|
||||
for (uint64_t ts = starter_timestamp; ts < starter_timestamp + POS_SCAN_WINDOW/2; ts += POS_SCAN_STEP)
|
||||
{
|
||||
//lets try to find block
|
||||
for (auto& w : wallets)
|
||||
{
|
||||
//adjust timestamp starting from timestamp%POS_SCAN_STEP = 0
|
||||
starter_timestamp = starter_timestamp - POS_SCAN_WINDOW;
|
||||
starter_timestamp = POS_SCAN_STEP - (starter_timestamp%POS_SCAN_STEP) + starter_timestamp;
|
||||
//set m_last_pow_block_h to big value, to let wallet to use any available outputs, including the those which is not behind last pow block
|
||||
if (m_ignore_last_pow_in_wallets)
|
||||
w->m_last_pow_block_h = CURRENCY_MAX_BLOCK_NUMBER;
|
||||
|
||||
for (uint64_t ts = starter_timestamp; ts < expected_avr_timestamp + POS_SCAN_WINDOW; ts += POS_SCAN_STEP)
|
||||
currency::COMMAND_RPC_SCAN_POS::request scan_pos_entries;
|
||||
bool r = w->get_pos_entries(scan_pos_entries);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get_pos_entries");
|
||||
|
||||
for (size_t i = 0; i != scan_pos_entries.pos_entries.size(); i++)
|
||||
{
|
||||
|
||||
stake_kernel sk = AUTO_VAL_INIT(sk);
|
||||
uint64_t coindays_weight = 0;
|
||||
build_kernel(scan_pos_entries.pos_entries[i].amount,
|
||||
|
|
@ -509,10 +545,23 @@ bool test_generator::find_kernel(const std::list<currency::account_base>& accs,
|
|||
continue;
|
||||
else
|
||||
{
|
||||
if (m_do_pos_to_low_timestamp)
|
||||
{
|
||||
if (!m_last_found_timestamp)
|
||||
{
|
||||
m_last_found_timestamp = ts;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(m_last_found_timestamp >= ts)
|
||||
continue;
|
||||
}
|
||||
|
||||
//found kernel
|
||||
LOG_PRINT_GREEN("Found kernel: amount=" << print_money(scan_pos_entries.pos_entries[i].amount)
|
||||
<< ", index=" << scan_pos_entries.pos_entries[i].index
|
||||
<< ", key_image" << scan_pos_entries.pos_entries[i].keyimage, LOG_LEVEL_0);
|
||||
<< ", key_image" << scan_pos_entries.pos_entries[i].keyimage
|
||||
<< ", diff: " << this_coin_diff, LOG_LEVEL_0);
|
||||
pe = scan_pos_entries.pos_entries[i];
|
||||
found_wallet_index = i;
|
||||
found_kh = kernel_hash;
|
||||
|
|
@ -673,7 +722,7 @@ currency::wide_difficulty_type test_generator::get_difficulty_for_next_block(con
|
|||
timestamps.push_back(blocks[i]->b.timestamp);
|
||||
commulative_difficulties.push_back(blocks[i]->cumul_difficulty);
|
||||
}
|
||||
return next_difficulty(timestamps, commulative_difficulties, pow ? DIFFICULTY_POW_TARGET : DIFFICULTY_POS_TARGET);
|
||||
return next_difficulty_1(timestamps, commulative_difficulties, pow ? DIFFICULTY_POW_TARGET : DIFFICULTY_POS_TARGET);
|
||||
}
|
||||
|
||||
currency::wide_difficulty_type test_generator::get_cumul_difficulty_for_next_block(const crypto::hash& head_id, bool pow) const
|
||||
|
|
@ -743,10 +792,19 @@ bool test_generator::construct_block(const std::vector<test_event_entry>& events
|
|||
const currency::block& blk_prev,
|
||||
const currency::account_base& miner_acc,
|
||||
const std::list<currency::transaction>& tx_list,
|
||||
const std::list<currency::account_base>& coin_stake_sources
|
||||
)
|
||||
const std::list<currency::account_base>& coin_stake_sources)
|
||||
{
|
||||
uint64_t height = boost::get<txin_gen>(blk_prev.miner_tx.vin.front()).height + 1;
|
||||
return construct_block(0, events, blk, blk_prev, miner_acc, tx_list, coin_stake_sources);
|
||||
}
|
||||
bool test_generator::construct_block(int64_t manual_timestamp_adjustment,
|
||||
const std::vector<test_event_entry>& events,
|
||||
currency::block& blk,
|
||||
const currency::block& blk_prev,
|
||||
const currency::account_base& miner_acc,
|
||||
const std::list<currency::transaction>& tx_list,
|
||||
const std::list<currency::account_base>& coin_stake_sources)
|
||||
{
|
||||
uint64_t height = boost::get<txin_gen>(blk_prev.miner_tx.vin[0]).height + 1;
|
||||
crypto::hash prev_id = get_block_hash(blk_prev);
|
||||
// Keep push difficulty little up to be sure about PoW hash success
|
||||
std::vector<currency::block> blockchain;
|
||||
|
|
@ -769,6 +827,7 @@ bool test_generator::construct_block(const std::vector<test_event_entry>& events
|
|||
block& prev_same_type = blockchain[prev_i];
|
||||
|
||||
timestamp = adjust_timestamp_finished ? prev_same_type.timestamp + diff_target : prev_same_type.timestamp + diff_target - diff_up_timestamp_delta;
|
||||
timestamp = timestamp + manual_timestamp_adjustment;
|
||||
|
||||
uint64_t already_generated_coins = get_already_generated_coins(prev_id);
|
||||
std::vector<size_t> block_sizes;
|
||||
|
|
@ -786,7 +845,7 @@ bool test_generator::construct_block(const std::vector<test_event_entry>& events
|
|||
size_t txs_sizes/* = 0*/)
|
||||
{
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
blk.major_version = actual_params & bf_major_ver ? major_ver : CURRENT_BLOCK_MAJOR_VERSION;
|
||||
blk.major_version = actual_params & bf_major_ver ? major_ver : BLOCK_MAJOR_VERSION_INITAL;
|
||||
blk.minor_version = actual_params & bf_minor_ver ? minor_ver : CURRENT_BLOCK_MINOR_VERSION;
|
||||
blk.timestamp = actual_params & bf_timestamp ? timestamp : (height > 10 ? prev_block.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN: prev_block.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN-POW_DIFF_UP_TIMESTAMP_DELTA); // Keep difficulty unchanged
|
||||
blk.prev_id = actual_params & bf_prev_id ? prev_id : get_block_hash(prev_block);
|
||||
|
|
@ -1197,10 +1256,10 @@ bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std:
|
|||
continue;
|
||||
if (check_for_unlocktime)
|
||||
{
|
||||
if (currency::get_tx_unlock_time(*oi.p_tx) < CURRENCY_MAX_BLOCK_NUMBER)
|
||||
if (currency::get_tx_max_unlock_time(*oi.p_tx) < CURRENCY_MAX_BLOCK_NUMBER)
|
||||
{
|
||||
//interpret as block index
|
||||
if (currency::get_tx_unlock_time(*oi.p_tx) > blockchain.size())
|
||||
if (currency::get_tx_max_unlock_time(*oi.p_tx) > blockchain.size())
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
|
@ -1445,14 +1504,14 @@ bool construct_tx_to_key(const std::vector<test_event_entry>& events,
|
|||
if (!fill_tx_sources(sources, events, blk_head, from.get_keys(), spending_amount, nmix, check_for_spends, check_for_unlocktime, use_ref_by_id))
|
||||
return false;
|
||||
|
||||
int64_t change = get_sources_total_amount(sources);
|
||||
boost::multiprecision::int128_t change = get_sources_total_amount(sources);
|
||||
change -= spending_amount;
|
||||
if (change < 0)
|
||||
return false; // should never happen if fill_tx_sources succeded
|
||||
if (change == 0)
|
||||
return construct_tx(from.get_keys(), sources, destinations, extr, att, tx, sk, 0, mix_attr);
|
||||
std::vector<tx_destination_entry> local_dst = destinations;
|
||||
local_dst.push_back(tx_destination_entry(change, from.get_public_address()));
|
||||
local_dst.push_back(tx_destination_entry(change.convert_to<uint64_t>(), from.get_public_address()));
|
||||
return construct_tx(from.get_keys(), sources, local_dst, extr, att, tx, sk, 0, mix_attr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ struct offers_count_param
|
|||
size_t offers_count_raw;
|
||||
};
|
||||
|
||||
class test_chain_unit_enchanced : public test_chain_unit_base
|
||||
class test_chain_unit_enchanced : virtual public test_chain_unit_base
|
||||
{
|
||||
public:
|
||||
test_chain_unit_enchanced();
|
||||
|
|
@ -345,7 +345,7 @@ public:
|
|||
currency::wide_difficulty_type cumul_difficulty;
|
||||
std::vector<currency::transaction> m_transactions;
|
||||
crypto::hash ks_hash;
|
||||
};
|
||||
};
|
||||
|
||||
// amount vec_ind, tx_index, out index in tx
|
||||
typedef std::map<uint64_t, std::vector<std::tuple<size_t, size_t, size_t> > > outputs_index;
|
||||
|
|
@ -473,6 +473,7 @@ public:
|
|||
bool construct_genesis_block(currency::block& blk,
|
||||
const currency::account_base& miner_acc,
|
||||
uint64_t timestamp);
|
||||
|
||||
bool construct_block(const std::vector<test_event_entry>& events,
|
||||
currency::block& blk,
|
||||
const currency::block& blk_prev,
|
||||
|
|
@ -480,6 +481,14 @@ public:
|
|||
const std::list<currency::transaction>& tx_list = std::list<currency::transaction>(),
|
||||
const std::list<currency::account_base>& coin_stake_sources = std::list<currency::account_base>() //in case of PoS block
|
||||
);
|
||||
bool construct_block(int64_t manual_timestamp_adjustment,
|
||||
const std::vector<test_event_entry>& events,
|
||||
currency::block& blk,
|
||||
const currency::block& blk_prev,
|
||||
const currency::account_base& miner_acc,
|
||||
const std::list<currency::transaction>& tx_list = std::list<currency::transaction>(),
|
||||
const std::list<currency::account_base>& coin_stake_sources = std::list<currency::account_base>() //in case of PoS block
|
||||
);
|
||||
|
||||
|
||||
bool construct_block_manually(currency::block& blk, const currency::block& prev_block,
|
||||
|
|
@ -500,8 +509,17 @@ public:
|
|||
static const test_gentime_settings& get_test_gentime_settings() { return m_test_gentime_settings; }
|
||||
static void set_test_gentime_settings(const test_gentime_settings& s) { m_test_gentime_settings = s; }
|
||||
static void set_test_gentime_settings_default() { m_test_gentime_settings = m_test_gentime_settings_default; }
|
||||
void set_pos_to_low_timestamp(bool do_pos_to_low_timestamp) { m_do_pos_to_low_timestamp = do_pos_to_low_timestamp; }
|
||||
void set_ignore_last_pow_in_wallets(bool ignore_last_pow_in_wallets) { m_ignore_last_pow_in_wallets = ignore_last_pow_in_wallets; }
|
||||
void set_hardfork_height(uint64_t h);
|
||||
|
||||
private:
|
||||
bool m_do_pos_to_low_timestamp;
|
||||
bool m_ignore_last_pow_in_wallets;
|
||||
uint64_t m_last_found_timestamp;
|
||||
|
||||
uint64_t m_hardfork_after_heigh;
|
||||
|
||||
std::unordered_map<crypto::hash, block_info> m_blocks_info;
|
||||
static test_gentime_settings m_test_gentime_settings;
|
||||
static test_gentime_settings m_test_gentime_settings_default;
|
||||
|
|
@ -956,12 +974,30 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
VEC_EVENTS.push_back(BLK_NAME); \
|
||||
PRINT_EVENT_NO(VEC_EVENTS);
|
||||
|
||||
|
||||
|
||||
#define MAKE_NEXT_BLOCK_TIMESTAMP_ADJUSTMENT(ADJ, VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC) \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_block(ADJ, VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC); \
|
||||
VEC_EVENTS.push_back(BLK_NAME); \
|
||||
PRINT_EVENT_NO(VEC_EVENTS);
|
||||
|
||||
#define MAKE_NEXT_POS_BLOCK(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, MINERS_ACC_LIST) \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_block(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, std::list<currency::transaction>(), MINERS_ACC_LIST); \
|
||||
VEC_EVENTS.push_back(BLK_NAME); \
|
||||
PRINT_EVENT_NO(VEC_EVENTS)
|
||||
|
||||
#define MAKE_NEXT_POS_BLOCK_TX1(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, MINERS_ACC_LIST, TX_1) \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
{ \
|
||||
std::list<currency::transaction>tx_list; \
|
||||
tx_list.push_back(TX_1); \
|
||||
generator.construct_block(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, tx_list, MINERS_ACC_LIST); \
|
||||
} \
|
||||
VEC_EVENTS.push_back(BLK_NAME); \
|
||||
PRINT_EVENT_NO(VEC_EVENTS)
|
||||
|
||||
#define MAKE_NEXT_BLOCK_NO_ADD(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC) \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_block(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC); \
|
||||
|
|
@ -982,6 +1018,7 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
VEC_EVENTS.push_back(BLK_NAME); \
|
||||
PRINT_EVENT_NO(VEC_EVENTS)
|
||||
|
||||
|
||||
#define MAKE_NEXT_BLOCK_TX_LIST(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST) \
|
||||
currency::block BLK_NAME = AUTO_VAL_INIT(BLK_NAME); \
|
||||
generator.construct_block(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST); \
|
||||
|
|
|
|||
|
|
@ -936,6 +936,17 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(gen_uint_overflow_1);
|
||||
GENERATE_AND_PLAY(gen_uint_overflow_2);
|
||||
|
||||
|
||||
// Hardfok1 tests
|
||||
GENERATE_AND_PLAY(before_hard_fork_1_cumulative_difficulty);
|
||||
GENERATE_AND_PLAY(inthe_middle_hard_fork_1_cumulative_difficulty);
|
||||
GENERATE_AND_PLAY(after_hard_fork_1_cumulative_difficulty);
|
||||
GENERATE_AND_PLAY(hard_fork_1_locked_mining_test);
|
||||
GENERATE_AND_PLAY(hard_fork_1_bad_pos_source);
|
||||
GENERATE_AND_PLAY(hard_fork_1_unlock_time_2_in_normal_tx);
|
||||
GENERATE_AND_PLAY(hard_fork_1_unlock_time_2_in_coinbase);
|
||||
GENERATE_AND_PLAY(hard_fork_1_chain_switch_pow_only);
|
||||
GENERATE_AND_PLAY(hard_fork_1_checkpoint_basic_test);
|
||||
//GENERATE_AND_PLAY(gen_block_reward); */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,3 +33,7 @@
|
|||
#include "escrow_wallet_altchain_test.h"
|
||||
#include "misc_tests.h"
|
||||
#include "emission_test.h"
|
||||
#include "hard_fork_1_locked_pos_test.h"
|
||||
#include "hard_fork_1_consensus_test.h"
|
||||
#include "hard_fork_1_bad_pos_source.h"
|
||||
#include "hard_fork_1.h"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include "chaingen.h"
|
||||
#include "random_helper.h"
|
||||
|
||||
struct checkpoints_test : public test_chain_unit_enchanced
|
||||
struct checkpoints_test : virtual public test_chain_unit_enchanced
|
||||
{
|
||||
checkpoints_test();
|
||||
|
||||
|
|
|
|||
423
tests/core_tests/hard_fork_1.cpp
Normal file
423
tests/core_tests/hard_fork_1.cpp
Normal file
|
|
@ -0,0 +1,423 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "chaingen.h"
|
||||
#include "hard_fork_1.h"
|
||||
#include "pos_block_builder.h"
|
||||
//#include "tx_builder.h"
|
||||
//#include "random_helper.h"
|
||||
|
||||
using namespace currency;
|
||||
|
||||
hard_fork_1_base_test::hard_fork_1_base_test(size_t hardfork_height)
|
||||
: m_hardfork_height(hardfork_height)
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_base_test, configure_core);
|
||||
}
|
||||
|
||||
bool hard_fork_1_base_test::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE;
|
||||
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH;
|
||||
pc.hard_fork1_starts_after_height = m_hardfork_height;
|
||||
c.get_blockchain_storage().set_core_runtime_config(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
hard_fork_1_unlock_time_2_in_normal_tx::hard_fork_1_unlock_time_2_in_normal_tx()
|
||||
: hard_fork_1_base_test(12)
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_unlock_time_2_in_normal_tx, configure_core);
|
||||
}
|
||||
|
||||
bool hard_fork_1_unlock_time_2_in_normal_tx::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: make sure etc_tx_details_unlock_time2 can be used in normal (non-coinbase) tx
|
||||
// only after hardfork 1
|
||||
|
||||
bool r = false;
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(alice_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
generator.set_hardfork_height(m_hardfork_height);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
//
|
||||
// before hardfork 1
|
||||
//
|
||||
|
||||
std::vector<tx_source_entry> sources;
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_0r, miner_acc, alice_acc, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations), false, "");
|
||||
|
||||
// set unlock_time_2
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.resize(destinations.size());
|
||||
ut2.unlock_time_array[0] = 1; // not zero, unlocked from block 1
|
||||
extra.push_back(ut2);
|
||||
|
||||
transaction tx_0 = AUTO_VAL_INIT(tx_0);
|
||||
crypto::secret_key tx_sec_key;
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx_0, tx_sec_key, 0 /* unlock time 1 is zero and thus will not be set */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
// tx_0 should be accepted
|
||||
events.push_back(tx_0);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1_bad, blk_0r, miner_acc, tx_0);
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
DO_CALLBACK(events, "clear_tx_pool");
|
||||
|
||||
// make another tx with the same inputs and extra (tx_0 was rejected so inputs can be reused)
|
||||
transaction tx_0a = AUTO_VAL_INIT(tx_0a);
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx_0a, tx_sec_key, 0 /* unlock time 1 is zero and thus will not be set */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
// tx_0a should be accepted as well
|
||||
events.push_back(tx_0a);
|
||||
// make an alternative block with it and make sure it is rejected
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1_alt_bad, blk_0r, miner_acc, tx_0a); // this alt block should be rejected because of tx_0a
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
DO_CALLBACK(events, "clear_tx_pool");
|
||||
|
||||
|
||||
// okay, go for a hardfork
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc); // hardfork should happen here
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
|
||||
// make sure hardfork went okay
|
||||
CHECK_AND_ASSERT_MES(blk_2.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_3.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected");
|
||||
|
||||
|
||||
//
|
||||
// after hardfork 1
|
||||
//
|
||||
|
||||
sources.clear();
|
||||
destinations.clear();
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_3, miner_acc, alice_acc, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations), false, "");
|
||||
|
||||
// set unlock_time_2
|
||||
extra.clear();
|
||||
ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.resize(destinations.size());
|
||||
ut2.unlock_time_array[0] = 1; // not zero, unlocked from block 1
|
||||
extra.push_back(ut2);
|
||||
|
||||
transaction tx_1 = AUTO_VAL_INIT(tx_1);
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx_1, tx_sec_key, 0 /* unlock time 1 is zero and not set */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_1);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, tx_1); // block with tx_1 should be accepted
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(0));
|
||||
|
||||
// do the same check for alt block
|
||||
sources.clear();
|
||||
destinations.clear();
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_4, miner_acc, alice_acc, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations), false, "");
|
||||
extra.clear();
|
||||
ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.resize(destinations.size());
|
||||
ut2.unlock_time_array[0] = 1; // not zero, unlocked from block 1
|
||||
extra.push_back(ut2);
|
||||
|
||||
transaction tx_1a = AUTO_VAL_INIT(tx_1a);
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx_1a, tx_sec_key, 0 /* unlock time 1 is zero and not set */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_1a);
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_5a, blk_4, miner_acc, tx_1a); // alt block with tx_1a should be accepted
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1)); // tx is still in the pool
|
||||
|
||||
// switch chains
|
||||
MAKE_NEXT_BLOCK(events, blk_6a, blk_5a, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_7a, blk_6a, miner_acc);
|
||||
|
||||
// make sure switching really happened
|
||||
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_7a));
|
||||
|
||||
// and tx_1a has gone
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
hard_fork_1_unlock_time_2_in_coinbase::hard_fork_1_unlock_time_2_in_coinbase()
|
||||
: hard_fork_1_base_test(3)
|
||||
{
|
||||
}
|
||||
|
||||
bool hard_fork_1_unlock_time_2_in_coinbase::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: make sure etc_tx_details_unlock_time2 can be used in-coinbase txs
|
||||
// only after hardfork 1
|
||||
|
||||
bool r = false;
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
generator.set_hardfork_height(m_hardfork_height);
|
||||
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
|
||||
|
||||
// before hardfork 1
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc);
|
||||
events.pop_back(); // remove blk_1
|
||||
|
||||
// remove etc_tx_details_unlock_time entries from miner_tx
|
||||
blk_1.miner_tx.extra.erase(std::remove_if(blk_1.miner_tx.extra.begin(), blk_1.miner_tx.extra.end(), [](extra_v& extra_element) { return extra_element.type() == typeid(etc_tx_details_unlock_time); }), blk_1.miner_tx.extra.end());
|
||||
|
||||
// add etc_tx_details_unlock_time2 entry
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.resize(blk_1.miner_tx.vout.size());
|
||||
ut2.unlock_time_array[0] = get_block_height(blk_1) + CURRENCY_MINED_MONEY_UNLOCK_WINDOW;
|
||||
blk_1.miner_tx.extra.push_back(ut2);
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
// add blk_1 with modified miner tx
|
||||
events.push_back(blk_1);
|
||||
generator.add_block_info(blk_1, std::list<transaction>()); // add modified block info
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_1a, blk_0, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1a, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); // hardfork should happen here
|
||||
MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc);
|
||||
// make sure hardfork went okay
|
||||
CHECK_AND_ASSERT_MES(blk_3.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_4.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected");
|
||||
|
||||
|
||||
// after hardfork 1
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc);
|
||||
wide_difficulty_type diff = generator.get_block_difficulty(get_block_hash(blk_5)); // remember block difficulty for nonce searching after modification
|
||||
events.pop_back();
|
||||
|
||||
// remove etc_tx_details_unlock_time entries from miner_tx
|
||||
blk_5.miner_tx.extra.erase(std::remove_if(blk_5.miner_tx.extra.begin(), blk_5.miner_tx.extra.end(), [](extra_v& extra_element) { return extra_element.type() == typeid(etc_tx_details_unlock_time); }), blk_5.miner_tx.extra.end());
|
||||
|
||||
// add etc_tx_details_unlock_time2 entry
|
||||
ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.resize(blk_5.miner_tx.vout.size());
|
||||
ut2.unlock_time_array[0] = get_block_height(blk_5) + CURRENCY_MINED_MONEY_UNLOCK_WINDOW;
|
||||
blk_5.miner_tx.extra.push_back(ut2);
|
||||
miner::find_nonce_for_given_block(blk_5, diff, get_block_height(blk_5));
|
||||
|
||||
// add blk_5 with modified miner tx
|
||||
events.push_back(blk_5);
|
||||
generator.add_block_info(blk_5, std::list<transaction>()); // add modified block info
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_6, blk_5, miner_acc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
hard_fork_1_chain_switch_pow_only::hard_fork_1_chain_switch_pow_only()
|
||||
: hard_fork_1_base_test(13)
|
||||
{
|
||||
}
|
||||
|
||||
bool hard_fork_1_chain_switch_pow_only::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: make sure chain switches without PoS before and after hardfork
|
||||
|
||||
bool r = false;
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(alice_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
generator.set_hardfork_height(m_hardfork_height);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
//
|
||||
// before hardfork 1
|
||||
//
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_1a, blk_0r, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_2a, blk_1a, miner_acc);
|
||||
|
||||
// make sure switch happened
|
||||
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_2a));
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_3a, blk_2a, miner_acc); // hardfork should happen here
|
||||
MAKE_NEXT_BLOCK(events, blk_4a, blk_3a, miner_acc);
|
||||
// make sure hardfork went okay
|
||||
CHECK_AND_ASSERT_MES(blk_3a.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_4a.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected");
|
||||
|
||||
|
||||
//
|
||||
// after hardfork 1
|
||||
//
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_5a, blk_4a, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_5b, blk_4a, miner_acc); // alternative chain B
|
||||
// switch chains
|
||||
MAKE_NEXT_BLOCK(events, blk_6b, blk_5b, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_7b, blk_6b, miner_acc);
|
||||
|
||||
// make sure switch happened
|
||||
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_7b));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
hard_fork_1_checkpoint_basic_test::hard_fork_1_checkpoint_basic_test()
|
||||
: hard_fork_1_base_test(13)
|
||||
, checkpoints_test()
|
||||
{
|
||||
}
|
||||
|
||||
bool hard_fork_1_checkpoint_basic_test::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
bool r = false;
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(alice_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
generator.set_hardfork_height(m_hardfork_height);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
DO_CALLBACK_PARAMS(events, "set_checkpoint", params_checkpoint(CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2));
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
//
|
||||
// before hardfork 1
|
||||
//
|
||||
|
||||
std::vector<tx_source_entry> sources;
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_0r, miner_acc, alice_acc, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations), false, "");
|
||||
|
||||
// set unlock_time_2, should be rejected before hardfork 1
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.resize(destinations.size());
|
||||
ut2.unlock_time_array[0] = 1; // not zero, unlocked from block 1
|
||||
extra.push_back(ut2);
|
||||
transaction tx_0 = AUTO_VAL_INIT(tx_0);
|
||||
crypto::secret_key tx_sec_key;
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx_0, tx_sec_key, 0 /* unlock time 1 is zero and thus will not be set */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
// tx_0 should be accepted
|
||||
events.push_back(tx_0);
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1_bad, blk_0r, miner_acc, tx_0); // should be rejected because of tx_0
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
DO_CALLBACK(events, "clear_tx_pool");
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc); // <-- checkpoint
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); // <-- hard fork
|
||||
MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc);
|
||||
// make sure hardfork went okay
|
||||
CHECK_AND_ASSERT_MES(blk_3.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_4.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
hard_fork_1_pos_and_locked_coins::hard_fork_1_pos_and_locked_coins()
|
||||
: hard_fork_1_base_test(13) // hardfork height
|
||||
, m_unique_amount(TESTS_DEFAULT_FEE * 9)
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_pos_and_locked_coins, check_outputs_with_unique_amount);
|
||||
}
|
||||
|
||||
bool hard_fork_1_pos_and_locked_coins::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
bool r = false;
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(alice_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
generator.set_hardfork_height(m_hardfork_height);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", static_cast<size_t>(0));
|
||||
|
||||
// create few locked outputs in the blockchain with unique amount
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time ut = AUTO_VAL_INIT(ut);
|
||||
ut.v = 100; // locked until block 100
|
||||
extra.push_back(ut);
|
||||
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
destinations.push_back(tx_destination_entry(m_unique_amount, alice_acc.get_public_address()));
|
||||
|
||||
transaction tx_0 = AUTO_VAL_INIT(tx_0);
|
||||
r = construct_tx_to_key(events, tx_0, blk_0r, miner_acc, destinations, TESTS_DEFAULT_FEE, 0, 0, extra);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_0);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", static_cast<size_t>(5));
|
||||
|
||||
|
||||
block blk_0a;
|
||||
{
|
||||
crypto::hash prev_id = get_block_hash(blk_0);
|
||||
size_t height = get_block_height(blk_0) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
const transaction& stake = blk_0.miner_tx;
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount = stake.vout[stake_output_idx].amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(miner_acc.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(stake.vout[stake_output_idx].target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, blk_0r.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), miner_acc.get_public_address());
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, miner_acc);
|
||||
blk_0a = pb.m_block;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hard_fork_1_pos_and_locked_coins::check_outputs_with_unique_amount(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
size_t expected_outputs_count = 0;
|
||||
const std::string& params = boost::get<callback_entry>(events[ev_index]).callback_params;
|
||||
CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(params, expected_outputs_count), false, "hex_to_pod failed, params = " << params);
|
||||
|
||||
std::list<crypto::public_key> pub_keys;
|
||||
bool r = c.get_outs(m_unique_amount, pub_keys);
|
||||
|
||||
CHECK_AND_ASSERT_MES(r && pub_keys.size() == expected_outputs_count, false, "amount " << print_money_brief(m_unique_amount) << ": " << pub_keys.size() << " != " << expected_outputs_count);
|
||||
|
||||
return true;
|
||||
}
|
||||
50
tests/core_tests/hard_fork_1.h
Normal file
50
tests/core_tests/hard_fork_1.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
|
||||
#include "chaingen.h"
|
||||
//#include "wallet_tests_basic.h"
|
||||
#include "checkpoints_tests.h"
|
||||
|
||||
struct hard_fork_1_base_test : virtual public test_chain_unit_enchanced
|
||||
{
|
||||
hard_fork_1_base_test(size_t hardfork_height);
|
||||
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
size_t m_hardfork_height;
|
||||
};
|
||||
|
||||
struct hard_fork_1_unlock_time_2_in_normal_tx : public hard_fork_1_base_test
|
||||
{
|
||||
hard_fork_1_unlock_time_2_in_normal_tx();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct hard_fork_1_unlock_time_2_in_coinbase : public hard_fork_1_base_test
|
||||
{
|
||||
hard_fork_1_unlock_time_2_in_coinbase();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct hard_fork_1_chain_switch_pow_only : public hard_fork_1_base_test
|
||||
{
|
||||
hard_fork_1_chain_switch_pow_only();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct hard_fork_1_checkpoint_basic_test : public hard_fork_1_base_test, public checkpoints_test
|
||||
{
|
||||
hard_fork_1_checkpoint_basic_test();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct hard_fork_1_pos_and_locked_coins : public hard_fork_1_base_test
|
||||
{
|
||||
hard_fork_1_pos_and_locked_coins();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
|
||||
bool check_outputs_with_unique_amount(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
uint64_t m_unique_amount;
|
||||
};
|
||||
93
tests/core_tests/hard_fork_1_bad_pos_source.cpp
Normal file
93
tests/core_tests/hard_fork_1_bad_pos_source.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "chaingen.h"
|
||||
#include "pos_validation.h"
|
||||
#include "tx_builder.h"
|
||||
#include "hard_fork_1_bad_pos_source.h"
|
||||
#include "random_helper.h"
|
||||
|
||||
using namespace epee;
|
||||
using namespace crypto;
|
||||
using namespace currency;
|
||||
|
||||
hard_fork_1_bad_pos_source::hard_fork_1_bad_pos_source()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_bad_pos_source, c1);
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_bad_pos_source, configure_core);
|
||||
}
|
||||
|
||||
bool hard_fork_1_bad_pos_source::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
random_state_test_restorer::reset_random();
|
||||
|
||||
GENERATE_ACCOUNT(preminer_acc);
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(pos_miner_acc_before_pow);
|
||||
GENERATE_ACCOUNT(pos_miner_acc_after_pow);
|
||||
m_accounts.push_back(miner_acc);
|
||||
m_accounts.push_back(pos_miner_acc_before_pow);
|
||||
m_accounts.push_back(pos_miner_acc_after_pow);
|
||||
std::list<account_base> miner_acc_lst(1, miner_acc);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, 1564434616);
|
||||
generator.set_hardfork_height(get_hardfork_height());
|
||||
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5);
|
||||
generator.set_pos_to_low_timestamp(true);
|
||||
MAKE_TX(events, tx_1, miner_acc, pos_miner_acc_before_pow, 1000000000000, blk_0r);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_pow_tx1, blk_0r, miner_acc, tx_1);
|
||||
MAKE_TX(events, tx_2, preminer_acc, pos_miner_acc_after_pow, 1000000000000, blk_pow_tx1);
|
||||
MAKE_NEXT_POS_BLOCK_TX1(events, blk_pos_tx2, blk_pow_tx1, miner_acc, miner_acc_lst, tx_2);
|
||||
|
||||
block last_block = blk_pos_tx2;
|
||||
for (size_t i = 0; i != CURRENCY_MINED_MONEY_UNLOCK_WINDOW; i++)
|
||||
{
|
||||
MAKE_NEXT_POS_BLOCK(events, next_blk_pos, last_block, miner_acc, miner_acc_lst);
|
||||
events.push_back(event_core_time(next_blk_pos.timestamp - 10));
|
||||
last_block = next_blk_pos;
|
||||
}
|
||||
|
||||
std::list<currency::account_base> accounts_before_pow;
|
||||
accounts_before_pow.push_back(pos_miner_acc_before_pow);
|
||||
//let's try to mint PoW block from account
|
||||
MAKE_NEXT_POS_BLOCK(events, next_blk_pos2, last_block, miner_acc, accounts_before_pow);
|
||||
|
||||
std::list<currency::account_base> accounts_after_pow;
|
||||
accounts_after_pow.push_back(pos_miner_acc_after_pow);
|
||||
//let's try to mint PoW block from account
|
||||
generator.set_ignore_last_pow_in_wallets(true);
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
MAKE_NEXT_POS_BLOCK(events, next_blk_pos3, next_blk_pos2, miner_acc, accounts_after_pow);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hard_fork_1_bad_pos_source::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; //four blocks
|
||||
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH; //four blocks
|
||||
pc.hard_fork1_starts_after_height = get_hardfork_height();
|
||||
|
||||
c.get_blockchain_storage().set_core_runtime_config(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hard_fork_1_bad_pos_source::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
|
||||
uint64_t h = c.get_blockchain_storage().get_current_blockchain_size();
|
||||
CHECK_AND_ASSERT_MES(h == 29, false, "locked pos block is not accepted");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t hard_fork_1_bad_pos_source::get_hardfork_height()const
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
18
tests/core_tests/hard_fork_1_bad_pos_source.h
Normal file
18
tests/core_tests/hard_fork_1_bad_pos_source.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "chaingen.h"
|
||||
#include "wallet_tests_basic.h"
|
||||
|
||||
|
||||
struct hard_fork_1_bad_pos_source : public wallet_test
|
||||
{
|
||||
hard_fork_1_bad_pos_source();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
virtual bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
virtual uint64_t get_hardfork_height()const;
|
||||
};
|
||||
119
tests/core_tests/hard_fork_1_consensus_test.cpp
Normal file
119
tests/core_tests/hard_fork_1_consensus_test.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "chaingen.h"
|
||||
#include "pos_validation.h"
|
||||
#include "tx_builder.h"
|
||||
#include "hard_fork_1_consensus_test.h"
|
||||
#include "random_helper.h"
|
||||
|
||||
using namespace epee;
|
||||
using namespace crypto;
|
||||
using namespace currency;
|
||||
|
||||
hard_fork_1_cumulative_difficulty_base::hard_fork_1_cumulative_difficulty_base()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_cumulative_difficulty_base, c1);
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_cumulative_difficulty_base, configure_core);
|
||||
}
|
||||
|
||||
bool hard_fork_1_cumulative_difficulty_base::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
random_state_test_restorer::reset_random();
|
||||
|
||||
GENERATE_ACCOUNT(preminer_acc);
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
m_accounts.push_back(miner_acc);
|
||||
std::list<account_base> miner_acc_lst(1, miner_acc);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, 1564434616);
|
||||
generator.set_hardfork_height(get_hardfork_height());
|
||||
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
|
||||
block last_block = blk_0r;
|
||||
for (size_t i = 0; i != 20; i++)
|
||||
{
|
||||
MAKE_NEXT_POS_BLOCK(events, next_blk_pos, last_block, miner_acc, miner_acc_lst);
|
||||
MAKE_NEXT_BLOCK(events, next_blk_pow, next_blk_pos, miner_acc);
|
||||
events.push_back(event_core_time(next_blk_pow.timestamp - 10));
|
||||
|
||||
last_block = next_blk_pow;
|
||||
}
|
||||
|
||||
generator.set_pos_to_low_timestamp(true);
|
||||
last_block = blk_0r;
|
||||
for (size_t i = 0; i != 20; i++)
|
||||
{
|
||||
MAKE_NEXT_POS_BLOCK(events, next_blk_pos, last_block, miner_acc, miner_acc_lst);
|
||||
MAKE_NEXT_BLOCK_TIMESTAMP_ADJUSTMENT(-14, events, next_blk_pow, next_blk_pos, miner_acc);
|
||||
last_block = next_blk_pow;
|
||||
}
|
||||
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hard_fork_1_cumulative_difficulty_base::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; //four blocks
|
||||
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH; //four blocks
|
||||
pc.hard_fork1_starts_after_height = get_hardfork_height();
|
||||
|
||||
c.get_blockchain_storage().set_core_runtime_config(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool before_hard_fork_1_cumulative_difficulty::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
|
||||
std::shared_ptr<block_extended_info> last_pow_block = c.get_blockchain_storage().get_last_block_of_type(false);
|
||||
std::shared_ptr<block_extended_info> last_pos_block = c.get_blockchain_storage().get_last_block_of_type(true);
|
||||
CHECK_AND_ASSERT_MES(last_pow_block->cumulative_diff_precise == 184, false, "Incorrect condition failed: last_pow_block->cumulative_diff_precise == 184");
|
||||
CHECK_AND_ASSERT_MES(last_pos_block->cumulative_diff_precise == 20, false, "Incorrect condition failed: last_pos_block->cumulative_diff_precise == 20");
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t before_hard_fork_1_cumulative_difficulty::get_hardfork_height()const
|
||||
{
|
||||
return 10000; //just big number which is obviously bigger then test blockchain
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool inthe_middle_hard_fork_1_cumulative_difficulty::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
|
||||
std::shared_ptr<block_extended_info> last_pow_block = c.get_blockchain_storage().get_last_block_of_type(false);
|
||||
std::shared_ptr<block_extended_info> last_pos_block = c.get_blockchain_storage().get_last_block_of_type(true);
|
||||
CHECK_AND_ASSERT_MES(last_pow_block->cumulative_diff_precise == 184, false, "Incorrect condition failed: last_pow_block->cumulative_diff_precise == 184");
|
||||
CHECK_AND_ASSERT_MES(last_pos_block->cumulative_diff_precise == 20, false, "Incorrect condition failed: last_pos_block->cumulative_diff_precise == 20");
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t inthe_middle_hard_fork_1_cumulative_difficulty::get_hardfork_height()const
|
||||
{
|
||||
return 15;
|
||||
}
|
||||
bool after_hard_fork_1_cumulative_difficulty::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
|
||||
std::shared_ptr<block_extended_info> last_pow_block = c.get_blockchain_storage().get_last_block_of_type(false);
|
||||
std::shared_ptr<block_extended_info> last_pos_block = c.get_blockchain_storage().get_last_block_of_type(true);
|
||||
CHECK_AND_ASSERT_MES(last_pow_block->cumulative_diff_precise == 172, false, "Incorrect condition failed: last_pow_block->cumulative_diff_precise == 184");
|
||||
CHECK_AND_ASSERT_MES(last_pos_block->cumulative_diff_precise == 199, false, "Incorrect condition failed: last_pos_block->cumulative_diff_precise == 20");
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t after_hard_fork_1_cumulative_difficulty::get_hardfork_height()const
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
|
||||
40
tests/core_tests/hard_fork_1_consensus_test.h
Normal file
40
tests/core_tests/hard_fork_1_consensus_test.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "chaingen.h"
|
||||
#include "wallet_tests_basic.h"
|
||||
|
||||
|
||||
struct hard_fork_1_cumulative_difficulty_base : public wallet_test
|
||||
{
|
||||
hard_fork_1_cumulative_difficulty_base();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
virtual bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)= 0;
|
||||
virtual uint64_t get_hardfork_height()const =0;
|
||||
};
|
||||
|
||||
// this test check if code still work same way as it supposed to work before hard fork point
|
||||
struct before_hard_fork_1_cumulative_difficulty : public hard_fork_1_cumulative_difficulty_base
|
||||
{
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
virtual uint64_t get_hardfork_height()const;
|
||||
};
|
||||
|
||||
// this test check if code still work same way as it supposed to work is split happened before hard fork point but finished after hard fork point
|
||||
struct inthe_middle_hard_fork_1_cumulative_difficulty : public hard_fork_1_cumulative_difficulty_base
|
||||
{
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
virtual uint64_t get_hardfork_height()const;
|
||||
};
|
||||
|
||||
// this test check if code follow the new consensus algorithm and prefer balanced branch of the blockchain tree
|
||||
struct after_hard_fork_1_cumulative_difficulty : public hard_fork_1_cumulative_difficulty_base
|
||||
{
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
virtual uint64_t get_hardfork_height()const;
|
||||
};
|
||||
|
||||
97
tests/core_tests/hard_fork_1_locked_pos_test.cpp
Normal file
97
tests/core_tests/hard_fork_1_locked_pos_test.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "chaingen.h"
|
||||
#include "pos_validation.h"
|
||||
#include "tx_builder.h"
|
||||
#include "hard_fork_1_locked_pos_test.h"
|
||||
#include "random_helper.h"
|
||||
|
||||
using namespace epee;
|
||||
using namespace crypto;
|
||||
using namespace currency;
|
||||
|
||||
hard_fork_1_locked_mining_test::hard_fork_1_locked_mining_test()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_locked_mining_test, c1);
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_locked_mining_test, configure_core);
|
||||
}
|
||||
|
||||
bool hard_fork_1_locked_mining_test::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
random_state_test_restorer::reset_random();
|
||||
|
||||
GENERATE_ACCOUNT(preminer_acc);
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(pos_miner_acc);
|
||||
m_accounts.push_back(miner_acc);
|
||||
m_accounts.push_back(pos_miner_acc);
|
||||
std::list<account_base> miner_acc_lst(1, miner_acc);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, 1564434616);
|
||||
generator.set_hardfork_height(get_hardfork_height());
|
||||
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
|
||||
|
||||
//construc tx that locks transaction for some period of time
|
||||
// make a couple of huge txs
|
||||
bool r = false;
|
||||
std::vector<extra_v> extra;
|
||||
|
||||
std::vector<tx_source_entry> sources_1;
|
||||
r = fill_tx_sources(sources_1, events, blk_0r, miner_acc.get_keys(), 2000000000000+TESTS_DEFAULT_FEE, 0);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
|
||||
std::vector<tx_destination_entry> destinations({ tx_destination_entry(2010000000000, pos_miner_acc.get_public_address()) });
|
||||
crypto::secret_key stub;
|
||||
transaction tx_1 = AUTO_VAL_INIT(tx_1);
|
||||
r = construct_tx(miner_acc.get_keys(), sources_1, destinations, extra, empty_attachment, tx_1, stub, get_block_height(blk_0r)+2000);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_1); // push it to the pool
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_0r_tx, blk_0r, miner_acc, tx_1);
|
||||
|
||||
block last_block = blk_0r_tx;
|
||||
for (size_t i = 0; i != CURRENCY_MINED_MONEY_UNLOCK_WINDOW; i++)
|
||||
{
|
||||
MAKE_NEXT_POS_BLOCK(events, next_blk_pos, last_block, miner_acc, miner_acc_lst);
|
||||
MAKE_NEXT_BLOCK(events, next_blk_pow, next_blk_pos, miner_acc);
|
||||
events.push_back(event_core_time(next_blk_pow.timestamp - 10));
|
||||
last_block = next_blk_pow;
|
||||
}
|
||||
|
||||
std::list<currency::account_base> accounts_2;
|
||||
accounts_2.push_back(pos_miner_acc);
|
||||
//let's try to mint PoS block from locked account
|
||||
MAKE_NEXT_POS_BLOCK(events, next_blk_pos, last_block, pos_miner_acc, accounts_2);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hard_fork_1_locked_mining_test::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; //four blocks
|
||||
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH; //four blocks
|
||||
pc.hard_fork1_starts_after_height = get_hardfork_height();
|
||||
|
||||
c.get_blockchain_storage().set_core_runtime_config(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hard_fork_1_locked_mining_test::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
|
||||
uint64_t h = c.get_blockchain_storage().get_current_blockchain_size();
|
||||
CHECK_AND_ASSERT_MES(h == 36, false, "locked pos block is not accepted");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t hard_fork_1_locked_mining_test::get_hardfork_height()const
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
18
tests/core_tests/hard_fork_1_locked_pos_test.h
Normal file
18
tests/core_tests/hard_fork_1_locked_pos_test.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "chaingen.h"
|
||||
#include "wallet_tests_basic.h"
|
||||
|
||||
|
||||
struct hard_fork_1_locked_mining_test : public wallet_test
|
||||
{
|
||||
hard_fork_1_locked_mining_test();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
virtual bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
virtual uint64_t get_hardfork_height()const;
|
||||
};
|
||||
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
#include "integer_overflow.h"
|
||||
|
||||
// TOTAL_MONEY_SUPPLY - total number coins to be generated
|
||||
#define TX_MAX_TRANSFER_AMOUNT ((uint64_t)(-1))
|
||||
|
||||
|
||||
using namespace epee;
|
||||
using namespace currency;
|
||||
|
||||
|
|
@ -83,7 +87,7 @@ bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const
|
|||
|
||||
// Problem 1. Miner tx output overflow
|
||||
MAKE_MINER_TX_MANUALLY(miner_tx_0, blk_0);
|
||||
split_miner_tx_outs(miner_tx_0, TOTAL_MONEY_SUPPLY);
|
||||
split_miner_tx_outs(miner_tx_0, TX_MAX_TRANSFER_AMOUNT);
|
||||
block blk_1;
|
||||
if (!generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx_0))
|
||||
return false;
|
||||
|
|
@ -91,23 +95,23 @@ bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const
|
|||
|
||||
// Problem 1. Miner tx outputs overflow
|
||||
MAKE_MINER_TX_MANUALLY(miner_tx_1, blk_1);
|
||||
split_miner_tx_outs(miner_tx_1, TOTAL_MONEY_SUPPLY);
|
||||
split_miner_tx_outs(miner_tx_1, TX_MAX_TRANSFER_AMOUNT);
|
||||
block blk_2;
|
||||
if (!generator.construct_block_manually(blk_2, blk_1, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx_1))
|
||||
return false;
|
||||
events.push_back(blk_2);
|
||||
|
||||
REWIND_BLOCKS(events, blk_2r, blk_2, miner_account);
|
||||
MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, TOTAL_MONEY_SUPPLY, blk_2r);
|
||||
MAKE_TX_LIST(events, txs_0, miner_account, bob_account, TOTAL_MONEY_SUPPLY, blk_2r);
|
||||
MAKE_TX_LIST_START(events, txs_0, miner_account, bob_account, TX_MAX_TRANSFER_AMOUNT, blk_2r);
|
||||
MAKE_TX_LIST(events, txs_0, miner_account, bob_account, TX_MAX_TRANSFER_AMOUNT, blk_2r);
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner_account, txs_0);
|
||||
REWIND_BLOCKS(events, blk_3r, blk_3, miner_account);
|
||||
|
||||
// Problem 2. total_fee overflow, block_reward overflow
|
||||
std::list<currency::transaction> txs_1;
|
||||
// Create txs with huge fee
|
||||
txs_1.push_back(construct_tx_with_fee(events, blk_3, bob_account, alice_account, MK_TEST_COINS(1), TOTAL_MONEY_SUPPLY - MK_TEST_COINS(1)));
|
||||
txs_1.push_back(construct_tx_with_fee(events, blk_3, bob_account, alice_account, MK_TEST_COINS(1), TOTAL_MONEY_SUPPLY - MK_TEST_COINS(1)));
|
||||
txs_1.push_back(construct_tx_with_fee(events, blk_3, bob_account, alice_account, MK_TEST_COINS(1), TX_MAX_TRANSFER_AMOUNT - MK_TEST_COINS(1)));
|
||||
txs_1.push_back(construct_tx_with_fee(events, blk_3, bob_account, alice_account, MK_TEST_COINS(1), TX_MAX_TRANSFER_AMOUNT - MK_TEST_COINS(1)));
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_4, blk_3r, miner_account, txs_1);
|
||||
|
||||
return true;
|
||||
|
|
@ -143,10 +147,10 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const
|
|||
|
||||
std::vector<currency::tx_destination_entry> destinations;
|
||||
const account_public_address& bob_addr = bob_account.get_keys().m_account_address;
|
||||
destinations.push_back(tx_destination_entry(TOTAL_MONEY_SUPPLY, bob_addr));
|
||||
destinations.push_back(tx_destination_entry(TOTAL_MONEY_SUPPLY - 1, bob_addr));
|
||||
destinations.push_back(tx_destination_entry(TX_MAX_TRANSFER_AMOUNT, bob_addr));
|
||||
destinations.push_back(tx_destination_entry(TX_MAX_TRANSFER_AMOUNT - 1, bob_addr));
|
||||
// sources.front().amount = destinations[0].amount + destinations[2].amount + destinations[3].amount + TESTS_DEFAULT_FEE
|
||||
destinations.push_back(tx_destination_entry(sources.front().amount - TOTAL_MONEY_SUPPLY - TOTAL_MONEY_SUPPLY + 1 - TESTS_DEFAULT_FEE, bob_addr));
|
||||
destinations.push_back(tx_destination_entry(sources.front().amount - TX_MAX_TRANSFER_AMOUNT - TX_MAX_TRANSFER_AMOUNT + 1 - TESTS_DEFAULT_FEE, bob_addr));
|
||||
|
||||
currency::transaction tx_1;
|
||||
std::vector<currency::attachment_v> attachments;
|
||||
|
|
@ -162,7 +166,7 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const
|
|||
for (size_t i = 0; i < tx_1.vout.size(); ++i)
|
||||
{
|
||||
auto& tx_1_out = tx_1.vout[i];
|
||||
if (tx_1_out.amount < TOTAL_MONEY_SUPPLY - 1)
|
||||
if (tx_1_out.amount < TX_MAX_TRANSFER_AMOUNT - 1)
|
||||
continue;
|
||||
|
||||
append_tx_source_entry(sources, tx_1, i);
|
||||
|
|
@ -171,7 +175,7 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const
|
|||
destinations.clear();
|
||||
currency::tx_destination_entry de;
|
||||
de.addr.push_back(alice_account.get_keys().m_account_address);
|
||||
de.amount = TOTAL_MONEY_SUPPLY - TESTS_DEFAULT_FEE;
|
||||
de.amount = TX_MAX_TRANSFER_AMOUNT - TESTS_DEFAULT_FEE;
|
||||
destinations.push_back(de);
|
||||
destinations.push_back(de);
|
||||
|
||||
|
|
|
|||
|
|
@ -1194,7 +1194,7 @@ bool multisig_and_unlock_time::generate(std::vector<test_event_entry>& events) c
|
|||
transaction tx_1 = AUTO_VAL_INIT(tx_1);
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, unlock_time, CURRENCY_TO_KEY_OUT_RELAXED, true);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
CHECK_AND_ASSERT_MES(get_tx_unlock_time(tx_1) == unlock_time, false, "Unlock time was not correctly set");
|
||||
CHECK_AND_ASSERT_MES(get_tx_max_unlock_time(tx_1) == unlock_time, false, "Unlock time was not correctly set");
|
||||
events.push_back(tx_1);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ void pos_block_builder::step1_init_header(size_t block_height, crypto::hash& pre
|
|||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(m_step == 0, "pos_block_builder: incorrect step sequence");
|
||||
m_block.minor_version = CURRENT_BLOCK_MINOR_VERSION;
|
||||
m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
m_block.major_version = BLOCK_MAJOR_VERSION_INITAL;
|
||||
m_block.timestamp = 0; // to be set at step 3
|
||||
m_block.prev_id = prev_block_hash;
|
||||
m_block.flags = CURRENCY_BLOCK_FLAG_POS_BLOCK;
|
||||
|
|
|
|||
|
|
@ -48,15 +48,15 @@ bool determine_tx_real_inputs(currency::core& c, const currency::transaction& tx
|
|||
, m_found(false)
|
||||
{}
|
||||
|
||||
bool handle_output(const currency::transaction& tx, const currency::tx_out& out)
|
||||
bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out& out, uint64_t out_i)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!m_found, false, "Internal error: m_found is true but the visitor is still being applied");
|
||||
auto it = std::find(tx.vout.begin(), tx.vout.end(), out);
|
||||
if (it == tx.vout.end())
|
||||
auto it = std::find(validated_tx.vout.begin(), validated_tx.vout.end(), out);
|
||||
if (it == validated_tx.vout.end())
|
||||
return false;
|
||||
size_t output_tx_index = it - tx.vout.begin();
|
||||
size_t output_tx_index = it - validated_tx.vout.begin();
|
||||
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(validated_tx);
|
||||
crypto::key_derivation derivation;
|
||||
bool r = generate_key_derivation(tx_pub_key, m_keys.m_view_secret_key, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_key_derivation failed");
|
||||
|
|
@ -96,7 +96,7 @@ bool determine_tx_real_inputs(currency::core& c, const currency::transaction& tx
|
|||
continue;
|
||||
}
|
||||
local_visitor vis(keys, in.k_image);
|
||||
bool r = c.get_blockchain_storage().scan_outputkeys_for_indexes(in, vis);
|
||||
bool r = c.get_blockchain_storage().scan_outputkeys_for_indexes(tx, in, vis);
|
||||
CHECK_AND_ASSERT_MES(r || vis.m_found, false, "scan_outputkeys_for_indexes failed");
|
||||
if (!vis.m_found)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ static const std::vector<currency::attachment_v> empty_attachment;
|
|||
bool create_block_template_manually(const currency::block& prev_block, boost::multiprecision::uint128_t already_generated_coins, const std::vector<const currency::transaction*>& txs, const currency::account_public_address& miner_addr, currency::block& result)
|
||||
{
|
||||
result.flags = 0;
|
||||
result.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
result.major_version = BLOCK_MAJOR_VERSION_INITAL;
|
||||
result.minor_version = CURRENT_BLOCK_MINOR_VERSION;
|
||||
result.nonce = 0;
|
||||
result.prev_id = get_block_hash(prev_block);
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ void run_emulation(const std::string& path)
|
|||
PERFORME_SIMULATION_FOR_FUNCTION(bbr_next_difficulty_configurable, BBR_DIFFICULTY_WINDOW, BBR_DIFFICULTY_CUT, BBR_DIFFICULTY_CUT);
|
||||
PERFORME_SIMULATION_FOR_FUNCTION(bbr_next_difficulty_configurable, 500, 60, 60);
|
||||
PERFORME_SIMULATION_FOR_FUNCTION(bbr_next_difficulty_configurable, 300, 60, 60);
|
||||
PERFORME_SIMULATION_FOR_FUNCTION_NO_WINDOW(currency::next_difficulty);
|
||||
PERFORME_SIMULATION_FOR_FUNCTION_NO_WINDOW(currency::next_difficulty_1);
|
||||
|
||||
print_blocks(result_blocks, path + "result.txt");
|
||||
LOG_PRINT_L0("Done");
|
||||
|
|
|
|||
104
tests/unit_tests/lmdb_tests.cpp
Normal file
104
tests/unit_tests/lmdb_tests.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#include <memory>
|
||||
#include "crypto/crypto.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "common/db_backend_lmdb.h"
|
||||
#include "common/db_abstract_accessor.h"
|
||||
|
||||
using namespace tools;
|
||||
|
||||
namespace lmdb_test
|
||||
{
|
||||
|
||||
TEST(lmdb, 2gb_test)
|
||||
{
|
||||
bool r = false;
|
||||
epee::shared_recursive_mutex rw_lock;
|
||||
|
||||
epee::log_space::log_singletone::enable_channels("lmdb");
|
||||
|
||||
static const uint64_t buffer_size = 64 * 1024; // 64 KB
|
||||
static const uint64_t db_total_size = static_cast<uint64_t>(2.1 * 1024 * 1024 * 1024); // 2.1 GB -- a bit more than 2GB to test 2GB boundary
|
||||
static const std::string db_file_path = "2gb_lmdb_test";
|
||||
|
||||
std::shared_ptr<db::lmdb_db_backend> lmdb_ptr = std::make_shared<db::lmdb_db_backend>();
|
||||
db::basic_db_accessor bdba(lmdb_ptr, rw_lock);
|
||||
|
||||
//
|
||||
// write data
|
||||
//
|
||||
|
||||
r = bdba.open(db_file_path, CACHE_SIZE);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
db::container_handle h;
|
||||
r = lmdb_ptr->open_container("c1", h);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->begin_transaction());
|
||||
ASSERT_TRUE(lmdb_ptr->clear(h));
|
||||
|
||||
std::vector<uint8_t> buffer;
|
||||
buffer.resize(buffer_size);
|
||||
crypto::generate_random_bytes(buffer_size, buffer.data());
|
||||
|
||||
uint64_t total_data = 0;
|
||||
for (uint64_t key = 0; key < db_total_size / buffer_size; ++key)
|
||||
{
|
||||
r = lmdb_ptr->set(h, (char*)&key, sizeof key, reinterpret_cast<const char*>(buffer.data()), buffer_size);
|
||||
ASSERT_TRUE(r);
|
||||
total_data += buffer_size;
|
||||
|
||||
if (key % 1024 == 0)
|
||||
{
|
||||
ASSERT_TRUE(lmdb_ptr->commit_transaction());
|
||||
ASSERT_TRUE(lmdb_ptr->resize_if_needed());
|
||||
ASSERT_TRUE(lmdb_ptr->begin_transaction());
|
||||
std::cout << total_data / 1024 / 1024 << " MB written to DB" << ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->commit_transaction());
|
||||
|
||||
r = bdba.close();
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
|
||||
//
|
||||
// read data and check
|
||||
//
|
||||
|
||||
r = bdba.open(db_file_path);
|
||||
ASSERT_TRUE(r);
|
||||
r = lmdb_ptr->open_container("c1", h);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->begin_transaction());
|
||||
|
||||
std::string out_buffer;
|
||||
total_data = 0;
|
||||
for (uint64_t key = 0; key < db_total_size / buffer_size; ++key)
|
||||
{
|
||||
r = lmdb_ptr->get(h, (char*)&key, sizeof key, out_buffer);
|
||||
ASSERT_TRUE(r);
|
||||
ASSERT_EQ(buffer_size, out_buffer.size());
|
||||
|
||||
ASSERT_TRUE(0 == memcmp(buffer.data(), out_buffer.c_str(), buffer_size));
|
||||
|
||||
total_data += buffer_size;
|
||||
if (key % 1024 == 0)
|
||||
std::cout << total_data / 1024 / 1024 << " MB read from DB" << ENDL;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->commit_transaction());
|
||||
|
||||
r = bdba.close();
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
boost::filesystem::remove_all(db_file_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,5 +16,6 @@ int main(int argc, char** argv)
|
|||
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
int ret = RUN_ALL_TESTS();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue