1
0
Fork 0
forked from lthn/blockchain

Merge branch 'develop' into develop_mobile

This commit is contained in:
cryptozoidberg 2020-10-12 16:27:55 +03:00
commit 524bc7f7fc
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
28 changed files with 17786 additions and 160 deletions

View file

@ -188,7 +188,7 @@ namespace tools
std::list<currency::block> blocks;
std::list<currency::transaction> txs;
bool r = source_core.get_blocks(i, 1, blocks, txs);
CHECK_AND_ASSERT_MES(r && blocks.size()==1, false, "Filed to get block " << i << " from core");
CHECK_AND_ASSERT_MES(r && blocks.size()==1, false, "Failed to get block " << i << " from core");
currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
crypto::hash tx_hash = AUTO_VAL_INIT(tx_hash);
for (auto& tx : txs)

View file

@ -65,6 +65,8 @@ namespace currency
bool store(const std::string& file_path);
void make_account_watch_only();
bool is_watch_only() const { return m_keys.spend_secret_key == currency::null_skey; }
bool is_auditable() const { return m_keys.account_address.is_auditable(); }
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int /*ver*/)

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__(/*! /home/user/zano_tmp/src/gui/qt-daemon/html_source/src/polyfills.ts */"./src/polyfills.ts");
module.exports = __webpack_require__(/*! /home/user/zano_tmp/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__(/*! /Users/mekasan/Projects/Projects/zano/src/gui/qt-daemon/html_source/src/polyfills.ts */"./src/polyfills.ts");
module.exports = __webpack_require__(/*! /Users/mekasan/Projects/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");
/***/ })

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 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

@ -32,6 +32,7 @@
"highcharts": "^7.0.3",
"idlejs": "^2.0.1",
"json-bignumber": "^1.0.1",
"lodash": "^4.17.20",
"ngx-contextmenu": "^5.1.1",
"ngx-papaparse": "^3.0.3",
"qrcode": "^1.3.0",

View file

@ -146,6 +146,9 @@ export class BackendService {
case 'ALREADY_EXISTS':
error_translate = 'ERRORS.FILE_EXIST';
break;
case 'FAILED':
BackendService.Debug(0, `Error: (${error}) was triggered by command: ${command}`);
break;
default:
error_translate = error;
}

View file

@ -1,14 +1,17 @@
import { Injectable, NgZone } from '@angular/core';
import { VariablesService } from './variables.service';
import { PaginationStore } from './pagination.store';
import * as _ from 'lodash';
@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class PaginationService {
constructor(
private variables: VariablesService,
private ngZone: NgZone
private ngZone: NgZone,
private paginationStore: PaginationStore
) { }
paginate(currentPage = 1) {
@ -44,4 +47,23 @@ export class PaginationService {
this.variables.currentWallet.pages = Array.from(Array((endPage + 1) - startPage).keys()).map(i => startPage + i);
});
}
getOffset() {
const mining = this.variables.currentWallet.exclude_mining_txs;
const currentPage = (this.variables.currentWallet.currentPage);
let offset = (currentPage * this.variables.count);
if (!mining) { return offset; }
const pages = this.paginationStore.value;
if (pages && pages.length) {
const max = _.maxBy(pages, 'page');
const isForward = this.paginationStore.isForward(pages, currentPage);
if (isForward) {
offset = max.offset;
} else {
const index = pages.findIndex(item => item.page === (currentPage));
offset = pages[index].offset;
}
}
return offset;
}
}

View file

@ -0,0 +1,41 @@
import {Injectable} from '@angular/core';
import {Observable, BehaviorSubject} from 'rxjs';
import {VariablesService} from './variables.service';
import * as _ from 'lodash';
export interface Pages {
page: number;
offset: number;
}
@Injectable({
providedIn: 'root'
})
export class PaginationStore {
constructor(
private variablesService: VariablesService
) {
}
private subject = new BehaviorSubject<Pages[]>(null);
pages$: Observable<Pages[]> = this.subject.asObservable();
isForward(pages, currentPage) {
const max = _.maxBy(pages, 'page');
return !max || max.page < currentPage || max.page === currentPage;
}
setPage(pageNumber: number, offset: number) {
const pages = this.subject.getValue();
const current = (this.variablesService.currentWallet.currentPage);
const isForward = this.isForward(pages, current);
let newPages: Pages[] = [];
if (pages && pages.length) {
newPages = pages.slice(0);
}
isForward ? newPages.push({page: pageNumber, offset}) : newPages.pop();
this.subject.next(newPages);
}
get value() {
return this.subject.value;
}
}

