1
0
Fork 0
forked from lthn/blockchain

Merge branch 'develop' of github.com:hyle-team/zano into develop

This commit is contained in:
cryptozoidberg 2019-09-05 18:25:00 +02:00
commit 4d1acdd783
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
23 changed files with 1379 additions and 1347 deletions

View file

@ -3910,14 +3910,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& max_related_block_height, uint64_t& max_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& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) 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(tx, txin, output_keys, max_related_block_height, max_unlock_time))
if(!get_output_keys_for_input_with_checks(tx, txin, output_keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase))
{
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;
@ -3936,7 +3936,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 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 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& source_max_unlock_time_for_pos_coinbase) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
@ -3944,10 +3944,13 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction
{
std::vector<crypto::public_key >& m_results_collector;
const blockchain_storage& m_bch;
uint64_t& m_max_unlock_time;
uint64_t& m_source_max_unlock_time_for_pos_coinbase;
outputs_visitor(std::vector<crypto::public_key>& results_collector,
const blockchain_storage& bch,
uint64_t& max_unlock_time) :m_results_collector(results_collector), m_bch(bch), m_max_unlock_time(max_unlock_time)
uint64_t& source_max_unlock_time_for_pos_coinbase)
: m_results_collector(results_collector)
, m_bch(bch)
, m_source_max_unlock_time_for_pos_coinbase(source_max_unlock_time_for_pos_coinbase)
{}
bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out& out, uint64_t out_i)
{
@ -3956,8 +3959,9 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction
//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))
{
if (source_out_unlock_time > m_max_unlock_time)
m_max_unlock_time = source_out_unlock_time;
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(source_out_unlock_time), false, "source output #" << out_i << " is locked by time, not by height, which is not allowed for PoS coinbase");
if (source_out_unlock_time > m_source_max_unlock_time_for_pos_coinbase)
m_source_max_unlock_time_for_pos_coinbase = source_out_unlock_time;
}
else
{
@ -3968,7 +3972,6 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction
}
}
if(out.target.type() != typeid(txout_to_key))
{
LOG_PRINT_L0("Output have wrong type id, which=" << out.target.which());
@ -3980,7 +3983,7 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction
}
};
outputs_visitor vi(output_keys, *this, max_unlock_time);
outputs_visitor vi(output_keys, *this, source_max_unlock_time_for_pos_coinbase);
return scan_outputkeys_for_indexes(tx, txin, vi, max_related_block_height);
}
//------------------------------------------------------------------
@ -4438,13 +4441,13 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
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
bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_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)
if (major_unlock_time < source_max_unlock_time)
return false;
else
return true;
@ -4458,11 +4461,13 @@ bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transactio
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;
uint64_t amount_of_coins_in_unlock_in_range = 0; // amount of outputs locked for at least the same time
for (uint64_t i = 0; i != miner_tx.vout.size(); i++)
{
if (ut2.unlock_time_array[i] >= max_unlock_time)
uint64_t unlock_value = ut2.unlock_time_array[i];
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(unlock_value), false, "output #" << i << " is locked by time, not buy height, which is not allowed for PoS coinbase");
if (unlock_value >= source_max_unlock_time)
amount_of_coins_in_unlock_in_range += miner_tx.vout[i].amount;
}
@ -4549,22 +4554,22 @@ 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()
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);
uint64_t source_max_unlock_time_for_pos_coinbase = 0;
r = check_tx_input(b.miner_tx, 1, coinstake_in, id, b.miner_tx.signatures[0], max_related_block_height, source_max_unlock_time_for_pos_coinbase);
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 << ")");
CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "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);
r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, source_max_unlock_time_for_pos_coinbase);
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);
<< "source_max_unlock_time_for_pos_coinbase=" << source_max_unlock_time_for_pos_coinbase);
}
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 << ")");
CHECK_AND_ASSERT_MES(is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase), false, "Failed to validate coinbase in PoS block, condition failed: is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase)(" << source_max_unlock_time_for_pos_coinbase << ")");
}
}

View file

@ -267,14 +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& max_related_block_height, uint64_t& max_unlock_time)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& source_max_unlock_time_for_pos_coinbase)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 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 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& source_max_unlock_time_for_pos_coinbase) 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;
@ -312,7 +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_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_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,

View file

@ -88,7 +88,7 @@ namespace currency
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));
<< " is less or equal to o_i=" << o_i << " in tx: " << get_transaction_hash(tx));
return ut2.unlock_time_array[o_i];
}

