1
0
Fork 0
forked from lthn/blockchain

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

This commit is contained in:
crypro.zoidberg 2019-04-30 18:35:36 +02:00
commit fc7e8d0514
23 changed files with 394 additions and 171 deletions

View file

@ -512,7 +512,7 @@ namespace currency
return true;
// maximum age check - remove too old
uint64_t tx_age = get_core_time() - tx_entry.receive_time;
int64_t tx_age = get_core_time() - tx_entry.receive_time;
if ((tx_age > CURRENCY_MEMPOOL_TX_LIVETIME ))
{

View file

@ -258,13 +258,14 @@
"AMOUNT_REQUIRED": "Amount is required.",
"AMOUNT_ZERO": "Amount is zero.",
"FEE_REQUIRED": "Fee is required.",
"FEE_MINIMUM": "Minimum fee: {{fee}}"
"FEE_MINIMUM": "Minimum fee: {{fee}}",
"MAX_LENGTH": "Maximum comment length reached."
}
},
"HISTORY": {
"STATUS": "Status",
"STATUS_TOOLTIP": "Confirmations {{current}}/{{total}}",
"SEND": "Send",
"SEND": "Sent",
"RECEIVED": "Received",
"DATE": "Date",
"AMOUNT": "Amount",
@ -375,6 +376,7 @@
"DESC_MAXIMUM": "Maximum field length reached.",
"SELLER_REQUIRED": "Seller is required.",
"SELLER_NOT_VALID": "Seller not valid.",
"ALIAS_NOT_VALID": "Alias not valid.",
"AMOUNT_REQUIRED": "Amount is required.",
"YOUR_DEPOSIT_REQUIRED": "Your deposit is required.",
"YOUR_DEPOSIT_TOO_SMALL": "Your deposit should be equal or greater than amount.",
@ -473,7 +475,7 @@
"NO_MONEY": "Not enough money",
"NOT_ENOUGH_MONEY": "Insufficient funds in account",
"CORE_BUSY": "Internal error (core is busy)",
"DAEMON_BUSY": "Internal error: deamon is busy",
"DAEMON_BUSY": "Internal error: daemon is busy",
"NO_MONEY_REMOVE_OFFER": "There is no fee for deleting an offer, but in order to protect the network against flood transactions you need to have at least {{fee}} {{currency}} in your wallet",
"NOT_ENOUGH_OUTPUTS_TO_MIX": "Mix-in number is too big for current blockchain state. There are not enough unspent outputs to mix with",
"TRANSACTION_IS_TO_BIG": "Transaction exceeds network limit, send required amount with multiple transactions",

View file

@ -566,6 +566,13 @@ input[type='checkbox'].style-checkbox {
max-width: 18rem;
}
.comment-tooltip {
overflow: auto;
word-break: break-word;
max-width: 50rem;
max-height: 25rem;
}
.ngx-contextmenu {
.dropdown-menu {

View file

@ -99,24 +99,6 @@ app-send {
.form-send {
.input-block-address {
.address-dropdown {
@include themify($themes) {
background-color: themed(inputBackgroundColor);
color: themed(mainTextColor);
}
div:hover {
@include themify($themes) {
background-color: themed(selectHoverColor);
}
}
}
}
.send-select {
@include themify($themes) {
@ -449,3 +431,31 @@ app-staking {
}
}
}
.input-block-alias {
position: relative;
.alias-dropdown {
position: absolute;
top: 6.5rem;
max-height: 10rem;
overflow: auto;
width: 100%;
@include themify($themes) {
background-color: themed(inputBackgroundColor);
color: themed(mainTextColor);
}
div {
font-size: 1.4rem;
padding: 1rem;
&:hover {
@include themify($themes) {
background-color: themed(selectHoverColor);
}
}
}
}
}

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 one or more lines are too long

View file

@ -13,12 +13,16 @@
</div>
<div class="row">
<span class="cell label" [style.flex-basis]="sizes[0] + 'px'">{{ 'HISTORY.DETAILS.INPUTS' | translate }}</span>
<span class="cell value" [style.flex-basis]="sizes[1] + 'px'" tooltip="{{inputs.join('\n')}}" placement="top" tooltipClass="table-tooltip" [delay]="500" [showWhenNoOverflow]="false">{{inputs.join(', ')}}</span>
<span class="cell value" [style.flex-basis]="sizes[1] + 'px'" tooltip="{{inputs.join(', ')}}" placement="top" tooltipClass="table-tooltip table-tooltip-width" [delay]="500" [showWhenNoOverflow]="false">{{inputs.join(', ')}}</span>
<span class="cell label" [style.flex-basis]="sizes[2] + 'px'">{{ 'HISTORY.DETAILS.OUTPUTS' | translate }}</span>
<span class="cell value" [style.flex-basis]="sizes[3] + 'px'" tooltip="{{outputs.join('\n')}}" placement="top" tooltipClass="table-tooltip" [delay]="500" [showWhenNoOverflow]="false">{{outputs.join(', ')}}</span>
<span class="cell value" [style.flex-basis]="sizes[3] + 'px'" tooltip="{{outputs.join(', ')}}" placement="top" tooltipClass="table-tooltip table-tooltip-width" [delay]="500" [showWhenNoOverflow]="false">{{outputs.join(', ')}}</span>
</div>
<div class="row">
<span class="cell label" [style.flex-basis]="sizes[0] + 'px'">{{ 'HISTORY.DETAILS.COMMENT' | translate }}</span>
<span class="cell value" [style.flex-basis]="sizes[1] + sizes[2] + sizes[3] + 'px'">{{transaction.comment}}</span>
<span class="cell value" [style.flex-basis]="sizes[1] + sizes[2] + sizes[3] + 'px'"
tooltip="{{transaction.comment}}" placement="top" tooltipClass="table-tooltip comment-tooltip scrolled-content" [delay]="500" [showWhenNoOverflow]="false"
(contextmenu)="variablesService.onContextMenuOnlyCopy($event, transaction.comment)">
{{transaction.comment}}
</span>
</div>
</div>

View file

@ -41,3 +41,7 @@
}
}
}
.table-tooltip-width {
max-width: 20rem;
}

View file

@ -156,6 +156,9 @@ export class BackendService {
if (error.indexOf('FAIL:failed to save file') > -1) {
error_translate = 'ERRORS.FILE_NOT_SAVED';
}
if (error.indexOf('FAILED:failed to open binary wallet file for saving') > -1 && command === 'generate_wallet') {
error_translate = '';
}
if (error_translate !== '') {
this.modalService.prepareModal('error', error_translate);
}

View file

@ -413,13 +413,6 @@ export class AppComponent implements OnInit, OnDestroy {
comment: data.events[i].details.comment
};
this.variablesService.aliases = this.variablesService.aliases.concat(newAlias);
// this.variablesService.aliases = this.variablesService.aliases.sort((a, b) => {
// if (a.name.length > b.name.length) return 1;
// if (a.name.length < b.name.length) return -1;
// if (a.name > b.name) return 1;
// if (a.name < b.name) return -1;
// return 0;
// });
this.variablesService.changeAliases();
}
break;

View file

@ -15,7 +15,7 @@
</tr>
</thead>
<tbody>
<tr *ngFor="let item of variablesService.currentWallet.contracts" [routerLink]="'/wallet/' + walletId + '/purchase/' + item.contract_id">
<tr *ngFor="let item of sortedArrayContracts" [routerLink]="'/wallet/' + walletId + '/purchase/' + item.contract_id">
<td>
<div class="contract">
<i class="icon alert" *ngIf="!item.is_new"></i>

View file

@ -18,6 +18,24 @@ export class ContractsComponent implements OnInit, OnDestroy {
) {
}
public get sortedArrayContracts(): any[] {
return this.variablesService.currentWallet.contracts.sort((a, b) => {
if (a.is_new < b.is_new) {
return 1;
}
if (a.is_new > b.is_new) {
return -1;
}
if (a.timestamp < b.timestamp) {
return 1;
}
if (a.timestamp > b.timestamp) {
return -1;
}
return 0;
});
}
ngOnInit() {
this.parentRouting = this.route.parent.params.subscribe(params => {
if (params.hasOwnProperty('id')) {

View file

@ -28,9 +28,12 @@
</div>
<div class="input-blocks-row">
<div class="input-block">
<div class="input-block input-block-alias">
<label for="purchase-seller">{{ 'PURCHASE.SELLER' | translate }}</label>
<input type="text" id="purchase-seller" formControlName="seller" [readonly]="!newPurchase" appInputDisableSelection (contextmenu)="(!newPurchase) ? variablesService.onContextMenuOnlyCopy($event, purchaseForm.controls['seller'].value) : variablesService.onContextMenu($event)">
<input type="text" id="purchase-seller" formControlName="seller" [readonly]="!newPurchase" (mousedown)="addressMouseDown($event)" (contextmenu)="(!newPurchase) ? variablesService.onContextMenuOnlyCopy($event, purchaseForm.controls['seller'].value) : variablesService.onContextMenu($event)">
<div class="alias-dropdown scrolled-content" *ngIf="isOpen">
<div *ngFor="let item of localAliases" (click)="setAlias(item.name)">{{item.name}}</div>
</div>
<div class="error-block" *ngIf="purchaseForm.controls['seller'].invalid && (purchaseForm.controls['seller'].dirty || purchaseForm.controls['seller'].touched)">
<div *ngIf="purchaseForm.controls['seller'].errors['required']">
{{ 'PURCHASE.FORM_ERRORS.SELLER_REQUIRED' | translate }}
@ -41,6 +44,9 @@
<div *ngIf="purchaseForm.controls['seller'].errors['address_same']">
{{ 'PURCHASE.FORM_ERRORS.SELLER_SAME' | translate }}
</div>
<div *ngIf="purchaseForm.controls['seller'].errors['alias_not_valid']">
{{ 'PURCHASE.FORM_ERRORS.ALIAS_NOT_VALID' | translate }}
</div>
</div>
</div>

View file

@ -1,4 +1,4 @@
import {Component, OnInit, OnDestroy, NgZone} from '@angular/core';
import {Component, OnInit, OnDestroy, NgZone, HostListener} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {BackendService} from '../_helpers/services/backend.service';
@ -15,6 +15,10 @@ import {BigNumber} from 'bignumber.js';
styleUrls: ['./purchase.component.scss']
})
export class PurchaseComponent implements OnInit, OnDestroy {
isOpen = false;
localAliases = [];
currentWalletId;
newPurchase = false;
parentRouting;
@ -29,22 +33,50 @@ export class PurchaseComponent implements OnInit, OnDestroy {
}
return null;
}, (g: FormControl) => {
this.localAliases = [];
if (g.value) {
this.backend.validateAddress(g.value, (valid_status) => {
this.ngZone.run(() => {
if (valid_status === false) {
g.setErrors(Object.assign({'address_not_valid': true}, g.errors) );
} else {
if (g.hasError('address_not_valid')) {
delete g.errors['address_not_valid'];
if (Object.keys(g.errors).length === 0) {
g.setErrors(null);
if (g.value.indexOf('@') !== 0) {
this.isOpen = false;
this.backend.validateAddress(g.value, (valid_status) => {
this.ngZone.run(() => {
if (valid_status === false) {
g.setErrors(Object.assign({'address_not_valid': true}, g.errors));
} else {
if (g.hasError('address_not_valid')) {
delete g.errors['address_not_valid'];
if (Object.keys(g.errors).length === 0) {
g.setErrors(null);
}
}
}
}
});
});
});
return (g.hasError('address_not_valid')) ? {'address_not_valid': true} : null;
return (g.hasError('address_not_valid')) ? {'address_not_valid': true} : null;
} else {
this.isOpen = true;
this.localAliases = this.variablesService.aliases.filter((item) => {
return item.name.indexOf(g.value) > -1;
});
if (!(/^@?[a-z0-9\.\-]{6,25}$/.test(g.value))) {
g.setErrors(Object.assign({'alias_not_valid': true}, g.errors));
} else {
this.backend.getAliasByName(g.value.replace('@', ''), (alias_status) => {
this.ngZone.run(() => {
if (alias_status) {
if (g.hasError('alias_not_valid')) {
delete g.errors['alias_not_valid'];
if (Object.keys(g.errors).length === 0) {
g.setErrors(null);
}
}
} else {
g.setErrors(Object.assign({'alias_not_valid': true}, g.errors));
}
});
});
}
return (g.hasError('alias_not_valid')) ? {'alias_not_valid': true} : null;
}
}
return null;
}]),
@ -74,8 +106,7 @@ export class PurchaseComponent implements OnInit, OnDestroy {
private modalService: ModalService,
private ngZone: NgZone,
private location: Location,
private intToMoneyPipe: IntToMoneyPipe,
private translate: TranslateService
private intToMoneyPipe: IntToMoneyPipe
) {
}
@ -87,6 +118,23 @@ export class PurchaseComponent implements OnInit, OnDestroy {
}
}
addressMouseDown(e) {
if (e['button'] === 0 && this.purchaseForm.get('seller').value && this.purchaseForm.get('seller').value.indexOf('@') === 0) {
this.isOpen = true;
}
}
setAlias(alias) {
this.purchaseForm.get('seller').setValue(alias);
}
@HostListener('document:click', ['$event.target'])
public onClick(targetElement) {
if (targetElement.id !== 'purchase-seller' && this.isOpen) {
this.isOpen = false;
}
}
ngOnInit() {
this.parentRouting = this.route.parent.params.subscribe(params => {
this.currentWalletId = params['id'];
@ -158,13 +206,7 @@ export class PurchaseComponent implements OnInit, OnDestroy {
this.currentContract.is_new = true;
this.variablesService.currentWallet.recountNewContracts();
}
// if (!this.newPurchase && this.currentContract.is_a && (this.currentContract.state === 201 || this.currentContract.state === 2 || this.currentContract.state === 120 || this.currentContract.state === 130)) {
// if (this.currentContract.cancel_expiration_time === 0 && (this.currentContract.height === 0 || (this.variablesService.height_app - this.currentContract.height) < 10)) {
// this.purchaseForm.get('timeCancel').disable();
// } else {
// this.purchaseForm.get('timeCancel').enable();
// }
// }
});
}
@ -198,25 +240,54 @@ export class PurchaseComponent implements OnInit, OnDestroy {
createPurchase() {
if (this.purchaseForm.valid) {
if (this.purchaseForm.get('sameAmount').value) {
this.purchaseForm.get('sellerDeposit').setValue(this.purchaseForm.get('amount').value);
}
this.backend.createProposal(
this.variablesService.currentWallet.wallet_id,
this.purchaseForm.get('description').value,
this.purchaseForm.get('comment').value,
this.variablesService.currentWallet.address,
this.purchaseForm.get('seller').value,
this.purchaseForm.get('amount').value,
this.purchaseForm.get('yourDeposit').value,
this.purchaseForm.get('sellerDeposit').value,
this.purchaseForm.get('time').value,
this.purchaseForm.get('payment').value,
(create_status) => {
if (create_status) {
this.back();
}
if (this.purchaseForm.get('seller').value.indexOf('@') !== 0) {
if (this.purchaseForm.get('sameAmount').value) {
this.purchaseForm.get('sellerDeposit').setValue(this.purchaseForm.get('amount').value);
}
this.backend.createProposal(
this.variablesService.currentWallet.wallet_id,
this.purchaseForm.get('description').value,
this.purchaseForm.get('comment').value,
this.variablesService.currentWallet.address,
this.purchaseForm.get('seller').value,
this.purchaseForm.get('amount').value,
this.purchaseForm.get('yourDeposit').value,
this.purchaseForm.get('sellerDeposit').value,
this.purchaseForm.get('time').value,
this.purchaseForm.get('payment').value,
(create_status) => {
if (create_status) {
this.back();
}
});
} else {
this.backend.getAliasByName(this.purchaseForm.get('seller').value.replace('@', ''), (alias_status, alias_data) => {
this.ngZone.run(() => {
if (alias_status === false) {
this.ngZone.run(() => {
this.purchaseForm.get('seller').setErrors({'alias_not_valid': true});
});
} else {
this.backend.createProposal(
this.variablesService.currentWallet.wallet_id,
this.purchaseForm.get('description').value,
this.purchaseForm.get('comment').value,
this.variablesService.currentWallet.address,
alias_data.address,
this.purchaseForm.get('amount').value,
this.purchaseForm.get('yourDeposit').value,
this.purchaseForm.get('sellerDeposit').value,
this.purchaseForm.get('time').value,
this.purchaseForm.get('payment').value,
(create_status) => {
if (create_status) {
this.back();
}
});
}
});
});
}
}
}

View file

@ -1,11 +1,11 @@
<form class="form-send" [formGroup]="sendForm" (ngSubmit)="onSend()">
<div class="input-block input-block-address">
<div class="input-block input-block-alias">
<label for="send-address">{{ 'SEND.ADDRESS' | translate }}</label>
<input type="text" id="send-address" formControlName="address" (mousedown)="addressMouseDown($event)" (contextmenu)="variablesService.onContextMenu($event)">
<div class="address-dropdown scrolled-content" *ngIf="isOpen">
<div class="alias-dropdown scrolled-content" *ngIf="isOpen">
<div *ngFor="let item of localAliases" (click)="setAlias(item.name)">{{item.name}}</div>
</div>
@ -39,7 +39,10 @@
<div class="input-block">
<label for="send-comment">{{ 'SEND.COMMENT' | translate }}</label>
<input type="text" id="send-comment" formControlName="comment" (contextmenu)="variablesService.onContextMenu($event)">
<input type="text" id="send-comment" formControlName="comment" [maxLength]="variablesService.maxCommentLength" (contextmenu)="variablesService.onContextMenu($event)">
<div class="error-block" *ngIf="sendForm.get('comment').value && sendForm.get('comment').value.length >= variablesService.maxCommentLength">
{{ 'SEND.FORM_ERRORS.MAX_LENGTH' | translate }}
</div>
</div>
</div>

View file

@ -4,23 +4,6 @@
.form-send {
.input-block-address {
position: relative;
.address-dropdown {
position: absolute;
top: 6.5rem;
max-height: 10rem;
overflow: auto;
width: 100%;
div {
font-size: 1.4rem;
padding: 1rem;
}
}
}
.input-blocks-row {
display: flex;

View file

@ -73,7 +73,13 @@ export class SendComponent implements OnInit, OnDestroy {
}
return null;
}]),
comment: new FormControl(null),
comment: new FormControl('', [(g: FormControl) => {
if (g.value > this.variablesService.maxCommentLength) {
return {'maxLength': true};
} else {
return null;
}
}]),
mixin: new FormControl(0, Validators.required),
fee: new FormControl(this.variablesService.default_fee, [Validators.required, (g: FormControl) => {
if ((new BigNumber(g.value)).isLessThan(this.variablesService.default_fee)) {

View file

@ -258,13 +258,14 @@
"AMOUNT_REQUIRED": "Amount is required.",
"AMOUNT_ZERO": "Amount is zero.",
"FEE_REQUIRED": "Fee is required.",
"FEE_MINIMUM": "Minimum fee: {{fee}}"
"FEE_MINIMUM": "Minimum fee: {{fee}}",
"MAX_LENGTH": "Maximum comment length reached."
}
},
"HISTORY": {
"STATUS": "Status",
"STATUS_TOOLTIP": "Confirmations {{current}}/{{total}}",
"SEND": "Send",
"SEND": "Sent",
"RECEIVED": "Received",
"DATE": "Date",
"AMOUNT": "Amount",
@ -375,6 +376,7 @@
"DESC_MAXIMUM": "Maximum field length reached.",
"SELLER_REQUIRED": "Seller is required.",
"SELLER_NOT_VALID": "Seller not valid.",
"ALIAS_NOT_VALID": "Alias not valid.",
"AMOUNT_REQUIRED": "Amount is required.",
"YOUR_DEPOSIT_REQUIRED": "Your deposit is required.",
"YOUR_DEPOSIT_TOO_SMALL": "Your deposit should be equal or greater than amount.",
@ -473,7 +475,7 @@
"NO_MONEY": "Not enough money",
"NOT_ENOUGH_MONEY": "Insufficient funds in account",
"CORE_BUSY": "Internal error (core is busy)",
"DAEMON_BUSY": "Internal error: deamon is busy",
"DAEMON_BUSY": "Internal error: daemon is busy",
"NO_MONEY_REMOVE_OFFER": "There is no fee for deleting an offer, but in order to protect the network against flood transactions you need to have at least {{fee}} {{currency}} in your wallet",
"NOT_ENOUGH_OUTPUTS_TO_MIX": "Mix-in number is too big for current blockchain state. There are not enough unspent outputs to mix with",
"TRANSACTION_IS_TO_BIG": "Transaction exceeds network limit, send required amount with multiple transactions",

View file

@ -566,6 +566,13 @@ input[type='checkbox'].style-checkbox {
max-width: 18rem;
}
.comment-tooltip {
overflow: auto;
word-break: break-word;
max-width: 50rem;
max-height: 25rem;
}
.ngx-contextmenu {
.dropdown-menu {

View file

@ -99,24 +99,6 @@ app-send {
.form-send {
.input-block-address {
.address-dropdown {
@include themify($themes) {
background-color: themed(inputBackgroundColor);
color: themed(mainTextColor);
}
div:hover {
@include themify($themes) {
background-color: themed(selectHoverColor);
}
}
}
}
.send-select {
@include themify($themes) {
@ -449,3 +431,31 @@ app-staking {
}
}
}
.input-block-alias {
position: relative;
.alias-dropdown {
position: absolute;
top: 6.5rem;
max-height: 10rem;
overflow: auto;
width: 100%;
@include themify($themes) {
background-color: themed(inputBackgroundColor);
color: themed(mainTextColor);
}
div {
font-size: 1.4rem;
padding: 1rem;
&:hover {
@include themify($themes) {
background-color: themed(selectHoverColor);
}
}
}
}
}

View file

@ -1658,12 +1658,21 @@ void wallet2::detach_blockchain(uint64_t height)
break;
tr_hist_it = it; // note that tr_hist_it->height >= height
}
if (tr_hist_it != m_transfer_history.rend())
{
auto it_from = --tr_hist_it.base();
// before removing wti from m_transfer_history put it into m_unconfirmed_txs as txs from detached blocks are most likely moved into the pool
// before removing wti from m_transfer_history put it into m_unconfirmed_txs as txs from detached blocks are most likely be moved into the pool
for (auto it = it_from; it != m_transfer_history.end(); ++it)
{
// skip coinbase txs as they are not expected to go into the pool
if (is_coinbase(it->tx))
{
if (!it->is_mining)
WLT_LOG_ERROR("is_mining flag is not consistent for tx " << it ->tx_hash);
continue;
}
if (!m_unconfirmed_txs.insert(std::make_pair(it->tx_hash, *it)).second)
{
WLT_LOG_ERROR("can't move wti from transfer history to unronfirmed txs because such it is already here, tx hash: " << it->tx_hash);