View file

@ -0,0 +1,14 @@
import {Injectable} from '@angular/core';
@Injectable()
export class UtilsService {
getMinWidthByScale(scale: number) {
switch (scale) {
case 7.5 : return 900;
case 10 : return 1200;
case 12.5 : return 1500;
case 15 : return 1800;
default : return 1200;
}
}
}

View file

@ -8,11 +8,13 @@ import {ContextMenuComponent} from 'ngx-contextmenu';
import {IntToMoneyPipe} from './_helpers/pipes/int-to-money.pipe';
import {BigNumber} from 'bignumber.js';
import {ModalService} from './_helpers/services/modal.service';
import {UtilsService} from './_helpers/services/utils.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
styleUrls: ['./app.component.scss'],
providers: [UtilsService]
})
export class AppComponent implements OnInit, OnDestroy {
@ -37,7 +39,8 @@ export class AppComponent implements OnInit, OnDestroy {
public variablesService: VariablesService,
private ngZone: NgZone,
private intToMoneyPipe: IntToMoneyPipe,
private modalService: ModalService
private modalService: ModalService,
private utilsService: UtilsService
) {
translate.addLangs(['en', 'fr', 'de', 'it', 'pt']);
translate.setDefaultLang('en');
@ -249,7 +252,7 @@ export class AppComponent implements OnInit, OnDestroy {
const wallet = this.variablesService.getWallet(wallet_id);
if (wallet) {
if(wallet.history.length > 40) {
wallet.history.splice(0, 1);
wallet.history.splice(40, 1);
}
this.ngZone.run(() => {
@ -553,6 +556,9 @@ export class AppComponent implements OnInit, OnDestroy {
this.renderer.addClass(document.body, 'theme-' + this.variablesService.defaultTheme);
}
if (this.variablesService.settings.hasOwnProperty('scale') && [7.5, 10, 12.5, 15].indexOf(this.variablesService.settings.scale) !== -1) {
const width = this.utilsService.getMinWidthByScale(this.variablesService.settings.scale);
const app = document.documentElement.querySelector('app-root');
this.renderer.setStyle(app, 'min-width', width + 'px');
this.renderer.setStyle(document.documentElement, 'font-size', this.variablesService.settings.scale + 'px');
}
} else {

View file

@ -32,9 +32,11 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgSelectModule } from '@ng-select/ng-select';
// SERVICES
import { BackendService } from './_helpers/services/backend.service';
import { ModalService } from './_helpers/services/modal.service';
import { PaginationStore } from './_helpers/services/pagination.store';
// SERVICES
import { MoneyToIntPipe } from './_helpers/pipes/money-to-int.pipe';
import { IntToMoneyPipe } from './_helpers/pipes/int-to-money.pipe';
import { HistoryTypeMessagesPipe } from './_helpers/pipes/history-type-messages.pipe';
@ -146,6 +148,7 @@ export function highchartsFactory() {
providers: [
BackendService,
ModalService,
PaginationStore,
MoneyToIntPipe,
IntToMoneyPipe,
{ provide: HIGHCHARTS_MODULES, useFactory: highchartsFactory }

View file

@ -71,9 +71,16 @@
}
&.received {
.status-transaction {
mask: url(../../assets/icons/receive.svg) no-repeat center;
background-color: transparent;
}
.status-transaction::after {
display: block;
content:'';
background:url("../../assets/icons/receive-green.svg") no-repeat center;
width: 13px;
height: 13px;
}
}
}

View file

@ -4,11 +4,13 @@ import {BackendService} from '../_helpers/services/backend.service';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {Location} from '@angular/common';
import { TranslateService } from '@ngx-translate/core';
import {UtilsService} from '../_helpers/services/utils.service';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss']
styleUrls: ['./settings.component.scss'],
providers: [UtilsService]
})
export class SettingsComponent implements OnInit {
@ -103,7 +105,8 @@ export class SettingsComponent implements OnInit {
private backend: BackendService,
private location: Location,
public translate: TranslateService,
private ngZone: NgZone
private ngZone: NgZone,
private utilsService: UtilsService
) {
this.theme = this.variablesService.settings.theme;
this.scale = this.variablesService.settings.scale;
@ -147,6 +150,9 @@ export class SettingsComponent implements OnInit {
setScale(scale) {
this.scale = scale;
this.variablesService.settings.scale = this.scale;
const width = this.utilsService.getMinWidthByScale(this.scale);
const app = document.documentElement.querySelector('app-root');
this.renderer.setStyle(app, 'min-width', width + 'px');
this.renderer.setStyle(document.documentElement, 'font-size', this.scale + 'px');
this.backend.storeAppData();
}

View file

@ -9,11 +9,12 @@ import { LOCKED_BALANCE_HELP_PAGE } from '../_shared/constants';
import icons from '../../assets/icons/icons.json';
import { PaginationService } from '../_helpers/services/pagination.service';
import { PaginationStore } from '../_helpers/services/pagination.store';
@Component({
selector: 'app-wallet',
templateUrl: './wallet.component.html',
styleUrls: ['./wallet.component.scss']
styleUrls: ['./wallet.component.scss'],
})
export class WalletComponent implements OnInit, OnDestroy {
subRouting1;
@ -96,7 +97,8 @@ export class WalletComponent implements OnInit, OnDestroy {
private ngZone: NgZone,
private translate: TranslateService,
private intToMoneyPipe: IntToMoneyPipe,
private pagination: PaginationService
private pagination: PaginationService,
private paginationStore: PaginationStore
) { }
ngOnInit() {
@ -207,12 +209,23 @@ export class WalletComponent implements OnInit, OnDestroy {
}
getRecentTransfers () {
const offset = this.pagination.getOffset();
const pages = this.paginationStore.value;
if (!pages) {
this.paginationStore.setPage(1, 40); // add back page for the first page
}
this.backend.getRecentTransfers(
this.walletID,
(this.variablesService.currentWallet.currentPage - 1) * this.variablesService.count,
offset,
this.variablesService.count, this.variablesService.currentWallet.exclude_mining_txs, (status, data) => {
const page = (this.variablesService.currentWallet.currentPage + 1);
this.paginationStore.setPage(page, data.last_item_index); // add back page for current page
if (data.history.length < this.variablesService.count) {
this.variablesService.currentWallet.totalPages = (page - 1); // stop paginate
}
if (status && data.total_history_items) {
this.variablesService.currentWallet.history.splice(0, this.variablesService.currentWallet.history.length);
this.variablesService.currentWallet.history.splice(0, this.variablesService.currentWallet.history.length);
this.ngZone.run(() => {
this.pagination.paginate(this.variablesService.currentWallet.currentPage);
if (data.history.length !== 0) {

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
<style type="text/css">
.st0{fill:#5cda9d;}
</style>
<path id="receive" class="st0" d="M64.2,309.6l58.2-210.4l48.1,71.6L178,182l12.7,4.7l81.9,30.4L64.2,309.6 M0,384l384-170.3
l-178.7-66.4L106.3,0L0,384L0,384z"/>
</svg>

After

Width:  |  Height:  |  Size: 573 B

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
<style type="text/css">
.st0{fill:#ff5252;}
</style>
<path id="send" class="st0" d="M319.8,74.4l-58.2,210.4l-48.1-71.6L206,202l-12.7-4.7l-81.9-30.4L319.8,74.4 M384,0L0,170.3
l178.7,66.4L277.7,384L384,0L384,0z"/>
</svg>

After

Width:  |  Height:  |  Size: 573 B

View file

@ -3,6 +3,7 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import 'lodash';
if (environment.production) {
enableProdMode();

View file

@ -2324,6 +2324,8 @@ void wallet2::assign_account(const currency::account_base& acc)
clear();
m_account = acc;
init_log_prefix();
if (m_account.is_watch_only())
m_watch_only = true;
}
//----------------------------------------------------------------------------------------------------
void wallet2::generate(const std::wstring& path, const std::string& pass, bool auditable_wallet)

View file

@ -863,6 +863,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(wallet_unconfirmed_tx_expiration);
GENERATE_AND_PLAY(wallet_unconfimed_tx_balance);
GENERATE_AND_PLAY(packing_outputs_on_pos_minting_wallet);
GENERATE_AND_PLAY(wallet_watch_only_and_chain_switch);
GENERATE_AND_PLAY(wallet_rpc_integrated_address);
GENERATE_AND_PLAY(wallet_rpc_integrated_address_transfer);

View file

@ -3441,5 +3441,103 @@ bool wallet_sending_to_integrated_address::c1(currency::core& c, size_t ev_index
miner_wlt_2->refresh();
CHECK_AND_ASSERT_MES(callback_succeded, false, "callback was not succeded (2)");
return true;
}
//------------------------------------------------------------------------------
wallet_watch_only_and_chain_switch::wallet_watch_only_and_chain_switch()
: m_split_point_block_height(0)
{
REGISTER_CALLBACK_METHOD(wallet_watch_only_and_chain_switch, c1);
}
bool wallet_watch_only_and_chain_switch::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.make_account_watch_only();
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); bob_acc.make_account_watch_only(); // Bob gonna have a tracking wallet
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// 0 10 11 12 13 23 15 <- blockchain height
// (0 )- (0r)- (1 )- (2 )- (3 )- (3r)- <- main chain
// | tx_0
// \ tx_1
// \
// \- (2a)- (3a)- (3ar)-
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc);
MAKE_TX_FEE(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(9), TESTS_DEFAULT_FEE, blk_2);
MAKE_TX_FEE(events, tx_1, miner_acc, bob_acc, MK_TEST_COINS(7), TESTS_DEFAULT_FEE, blk_2);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2, miner_acc, std::list<transaction>({ tx_0, tx_1 }));
REWIND_BLOCKS_N(events, blk_3r, blk_3, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
m_split_point_block_id = get_block_hash(blk_1);
m_split_point_block_height = get_block_height(blk_1);
DO_CALLBACK(events, "c1");
return true;
}
bool wallet_watch_only_and_chain_switch::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
// make sure Alice's wallet is watch-only but not a tracking wallet (not auditable)
CHECK_AND_ASSERT_MES(alice_wlt->is_watch_only() && !alice_wlt->is_auditable(), false, "incorrect type of Alice's wallet");
// make sure Bob's wallet is a tracking wallet
CHECK_AND_ASSERT_MES(bob_wlt->is_watch_only() && bob_wlt->is_auditable(), false, "incorrect type of Bob's wallet");
miner_wlt->refresh();
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
// check the balances
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(9), false, UINT64_MAX, MK_TEST_COINS(9), 0, 0, 0), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(7), false, UINT64_MAX, MK_TEST_COINS(7), 0, 0, 0), false, "");
// make a split
block out_block;
crypto::hash prev_id = m_split_point_block_id;
uint64_t current_height = m_split_point_block_height + 1;
for (size_t i = 0; i < CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3; ++i)
{
r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector<transaction>(), prev_id, current_height, &out_block);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed");
current_height++;
prev_id = get_block_hash(out_block);
}
// make sure the split has happened
uint64_t top_height = 0;
crypto::hash top_id;
c.get_blockchain_top(top_height, top_id);
CHECK_AND_ASSERT_MES(top_height == current_height - 1, false, "incorrect top_hegiht = " << top_height);
CHECK_AND_ASSERT_MES(top_id == prev_id, false, "incorrect top id = " << top_id);
// tx_0 and tx_1 should be moved back to the pool
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
// check the balances, should be zero in actual and few coins in awaiting
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(9), false, UINT64_MAX, 0, 0, MK_TEST_COINS(9), 0), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(7), false, UINT64_MAX, 0, 0, MK_TEST_COINS(7), 0), false, "");
return true;
}

View file

@ -265,4 +265,14 @@ struct wallet_sending_to_integrated_address : public wallet_test
wallet_sending_to_integrated_address();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
};
struct wallet_watch_only_and_chain_switch : public wallet_test
{
wallet_watch_only_and_chain_switch();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
mutable crypto::hash m_split_point_block_id;
mutable uint64_t m_split_point_block_height;
};