[FEATURE] Additional validation

This commit is contained in:
Daniel Kmak 2018-04-06 08:48:35 +02:00 committed by Bagaric
parent 40be251e7b
commit 37e81f7040
8 changed files with 149 additions and 85 deletions

View File

@ -95,7 +95,7 @@ interface SetWindowSizeFieldAction {
type: TypeKeys.WINDOW_SIZE_FIELD_SET;
payload: {
raw: string;
value: number | null;
value: Wei | null;
};
}

View File

@ -4,11 +4,17 @@ import { SagaIterator } from 'redux-saga';
import { TypeKeys } from 'actions/transaction/constants';
import { SetWindowSizeFieldAction } from 'actions/transaction';
import { SetCurrentWindowSizeAction } from '../../../actions/transaction/actionTypes/windowSize';
import { validNumber } from 'libs/validators';
import BN from 'bn.js';
export function* setCurrentWindowSize({ payload: raw }: SetCurrentWindowSizeAction): SagaIterator {
let value: number | null = null;
let value: BN | null = null;
value = parseInt(raw, 10);
if (!validNumber(parseInt(raw, 10))) {
yield call(setField, { raw, value: null });
}
value = new BN(raw);
yield call(setField, { value, raw });
}

View File

@ -3,7 +3,12 @@ import { select, fork, call, take, apply, put } from 'redux-saga/effects';
import { getOffline, getNodeLib } from 'selectors/config';
import {
ICurrentSchedulingToggle,
ICurrentWindowSize
ICurrentWindowSize,
ICurrentWindowStart,
ICurrentScheduleType,
ICurrentScheduleTimezone,
ICurrentScheduleTimestamp,
ICurrentTimeBounty
} from 'containers/Tabs/ScheduleTransaction/selectors';
import {
getSchedulingToggle,
@ -39,7 +44,7 @@ import { gasPriceToBase } from 'libs/units';
import BN from 'bn.js';
import { bufferToHex } from 'ethereumjs-util';
import RequestFactory from 'libs/scheduling/contracts/RequestFactory';
import { dateTimeToUnixTimestamp, windowSizeBlockToMin } from 'selectors/transaction/helpers';
import { windowSizeBlockToMin, calculateWindowStart } from 'selectors/transaction/helpers';
export function* shouldValidateParams(): SagaIterator {
while (true) {
@ -74,24 +79,25 @@ function* checkSchedulingParametersValidity() {
const currentTo = yield select(getCurrentTo);
const currentValue = yield select(getCurrentValue);
const callData = yield select(getData);
const scheduleType = yield select(getScheduleType);
const windowStart = yield select(getWindowStart);
const scheduleType: ICurrentScheduleType = yield select(getScheduleType);
const windowStart: ICurrentWindowStart = yield select(getWindowStart);
const windowSize: ICurrentWindowSize = yield select(getWindowSize);
const timeBounty = yield select(getTimeBounty);
const timeBounty: ICurrentTimeBounty = yield select(getTimeBounty);
const scheduleGasPrice = yield select(getScheduleGasPrice);
const scheduleGasLimit = yield select(getScheduleGasLimit);
const deposit = yield select(getScheduleDeposit);
const node = yield select(getNodeLib);
const wallet = yield select(getWalletInst);
const scheduleTimestamp = yield select(getScheduleTimestamp);
const scheduleTimezone = yield select(getScheduleTimezone);
const scheduleTimestamp: ICurrentScheduleTimestamp = yield select(getScheduleTimestamp);
const scheduleTimezone: ICurrentScheduleTimezone = yield select(getScheduleTimezone);
if (
!currentValue.value ||
!currentTo.value ||
!scheduleGasPrice.value ||
!wallet ||
!windowSize.value
!windowSize.value ||
!windowStart.value
) {
return;
}
@ -112,10 +118,13 @@ function* checkSchedulingParametersValidity() {
callData.value ? bufferToHex(callData.value) : '',
callGasLimit,
currentValue.value,
windowSizeBlockToMin(windowSize.value, scheduleType.value) || 0,
scheduleType.value === 'time'
? dateTimeToUnixTimestamp(scheduleTimestamp, scheduleTimezone.value)
: windowStart.value,
windowSizeBlockToMin(windowSize.value, scheduleType.value),
calculateWindowStart(
scheduleType.value,
scheduleTimestamp,
scheduleTimezone.value,
windowStart.value
),
scheduleGasPrice.value,
timeBounty.value,
deposit.value || new BN(0),

View File

@ -1,12 +1,8 @@
import { AppState } from 'reducers';
import moment from 'moment';
import 'moment-timezone';
export const isWindowSizeValid = (transactionFields: AppState['transaction']['fields']) => {
const { windowSize } = transactionFields;
return Boolean(windowSize && windowSize.value);
};
import { ICurrentScheduleTimestamp } from '.';
import BN from 'bn.js';
export const isWindowStartValid = (
transactionFields: AppState['transaction']['fields'],
@ -24,16 +20,29 @@ export const isScheduleTimestampValid = (transactionFields: AppState['transactio
return Boolean(scheduleTimestamp && scheduleTimestamp.value && scheduleTimestamp.value > now);
};
export const dateTimeToUnixTimestamp = (scheduleTimestamp: any, timezone: string) => {
export const dateTimeToUnixTimestamp = (
scheduleTimestamp: ICurrentScheduleTimestamp,
timezone: string
) => {
if (scheduleTimestamp.value) {
return moment.tz(scheduleTimestamp.raw, timezone).unix();
}
return scheduleTimestamp.value;
};
export const windowSizeBlockToMin = (numberInput: number | null, scheduleType: string | null) => {
export const windowSizeBlockToMin = (numberInput: BN | null, scheduleType: string | null) => {
if (numberInput && scheduleType && scheduleType === 'time') {
return numberInput * 60;
return numberInput.mul(new BN(60));
}
return numberInput;
};
export const calculateWindowStart = (
scheduleType: string | null,
scheduleTimestamp: any,
scheduleTimezone: string,
blockWindowStart: number | null
): number =>
(scheduleType === 'time'
? dateTimeToUnixTimestamp(scheduleTimestamp, scheduleTimezone)
: blockWindowStart) || 0;

View File

@ -3,10 +3,7 @@ import {
getCurrentTo,
getCurrentValue,
getFields,
getUnit,
getDataExists,
getData,
getValidGasCost,
getScheduleType,
getWindowStart,
getNonce,
@ -21,81 +18,71 @@ import {
getScheduleDeposit,
getScheduleTimestamp,
getScheduleTimezone,
IGetTransaction
IGetTransaction,
getTransaction,
isValidCurrentTimeBounty,
isWindowSizeValid
} from 'selectors/transaction';
import { Address, gasPriceToBase } from 'libs/units';
import {
EAC_SCHEDULING_CONFIG,
getScheduleData,
calcEACEndowment,
EAC_ADDRESSES
getSchedulerAddress
} from 'libs/scheduling';
import BN from 'bn.js';
import { makeTransaction } from 'libs/transaction';
import {
isFullTx,
isWindowSizeValid,
isWindowStartValid,
isScheduleTimestampValid,
dateTimeToUnixTimestamp,
windowSizeBlockToMin
windowSizeBlockToMin,
calculateWindowStart
} from 'selectors/transaction/helpers';
import EthTx from 'ethereumjs-tx';
import { getLatestBlock } from 'selectors/config';
export const getSchedulingTransaction = (state: AppState): IGetTransaction => {
const { isFullTransaction } = getTransaction(state);
const currentTo = getCurrentTo(state);
const currentValue = getCurrentValue(state);
const transactionFields = getFields(state);
const unit = getUnit(state);
const dataExists = getDataExists(state);
const callData = getData(state);
const validGasCost = getValidGasCost(state);
const scheduleType = getScheduleType(state);
const windowStart = getWindowStart(state);
const windowSize = getWindowSize(state);
const nonce = getNonce(state);
const gasPrice = getGasPrice(state);
const timeBounty = getTimeBounty(state);
const windowSizeValid = isWindowSizeValid(transactionFields);
const windowStartValid = isWindowStartValid(transactionFields, getLatestBlock(state));
const scheduleTimestamp = getScheduleTimestamp(state);
const scheduleTimestampValid = isScheduleTimestampValid(transactionFields);
const scheduleTimezone = getScheduleTimezone(state);
const scheduleGasPrice = getScheduleGasPrice(state);
const scheduleGasPriceValid = isValidScheduleGasPrice(state);
const scheduleGasLimit = getScheduleGasLimit(state);
const scheduleGasLimitValid = isValidScheduleGasLimit(state);
const depositValid = isValidScheduleDeposit(state);
const deposit = getScheduleDeposit(state);
const scheduleType = getScheduleType(state);
const endowment = calcEACEndowment(
scheduleGasLimit.value || EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK,
currentValue.value || new BN(0),
scheduleGasPrice.value || gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK),
scheduleGasLimit.value,
currentValue.value,
scheduleGasPrice.value,
timeBounty.value
);
const isFullTransaction =
isFullTx(state, transactionFields, currentTo, currentValue, dataExists, validGasCost, unit) &&
(windowStartValid || scheduleTimestampValid) &&
windowSizeValid &&
scheduleGasPriceValid &&
scheduleGasLimitValid &&
depositValid;
let transactionData = null;
if (isFullTransaction) {
const transactionFullAndValid = isFullTransaction && isSchedulingTransactionValid(state);
if (transactionFullAndValid) {
const deposit = getScheduleDeposit(state);
const scheduleTimestamp = getScheduleTimestamp(state);
const windowSize = getWindowSize(state);
const callData = getData(state);
const scheduleTimezone = getScheduleTimezone(state);
const windowStart = getWindowStart(state);
transactionData = getScheduleData(
currentTo.raw,
callData.raw,
scheduleGasLimit.value,
currentValue.value,
windowSizeBlockToMin(windowSize.value, scheduleType.value),
scheduleType.value === 'time'
? dateTimeToUnixTimestamp(scheduleTimestamp, scheduleTimezone.value)
: windowStart.value,
calculateWindowStart(
scheduleType.value,
scheduleTimestamp,
scheduleTimezone.value,
windowStart.value
),
scheduleGasPrice.value,
timeBounty.value,
deposit.value
@ -103,11 +90,7 @@ export const getSchedulingTransaction = (state: AppState): IGetTransaction => {
}
const transactionOptions = {
to: Address(
scheduleType.value === 'time'
? EAC_ADDRESSES.KOVAN.timestampScheduler
: EAC_ADDRESSES.KOVAN.blockScheduler
),
to: getSchedulerAddress(scheduleType.value),
data: transactionData,
gasLimit: EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT,
gasPrice: gasPrice.value,
@ -119,10 +102,30 @@ export const getSchedulingTransaction = (state: AppState): IGetTransaction => {
transactionOptions.nonce = new BN(nonce.raw);
}
const transaction: EthTx = makeTransaction(transactionOptions);
const schedulingTransaction: EthTx = makeTransaction(transactionOptions);
return {
transaction,
isFullTransaction
transaction: schedulingTransaction,
isFullTransaction: transactionFullAndValid
};
};
const isSchedulingTransactionValid = (state: AppState): boolean => {
const transactionFields = getFields(state);
const windowSizeValid = isWindowSizeValid(state);
const windowStartValid = isWindowStartValid(transactionFields, getLatestBlock(state));
const scheduleTimestampValid = isScheduleTimestampValid(transactionFields);
const scheduleGasPriceValid = isValidScheduleGasPrice(state);
const scheduleGasLimitValid = isValidScheduleGasLimit(state);
const depositValid = isValidScheduleDeposit(state);
const timeBountyValid = isValidCurrentTimeBounty(state);
return (
(windowStartValid || scheduleTimestampValid) &&
windowSizeValid &&
scheduleGasPriceValid &&
scheduleGasLimitValid &&
depositValid &&
timeBountyValid
);
};

View File

@ -1,15 +1,21 @@
import { AppState } from 'reducers';
import { getWindowSize } from './fields';
import BN from 'bn.js';
interface ICurrentWindowSize {
raw: string;
value: number | null;
value: BN | null;
}
const isValidCurrentWindowSize = (state: AppState) => {
const currentWindowSize = getWindowSize(state);
return currentWindowSize && currentWindowSize.value && currentWindowSize.value > 0;
return (
currentWindowSize &&
currentWindowSize.value &&
currentWindowSize.value.gt(new BN(0)) &&
currentWindowSize.value.bitLength() <= 256
);
};
const getCurrentWindowSize = (state: AppState): ICurrentWindowSize => getWindowSize(state);

View File

@ -1,6 +1,6 @@
import BN from 'bn.js';
import abi from 'ethereumjs-abi';
import { toWei, Units } from '../units';
import { toWei, Units, gasPriceToBase, Address } from '../units';
import { toBuffer } from 'ethereumjs-util';
import RequestFactory from './contracts/RequestFactory';
@ -47,8 +47,22 @@ export const calcEACFutureExecutionCost = (
.add(totalGas.mul(callGasPrice));
};
export const calcEACEndowment = (callGas: BN, callValue: BN, callGasPrice: BN, timeBounty: BN) =>
callValue.add(calcEACFutureExecutionCost(callGas, callGasPrice, timeBounty));
export const calcEACEndowment = (
callGas: BN | null,
callValue: BN | null,
callGasPrice: BN | null,
timeBounty: BN
) => {
callValue = callValue || new BN(0);
return callValue.add(
calcEACFutureExecutionCost(
callGas || EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK,
callGasPrice || gasPriceToBase(EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_PRICE_FALLBACK),
timeBounty
)
);
};
export const calcEACTotalCost = (
callGas: BN,
@ -68,7 +82,7 @@ export const getScheduleData = (
callData: string | Buffer = '',
callGas: BN | null,
callValue: BN | null,
windowSize: number | null,
windowSize: BN | null,
windowStart: any,
callGasPrice: BN | null,
timeBounty: BN | null,
@ -91,7 +105,8 @@ export const getScheduleData = (
!timeBounty ||
timeBounty.lt(new BN(0)) ||
callGasPrice.lt(new BN(0)) ||
windowSize < 0
windowSize.lt(new BN(0)) ||
windowSize.bitLength() > 256
) {
return;
}
@ -133,8 +148,8 @@ export const getValidateRequestParamsData = (
callData = '',
callGas: BN,
callValue: any,
windowSize: number,
windowStart: BN,
windowSize: BN | null,
windowStart: number,
gasPrice: BN,
timeBounty: BN,
requiredDeposit: BN,
@ -142,6 +157,8 @@ export const getValidateRequestParamsData = (
endowment: BN,
fromAddress: string
): string => {
windowSize = windowSize || new BN(0);
const temporalUnit = isTimestamp ? 2 : 1;
const freezePeriod = isTimestamp ? 3 * 60 : 10; // 3 minutes or 10 blocks
const reservedWindowSize = isTimestamp ? 5 * 60 : 16; // 5 minutes or 16 blocks
@ -172,3 +189,10 @@ export const getValidateRequestParamsData = (
export const getTXDetailsCheckURL = (txHash: string) => {
return `${EAC_SCHEDULING_CONFIG.DAPP_ADDRESS}/awaiting/scheduler/${txHash}`;
};
export const getSchedulerAddress = (scheduleType: string | null): Address =>
Address(
scheduleType === 'time'
? EAC_ADDRESSES.KOVAN.timestampScheduler
: EAC_ADDRESSES.KOVAN.blockScheduler
);

View File

@ -1,4 +1,4 @@
import { getTo, getValue, getScheduleGasPrice } from './fields';
import { getTo, getValue, getScheduleGasPrice, getWindowSize } from './fields';
import { getUnit, getTokenTo, getTokenValue } from './meta';
import { AppState } from 'reducers';
import { TokenValue, Wei, Address } from 'libs/units';
@ -64,7 +64,13 @@ const isValidScheduleDeposit = (state: AppState): boolean => {
return true;
}
return depositValue.gte(new BN('0'));
return depositValue.gte(new BN('0')) && depositValue.bitLength() <= 256;
};
const isWindowSizeValid = (state: AppState): boolean => {
const windowSize = getWindowSize(state);
return Boolean(windowSize && windowSize.value && windowSize.value.bitLength() <= 256);
};
function getCurrentToAddressMessage(state: AppState): AddressMessage | undefined {
@ -84,5 +90,6 @@ export {
isValidScheduleGasLimit,
isValidScheduleGasPrice,
isValidScheduleDeposit,
isWindowSizeValid,
getCurrentToAddressMessage
};