View file

@ -85,6 +85,7 @@ namespace currency
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 bool should_unlock_value_be_treated_as_block_height(uint64_t v) { return v < CURRENCY_MAX_BLOCK_NUMBER; }
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); }
@ -106,4 +107,4 @@ namespace currency
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size);
blobdata tx_to_blob(const transaction& b);
bool tx_to_blob(const transaction& b, blobdata& b_blob);
}
}

View file

@ -39,8 +39,10 @@
"SYNCING": "Syncing wallet"
},
"CONTACTS": "Contacts",
"CONTACTS_TOOLTIP": "Contacts option available only with Master Password enabled",
"SETTINGS": "Settings",
"LOG_OUT": "Log out",
"LOG_OUT_TOOLTIP": "Logout option available only with Master Password enabled",
"SYNCHRONIZATION": {
"OFFLINE": "Offline",
"ONLINE": "Online",
@ -60,7 +62,9 @@
"CRITICAL_TOOLTIP": "<span class=\"critical-update\">Critical update available.</span><i class=\"icon\"></i><span>Update strongly recommended!</span>",
"TIME": "System time differs from network",
"TIME_TOOLTIP": "<span class=\"wrong-time\">Wrong system time!</span><br><span>Check and repair your system time.</span>"
}
},
"BLOCK": "Block",
"OF": "of"
},
"MAIN": {
"TITLE": "Create or open the wallet to start using Zano",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -5800,8 +5800,8 @@ __webpack_require__.r(__webpack_exports__);
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__(/*! c:\Projects\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
module.exports = __webpack_require__(/*! c:\Projects\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
__webpack_require__(/*! D:\Projects\Projects now\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
module.exports = __webpack_require__(/*! D:\Projects\Projects now\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
/***/ })

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -22,6 +22,7 @@ export class VariablesService {
public exp_med_ts = 0;
public net_time_delta_median = 0;
public height_app = 0;
public height_max = 0;
public last_build_available = '';
public last_build_displaymode = 0;
public daemon_state = 3;
@ -59,18 +60,23 @@ export class VariablesService {
getExpMedTsEvent = new BehaviorSubject(null);
getHeightAppEvent = new BehaviorSubject(null);
getHeightMaxEvent = new BehaviorSubject(null);
getRefreshStackingEvent = new BehaviorSubject(null);
getAliasChangedEvent = new BehaviorSubject(null);
public idle = new Idle()
.whenNotInteractive()
.do(() => {
this.ngZone.run(() => {
if (this.appPass == '') {
this.restartCountdown();
} else {
this.ngZone.run(() => {
this.idle.stop();
this.appPass = '';
this.appLogin = false;
this.router.navigate(['/login'], {queryParams: {type: 'auth'}});
});
}
});
public allContextMenu: ContextMenuComponent;
@ -94,6 +100,13 @@ export class VariablesService {
}
}
setHeightMax(height: number) {
if (height !== this.height_max) {
this.height_max = height;
this.getHeightMaxEvent.next(height);
}
}
setRefreshStacking(wallet_id: number) {
this.getHeightAppEvent.next(wallet_id);
}

View file

@ -172,6 +172,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.variablesService.last_build_available = data.last_build_available;
this.variablesService.last_build_displaymode = data.last_build_displaymode;
this.variablesService.setHeightApp(data.height);
this.variablesService.setHeightMax(data.max_net_seen_height);
this.ngZone.run(() => {
this.variablesService.daemon_state = data['daemon_network_state'];

View file

@ -38,24 +38,40 @@
</div>
</div>
<div class="sidebar-settings">
<div class="wrap-button" routerLinkActive="active">
<button (click)="contactsRoute()" [class.disabled]="variablesService.daemon_state !== 2" [disabled]="variablesService.daemon_state !== 2">
<div class="wrap-button" routerLinkActive="active" *ngIf="variablesService.appPass === ''; else contactsShow" tooltip="{{ 'SIDEBAR.CONTACTS_TOOLTIP' | translate }}" placement="top" tooltipClass="table-tooltip account-tooltip" [delay]="500">
<button (click)="contactsRoute()" [class.disabled]="variablesService.daemon_state !== 2 || variablesService.appPass === ''" [disabled]="variablesService.daemon_state !== 2 || variablesService.appPass === ''">
<i class="icon contacts"></i>
<span>{{ 'SIDEBAR.CONTACTS' | translate }}</span>
</button>
</div>
<ng-template #contactsShow>
<div class="wrap-button" routerLinkActive="active">
<button (click)="contactsRoute()">
<i class="icon contacts"></i>
<span>{{ 'SIDEBAR.CONTACTS' | translate }}</span>
</button>
</div>
</ng-template>
<div class="wrap-button" routerLinkActive="active">
<button [routerLink]="['/settings']">
<i class="icon settings"></i>
<span>{{ 'SIDEBAR.SETTINGS' | translate }}</span>
</button>
</div>
<div class="wrap-button">
<button (click)="logOut()">
<div class="wrap-button" *ngIf="variablesService.appPass === ''; else masterPass" tooltip="{{ 'SIDEBAR.LOG_OUT_TOOLTIP' | translate }}" placement="bottom" tooltipClass="table-tooltip account-tooltip" [delay]="500">
<button (click)="logOut()" [class.disabled]="variablesService.appPass === ''" [disabled]="variablesService.appPass === ''">
<i class="icon logout"></i>
<span>{{ 'SIDEBAR.LOG_OUT' | translate }}</span>
</button>
</div>
<ng-template #masterPass>
<div class="wrap-button">
<button (click)="logOut()">
<i class="icon logout"></i>
<span>{{ 'SIDEBAR.LOG_OUT' | translate }}</span>
</button>
</div>
</ng-template>
</div>
<div class="sidebar-synchronization-status">
<div class="status-container">
@ -87,6 +103,11 @@
<div class="loading" *ngIf="variablesService.daemon_state === 3"></div>
</div>
</div>
<ng-container *ngIf="variablesService.daemon_state === 1 || variablesService.daemon_state === 3">
<ng-container *ngIf="variablesService.daemon_state === 1">
<div class="progress-height">{{ 'SIDEBAR.BLOCK' | translate }} {{ variablesService.height_app }} {{ 'SIDEBAR.OF' | translate }} {{ variablesService.height_max }}</div>
</ng-container>
</ng-container>
<div class="update-container" *ngIf="(variablesService.daemon_state === 0 || variablesService.daemon_state === 2) && [2, 3, 4].indexOf(variablesService.last_build_displaymode) !== -1">
<ng-container *ngIf="variablesService.last_build_displaymode === 2">
<div class="update-text standard">
@ -118,3 +139,4 @@
<i class="icon time" tooltip="{{ 'SIDEBAR.UPDATE.TIME_TOOLTIP' | translate }}" placement="right-bottom" tooltipClass="update-tooltip important" [delay]="500"></i>
</div>
</div>

View file

@ -225,14 +225,17 @@
.sidebar-synchronization-status {
display: flex;
align-items: center;
justify-content: flex-start;
flex: 0 0 7rem;
flex-direction: column;
justify-content: center;
flex: 0 0 8rem;
font-size: 1.3rem;
.progress-height {
margin-top: 1rem;
}
.status-container {
position: relative;
flex-grow: 1;
text-align: left;
.offline, .online {
@ -280,6 +283,9 @@
line-height: 0.7rem;
padding-left: 0.7rem;
}
}
.loading {

View file

@ -39,8 +39,10 @@
"SYNCING": "Syncing wallet"
},
"CONTACTS": "Contacts",
"CONTACTS_TOOLTIP": "Contacts option available only with Master Password enabled",
"SETTINGS": "Settings",
"LOG_OUT": "Log out",
"LOG_OUT_TOOLTIP": "Logout option available only with Master Password enabled",
"SYNCHRONIZATION": {
"OFFLINE": "Offline",
"ONLINE": "Online",
@ -60,7 +62,9 @@
"CRITICAL_TOOLTIP": "<span class=\"critical-update\">Critical update available.</span><i class=\"icon\"></i><span>Update strongly recommended!</span>",
"TIME": "System time differs from network",
"TIME_TOOLTIP": "<span class=\"wrong-time\">Wrong system time!</span><br><span>Check and repair your system time.</span>"
}
},
"BLOCK": "Block",
"OF": "of"
},
"MAIN": {
"TITLE": "Create or open the wallet to start using Zano",

View file

@ -2,6 +2,6 @@
#define BUILD_COMMIT_ID "@VERSION@"
#define PROJECT_VERSION "1.0"
#define PROJECT_VERSION_BUILD_NO 53
#define PROJECT_VERSION_BUILD_NO 54
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -1124,13 +1124,13 @@ void append_vector_by_another_vector(U& dst, const V& src)
#define MAKE_TX_ATTACH(EVENTS, TX_VAR, FROM, TO, AMOUNT, HEAD, ATTACH) MAKE_TX_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, HEAD, ATTACH)
#define MAKE_MINER_TX_AND_KEY_MANUALLY(TX, BLK, KEY) \
transaction TX; \
if (!construct_miner_tx_manually(get_block_height(BLK) + 1, generator.get_already_generated_coins(BLK), \
miner_account.get_keys().m_account_address, TX, 0, KEY)) \
#define MAKE_MINER_TX_AND_KEY_MANUALLY(TX, PREV_BLOCK, P_KEYPAIR) \
transaction TX; \
if (!construct_miner_tx_manually(get_block_height(PREV_BLOCK) + 1, generator.get_already_generated_coins(PREV_BLOCK), \
miner_account.get_keys().m_account_address, TX, 0, P_KEYPAIR)) \
return false;
#define MAKE_MINER_TX_MANUALLY(TX, BLK) MAKE_MINER_TX_AND_KEY_MANUALLY(TX, BLK, 0)
#define MAKE_MINER_TX_MANUALLY(TX, PREV_BLOCK) MAKE_MINER_TX_AND_KEY_MANUALLY(TX, PREV_BLOCK, nullptr)
#define SET_EVENT_VISITOR_SETT(VEC_EVENTS, SETT, VAL) VEC_EVENTS.push_back(event_visitor_settings(SETT, VAL));

View file

@ -947,6 +947,7 @@ int main(int argc, char* argv[])
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(hard_fork_1_pos_locked_height_vs_time);
//GENERATE_AND_PLAY(gen_block_reward); */

View file

@ -10,6 +10,20 @@
using namespace currency;
template<typename extra_t>
void remove_unlock_v1_entries_from_extra(extra_t& extra)
{
extra.erase(std::remove_if(extra.begin(), extra.end(), [](extra_v& extra_element) { return extra_element.type() == typeid(etc_tx_details_unlock_time); }), extra.end());
}
template<typename extra_t>
void remove_unlock_v2_entries_from_extra(extra_t& extra)
{
extra.erase(std::remove_if(extra.begin(), extra.end(), [](extra_v& extra_element) { return extra_element.type() == typeid(etc_tx_details_unlock_time2); }), extra.end());
}
//------------------------------------------------------------------------------
hard_fork_1_base_test::hard_fork_1_base_test(size_t hardfork_height)
: m_hardfork_height(hardfork_height)
{
@ -28,7 +42,6 @@ bool hard_fork_1_base_test::configure_core(currency::core& c, size_t ev_index, c
//------------------------------------------------------------------------------
hard_fork_1_unlock_time_2_in_normal_tx::hard_fork_1_unlock_time_2_in_normal_tx()
: hard_fork_1_base_test(12)
{
@ -341,9 +354,27 @@ bool hard_fork_1_checkpoint_basic_test::generate(std::vector<test_event_entry>&
//------------------------------------------------------------------------------
struct unique_amount_params
{
unique_amount_params(uint64_t amount, uint64_t count) : amount(amount), count(count) {}
uint64_t amount;
uint64_t count;
};
// check that the given amount has only one non-zero gidit
// 3000 => true
// 11000 => false
bool does_amount_have_one_non_zero_digit(uint64_t amount)
{
size_t count = 0;
auto f = [&count](uint64_t){ ++count; };
decompose_amount_into_digits(amount, DEFAULT_DUST_THRESHOLD, f, f);
return count == 1;
}
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)
: hard_fork_1_base_test(25) // hardfork height
{
REGISTER_CALLBACK_METHOD(hard_fork_1_pos_and_locked_coins, check_outputs_with_unique_amount);
}
@ -353,14 +384,24 @@ bool hard_fork_1_pos_and_locked_coins::generate(std::vector<test_event_entry>& e
bool r = false;
GENERATE_ACCOUNT(miner_acc);
GENERATE_ACCOUNT(alice_acc);
GENERATE_ACCOUNT(bob_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));
const uint64_t unique_amount_alice = TESTS_DEFAULT_FEE * 9;
const uint64_t unique_amount_bob = TESTS_DEFAULT_FEE * 3;
CHECK_AND_ASSERT_MES(does_amount_have_one_non_zero_digit(unique_amount_alice), false, "does_amount_have_one_non_zero_digit failed for Alice");
CHECK_AND_ASSERT_MES(does_amount_have_one_non_zero_digit(unique_amount_bob), false, "does_amount_have_one_non_zero_digit failed for Bob");
// make sure no outputs have such unique amounts
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", unique_amount_params(unique_amount_alice, 0) );
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", unique_amount_params(unique_amount_bob, 0) );
// create few locked outputs in the blockchain with unique amount
// tx_0 : miner -> Alice
std::vector<extra_v> extra;
etc_tx_details_unlock_time ut = AUTO_VAL_INIT(ut);
ut.v = 100; // locked until block 100
@ -368,56 +409,317 @@ bool hard_fork_1_pos_and_locked_coins::generate(std::vector<test_event_entry>& e
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()));
destinations.push_back(tx_destination_entry(unique_amount_alice, 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);
// tx_1 : miner -> Bob
extra.clear();
uint64_t ut2_unlock_time = 100; // locked until block 100
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
destinations.clear();
for (size_t i = 0; i < 5; ++i)
{
destinations.push_back(tx_destination_entry(unique_amount_bob, bob_acc.get_public_address()));
ut2.unlock_time_array.push_back(ut2_unlock_time);
}
ut2.unlock_time_array.push_back(ut2_unlock_time);
extra.push_back(ut2);
transaction tx_1 = AUTO_VAL_INIT(tx_1);
r = construct_tx_to_key(events, tx_1, blk_0r, miner_acc, destinations, TESTS_DEFAULT_FEE, 0, 0, extra);
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
events.push_back(tx_1);
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 with tx_1 should be rejected because etc_tx_details_unlock_time2 is not allowed prior to hardfork 1
DO_CALLBACK(events, "mark_invalid_block");
MAKE_NEXT_BLOCK_TX1(events, blk_1b, blk_1, miner_acc, tx_1);
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
block blk_0a;
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", unique_amount_params(unique_amount_alice, 5) );
// make sure outputs with m_unique_amount are still locked
r = false;
try
{
crypto::hash prev_id = get_block_hash(blk_0);
size_t height = get_block_height(blk_0) + 1;
MAKE_TX(events, tx_1_bad, alice_acc, miner_acc, unique_amount_alice - TESTS_DEFAULT_FEE, blk_1r);
}
catch (std::runtime_error&)
{
r = true;
}
CHECK_AND_ASSERT_MES(r, false, "exception was not cought as expected");
// try to make a PoS block with locked stake before the hardfork
block blk_2b;
{
const block& prev_block = blk_1r;
const transaction& stake = tx_0;
crypto::hash prev_id = get_block_hash(prev_block);
size_t height = get_block_height(prev_block) + 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);
generate_key_image_helper(alice_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;
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, alice_acc);
blk_2b = pb.m_block;
}
// it should not be accepted, because stake coins is still locked
DO_CALLBACK(events, "mark_invalid_block");
events.push_back(blk_2b);
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc);
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");
// try to make a PoS block with locked stake after the hardfork
block blk_4b;
{
const block& prev_block = blk_3;
const transaction& stake = tx_0;
crypto::hash prev_id = get_block_hash(prev_block);
size_t height = get_block_height(prev_block) + 1;
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
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(alice_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.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
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, prev_block.timestamp);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, alice_acc);
blk_4b = pb.m_block;
}
// it should not be accepted, because stake coins is still locked
DO_CALLBACK(events, "mark_invalid_block");
events.push_back(blk_4b);
// blk_4 with tx_1 (etc_tx_details_unlock_time2) should be accepted after hardfork 1
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, tx_1);
block prev = blk_4;
for(size_t i = 0; i < CURRENCY_MINED_MONEY_UNLOCK_WINDOW; ++i)
{
MAKE_NEXT_POS_BLOCK(events, b, prev, miner_acc, std::list<currency::account_base>{miner_acc});
prev = b;
}
//REWIND_BLOCKS_N_WITH_TIME(events, blk_4r, blk_4, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
block blk_5;
{
const block& prev_block = prev;
const transaction& stake = tx_1;
crypto::hash prev_id = get_block_hash(prev_block);
size_t height = get_block_height(prev_block) + 1;
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
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(bob_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.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
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, prev_block.timestamp);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, bob_acc);
blk_5 = pb.m_block;
}
// it should not be accepted, because stake coins is still locked
DO_CALLBACK(events, "mark_invalid_block");
events.push_back(blk_5);
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;
unique_amount_params p(0, 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);
CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(params, p), false, "hex_to_pod failed, params = " << params);
std::list<crypto::public_key> pub_keys;
bool r = c.get_outs(m_unique_amount, pub_keys);
bool r = c.get_outs(p.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);
CHECK_AND_ASSERT_MES(r && pub_keys.size() == p.count, false, "amount " << print_money_brief(p.amount) << ": " << pub_keys.size() << " != " << p.count);
return true;
}
//------------------------------------------------------------------------------
hard_fork_1_pos_locked_height_vs_time::hard_fork_1_pos_locked_height_vs_time()
: hard_fork_1_base_test(11)
{
}
bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector<test_event_entry>& events) const
{
// Test idea: make sure it's impossible to use height-locked coins as PoS stake IF they are ts-locked (not height-locked) in some outputs
// (because it could possibly be used to unlock coins eralier)
bool r = false;
GENERATE_ACCOUNT(miner_acc);
GENERATE_ACCOUNT(alice_acc);
GENERATE_ACCOUNT(bob_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 + 1);
// create few locked outputs in the blockchain with unique amount
// tx_0 : miner -> Alice, miner -> Bob
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;
destinations.push_back(tx_destination_entry(MK_TEST_COINS(10), alice_acc.get_public_address()));
destinations.push_back(tx_destination_entry(MK_TEST_COINS(10), bob_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); // first block after hardfork
// make sure hardfork went okay
CHECK_AND_ASSERT_MES(blk_0r.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_1.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected");
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
block blk_s;
{
const block& prev_block = blk_1r;
const transaction& stake = tx_0;
const account_base& stakeholder = alice_acc;
crypto::hash prev_id = get_block_hash(prev_block);
size_t height = get_block_height(prev_block) + 1;
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
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(stakeholder.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.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
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, prev_block.timestamp);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
// set etc_tx_details_unlock_time2
remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock
std::vector<extra_v> extra;
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
ut2.unlock_time_array.push_back(height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // reward lock
for(size_t i = 0; i < pb.m_block.miner_tx.vout.size() - 1; ++i)
ut2.unlock_time_array.push_back(test_core_time::get_time() - 1000); // stake locked by time and it's already passed
extra.push_back(ut2);
pb.m_block.miner_tx.extra.push_back(ut2);
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, stakeholder);
blk_s = pb.m_block;
}
DO_CALLBACK(events, "mark_invalid_block"); // should not pass as using time-locking in outputs
events.push_back(blk_s);
block blk_good;
{
const block& prev_block = blk_1r;
const transaction& stake = tx_0;
const account_base& stakeholder = alice_acc;
crypto::hash prev_id = get_block_hash(prev_block);
size_t height = get_block_height(prev_block) + 1;
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
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(stakeholder.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.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
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, prev_block.timestamp);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
// set etc_tx_details_unlock_time2
remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock
std::vector<extra_v> extra;
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
ut2.unlock_time_array.push_back(height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // reward lock
for(size_t i = 0; i < pb.m_block.miner_tx.vout.size() - 1; ++i)
ut2.unlock_time_array.push_back(100); // stake locked by height 100
extra.push_back(ut2);
pb.m_block.miner_tx.extra.push_back(ut2);
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, stakeholder);
blk_good = pb.m_block;
}
// should be okay
events.push_back(blk_good);
return true;
}

View file

@ -45,6 +45,10 @@ struct hard_fork_1_pos_and_locked_coins : public hard_fork_1_base_test
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;
};
struct hard_fork_1_pos_locked_height_vs_time : public hard_fork_1_base_test
{
hard_fork_1_pos_locked_height_vs_time();
bool generate(std::vector<test_event_entry>& events) const;
};

View file

@ -169,11 +169,19 @@ IF %ERRORLEVEL% NEQ 0 (
@echo "---------------------------------------------------------------"
@echo "---------------------------------------------------------------"
@echo " UPLOADING TO SERVER ...."
set installer_file=%ACHIVE_NAME_PREFIX%%version%-installer.exe
set installer_path=%BUILDS_PATH%\builds\%installer_file%
@echo " SIGNING ...."
%ZANO_SIGN_CMD% %installer_path%
IF %ERRORLEVEL% NEQ 0 (
@echo "failed to sign installer"
goto error
)
@echo " UPLOADING TO SERVER ...."
pscp -load zano_build_server %installer_path% build.zano.org:/var/www/html/builds
IF %ERRORLEVEL% NEQ 0 (
@echo "FAILED TO UPLOAD EXE TO SERVER"