Util/validation update (#4051)
* Fix code validation for null inputs * tests WIP * tests WIP * Update validation tests * Adjust block names, slice (PR comments)
This commit is contained in:
		
							parent
							
								
									9613145464
								
							
						
					
					
						commit
						20ad2e7d42
					
				@ -441,9 +441,7 @@ class DeployContract extends Component {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onCodeChange = (code) => {
 | 
			
		||||
    const { api } = this.context;
 | 
			
		||||
 | 
			
		||||
    this.setState(validateCode(code, api), this.estimateGas);
 | 
			
		||||
    this.setState(validateCode(code), this.estimateGas);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onDeployStart = () => {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,12 @@
 | 
			
		||||
 | 
			
		||||
import BigNumber from 'bignumber.js';
 | 
			
		||||
 | 
			
		||||
import util from '~/api/util';
 | 
			
		||||
import apiutil from '~/api/util';
 | 
			
		||||
 | 
			
		||||
import { NULL_ADDRESS } from './constants';
 | 
			
		||||
 | 
			
		||||
// TODO: Convert to FormattedMessages as soon as comfortable with the impact, i.e. errors
 | 
			
		||||
// not being concatted into strings in components, all supporting a non-string format
 | 
			
		||||
export const ERRORS = {
 | 
			
		||||
  invalidAddress: 'address is an invalid network address',
 | 
			
		||||
  invalidAmount: 'the supplied amount should be a valid positive number',
 | 
			
		||||
@ -42,9 +44,14 @@ export function validateAbi (abi) {
 | 
			
		||||
  try {
 | 
			
		||||
    abiParsed = JSON.parse(abi);
 | 
			
		||||
 | 
			
		||||
    if (!util.isArray(abiParsed)) {
 | 
			
		||||
    if (!apiutil.isArray(abiParsed)) {
 | 
			
		||||
      abiError = ERRORS.invalidAbi;
 | 
			
		||||
      return { abi, abiError, abiParsed };
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        abi,
 | 
			
		||||
        abiError,
 | 
			
		||||
        abiParsed
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Validate each elements of the Array
 | 
			
		||||
@ -54,8 +61,15 @@ export function validateAbi (abi) {
 | 
			
		||||
 | 
			
		||||
    if (invalidIndex !== -1) {
 | 
			
		||||
      const invalid = abiParsed[invalidIndex];
 | 
			
		||||
 | 
			
		||||
      // TODO: Needs seperate error when using FormattedMessage (no concats)
 | 
			
		||||
      abiError = `${ERRORS.invalidAbi} (#${invalidIndex}: ${invalid.name || invalid.type})`;
 | 
			
		||||
      return { abi, abiError, abiParsed };
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        abi,
 | 
			
		||||
        abiError,
 | 
			
		||||
        abiParsed
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    abi = JSON.stringify(abiParsed);
 | 
			
		||||
@ -76,7 +90,7 @@ function isValidAbiFunction (object) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ((object.type === 'function' && object.name) || object.type === 'constructor') &&
 | 
			
		||||
    (object.inputs && util.isArray(object.inputs));
 | 
			
		||||
    (object.inputs && apiutil.isArray(object.inputs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isAbiFallback (object) {
 | 
			
		||||
@ -94,7 +108,7 @@ function isValidAbiEvent (object) {
 | 
			
		||||
 | 
			
		||||
  return (object.type === 'event') &&
 | 
			
		||||
    (object.name) &&
 | 
			
		||||
    (object.inputs && util.isArray(object.inputs));
 | 
			
		||||
    (object.inputs && apiutil.isArray(object.inputs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function validateAddress (address) {
 | 
			
		||||
@ -102,10 +116,10 @@ export function validateAddress (address) {
 | 
			
		||||
 | 
			
		||||
  if (!address) {
 | 
			
		||||
    addressError = ERRORS.invalidAddress;
 | 
			
		||||
  } else if (!util.isAddressValid(address)) {
 | 
			
		||||
  } else if (!apiutil.isAddressValid(address)) {
 | 
			
		||||
    addressError = ERRORS.invalidAddress;
 | 
			
		||||
  } else {
 | 
			
		||||
    address = util.toChecksumAddress(address);
 | 
			
		||||
    address = apiutil.toChecksumAddress(address);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
@ -114,12 +128,12 @@ export function validateAddress (address) {
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function validateCode (code, api) {
 | 
			
		||||
export function validateCode (code) {
 | 
			
		||||
  let codeError = null;
 | 
			
		||||
 | 
			
		||||
  if (!code.length) {
 | 
			
		||||
  if (!code || !code.length) {
 | 
			
		||||
    codeError = ERRORS.invalidCode;
 | 
			
		||||
  } else if (!api.util.isHex(code)) {
 | 
			
		||||
  } else if (!apiutil.isHex(code)) {
 | 
			
		||||
    codeError = ERRORS.invalidCode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -130,7 +144,9 @@ export function validateCode (code, api) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function validateName (name) {
 | 
			
		||||
  const nameError = !name || name.trim().length < 2 ? ERRORS.invalidName : null;
 | 
			
		||||
  const nameError = !name || name.trim().length < 2
 | 
			
		||||
    ? ERRORS.invalidName
 | 
			
		||||
    : null;
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    name,
 | 
			
		||||
@ -162,6 +178,7 @@ export function validateUint (value) {
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const bn = new BigNumber(value);
 | 
			
		||||
 | 
			
		||||
    if (bn.lt(0)) {
 | 
			
		||||
      valueError = ERRORS.negativeNumber;
 | 
			
		||||
    } else if (!bn.isInteger()) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										303
									
								
								js/src/util/validation.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								js/src/util/validation.spec.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,303 @@
 | 
			
		||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import BigNumber from 'bignumber.js';
 | 
			
		||||
 | 
			
		||||
import { NULL_ADDRESS } from './constants';
 | 
			
		||||
import { ERRORS, isNullAddress, validateAbi, validateAddress, validateCode, validateName, validatePositiveNumber, validateUint } from './validation';
 | 
			
		||||
 | 
			
		||||
describe('util/validation', () => {
 | 
			
		||||
  describe('validateAbi', () => {
 | 
			
		||||
    it('passes on valid ABI', () => {
 | 
			
		||||
      const abi = '[{"type":"function","name":"test","inputs":[],"outputs":[]}]';
 | 
			
		||||
 | 
			
		||||
      expect(validateAbi(abi)).to.deep.equal({
 | 
			
		||||
        abi,
 | 
			
		||||
        abiError: null,
 | 
			
		||||
        abiParsed: [{
 | 
			
		||||
          type: 'function',
 | 
			
		||||
          name: 'test',
 | 
			
		||||
          inputs: [],
 | 
			
		||||
          outputs: []
 | 
			
		||||
        }]
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('passes on valid ABI & trims ABI', () => {
 | 
			
		||||
      const abi = '[ { "type" : "function" , "name" : "test" , "inputs" : [] , "outputs" : [] } ]';
 | 
			
		||||
 | 
			
		||||
      expect(validateAbi(abi)).to.deep.equal({
 | 
			
		||||
        abi: '[{"type":"function","name":"test","inputs":[],"outputs":[]}]',
 | 
			
		||||
        abiError: null,
 | 
			
		||||
        abiParsed: [{
 | 
			
		||||
          type: 'function',
 | 
			
		||||
          name: 'test',
 | 
			
		||||
          inputs: [],
 | 
			
		||||
          outputs: []
 | 
			
		||||
        }]
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on invalid JSON', () => {
 | 
			
		||||
      const abi = 'this is not json';
 | 
			
		||||
 | 
			
		||||
      expect(validateAbi(abi)).to.deep.equal({
 | 
			
		||||
        abi,
 | 
			
		||||
        abiError: ERRORS.invalidAbi,
 | 
			
		||||
        abiParsed: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on non-array JSON', () => {
 | 
			
		||||
      const abi = '{}';
 | 
			
		||||
 | 
			
		||||
      expect(validateAbi(abi)).to.deep.equal({
 | 
			
		||||
        abi,
 | 
			
		||||
        abiError: ERRORS.invalidAbi,
 | 
			
		||||
        abiParsed: {}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('fails with invalid event', () => {
 | 
			
		||||
      const abi = '[{ "type":"event" }]';
 | 
			
		||||
 | 
			
		||||
      expect(validateAbi(abi)).to.deep.equal({
 | 
			
		||||
        abi,
 | 
			
		||||
        abiError: `${ERRORS.invalidAbi} (#0: event)`,
 | 
			
		||||
        abiParsed: [{ type: 'event' }]
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('fails with invalid function', () => {
 | 
			
		||||
      const abi = '[{ "type":"function" }]';
 | 
			
		||||
 | 
			
		||||
      expect(validateAbi(abi)).to.deep.equal({
 | 
			
		||||
        abi,
 | 
			
		||||
        abiError: `${ERRORS.invalidAbi} (#0: function)`,
 | 
			
		||||
        abiParsed: [{ type: 'function' }]
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('fails with unknown type', () => {
 | 
			
		||||
      const abi = '[{ "type":"somethingElse" }]';
 | 
			
		||||
 | 
			
		||||
      expect(validateAbi(abi)).to.deep.equal({
 | 
			
		||||
        abi,
 | 
			
		||||
        abiError: `${ERRORS.invalidAbi} (#0: somethingElse)`,
 | 
			
		||||
        abiParsed: [{ type: 'somethingElse' }]
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('validateAddress', () => {
 | 
			
		||||
    it('validates address', () => {
 | 
			
		||||
      const address = '0x1234567890123456789012345678901234567890';
 | 
			
		||||
 | 
			
		||||
      expect(validateAddress(address)).to.deep.equal({
 | 
			
		||||
        address,
 | 
			
		||||
        addressError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('validates address and converts to checksum', () => {
 | 
			
		||||
      const address = '0x5A5eFF38DA95b0D58b6C616f2699168B480953C9';
 | 
			
		||||
 | 
			
		||||
      expect(validateAddress(address.toLowerCase())).to.deep.equal({
 | 
			
		||||
        address,
 | 
			
		||||
        addressError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on null addresses', () => {
 | 
			
		||||
      expect(validateAddress(null)).to.deep.equal({
 | 
			
		||||
        address: null,
 | 
			
		||||
        addressError: ERRORS.invalidAddress
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on invalid addresses', () => {
 | 
			
		||||
      const address = '0x12344567';
 | 
			
		||||
 | 
			
		||||
      expect(validateAddress(address)).to.deep.equal({
 | 
			
		||||
        address,
 | 
			
		||||
        addressError: ERRORS.invalidAddress
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('validateCode', () => {
 | 
			
		||||
    it('validates hex code', () => {
 | 
			
		||||
      expect(validateCode('0x123abc')).to.deep.equal({
 | 
			
		||||
        code: '0x123abc',
 | 
			
		||||
        codeError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('validates hex code (non-prefix)', () => {
 | 
			
		||||
      expect(validateCode('123abc')).to.deep.equal({
 | 
			
		||||
        code: '123abc',
 | 
			
		||||
        codeError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on invalid code', () => {
 | 
			
		||||
      expect(validateCode(null)).to.deep.equal({
 | 
			
		||||
        code: null,
 | 
			
		||||
        codeError: ERRORS.invalidCode
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on empty code', () => {
 | 
			
		||||
      expect(validateCode('')).to.deep.equal({
 | 
			
		||||
        code: '',
 | 
			
		||||
        codeError: ERRORS.invalidCode
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on non-hex code', () => {
 | 
			
		||||
      expect(validateCode('123hfg')).to.deep.equal({
 | 
			
		||||
        code: '123hfg',
 | 
			
		||||
        codeError: ERRORS.invalidCode
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('validateName', () => {
 | 
			
		||||
    it('validates names', () => {
 | 
			
		||||
      expect(validateName('Joe Bloggs')).to.deep.equal({
 | 
			
		||||
        name: 'Joe Bloggs',
 | 
			
		||||
        nameError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on null names', () => {
 | 
			
		||||
      expect(validateName(null)).to.deep.equal({
 | 
			
		||||
        name: null,
 | 
			
		||||
        nameError: ERRORS.invalidName
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on short names', () => {
 | 
			
		||||
      expect(validateName('  1  ')).to.deep.equal({
 | 
			
		||||
        name: '  1  ',
 | 
			
		||||
        nameError: ERRORS.invalidName
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('validatePositiveNumber', () => {
 | 
			
		||||
    it('validates numbers', () => {
 | 
			
		||||
      expect(validatePositiveNumber(123)).to.deep.equal({
 | 
			
		||||
        number: 123,
 | 
			
		||||
        numberError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('validates strings', () => {
 | 
			
		||||
      expect(validatePositiveNumber('123')).to.deep.equal({
 | 
			
		||||
        number: '123',
 | 
			
		||||
        numberError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('validates bignumbers', () => {
 | 
			
		||||
      expect(validatePositiveNumber(new BigNumber(123))).to.deep.equal({
 | 
			
		||||
        number: new BigNumber(123),
 | 
			
		||||
        numberError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on invalid numbers', () => {
 | 
			
		||||
      expect(validatePositiveNumber(null)).to.deep.equal({
 | 
			
		||||
        number: null,
 | 
			
		||||
        numberError: ERRORS.invalidAmount
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on negative numbers', () => {
 | 
			
		||||
      expect(validatePositiveNumber(-1)).to.deep.equal({
 | 
			
		||||
        number: -1,
 | 
			
		||||
        numberError: ERRORS.invalidAmount
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('validateUint', () => {
 | 
			
		||||
    it('validates numbers', () => {
 | 
			
		||||
      expect(validateUint(123)).to.deep.equal({
 | 
			
		||||
        value: 123,
 | 
			
		||||
        valueError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('validates strings', () => {
 | 
			
		||||
      expect(validateUint('123')).to.deep.equal({
 | 
			
		||||
        value: '123',
 | 
			
		||||
        valueError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('validates bignumbers', () => {
 | 
			
		||||
      expect(validateUint(new BigNumber(123))).to.deep.equal({
 | 
			
		||||
        value: new BigNumber(123),
 | 
			
		||||
        valueError: null
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on invalid numbers', () => {
 | 
			
		||||
      expect(validateUint(null)).to.deep.equal({
 | 
			
		||||
        value: null,
 | 
			
		||||
        valueError: ERRORS.invalidNumber
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on negative numbers', () => {
 | 
			
		||||
      expect(validateUint(-1)).to.deep.equal({
 | 
			
		||||
        value: -1,
 | 
			
		||||
        valueError: ERRORS.negativeNumber
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets error on decimal numbers', () => {
 | 
			
		||||
      expect(validateUint(3.1415927)).to.deep.equal({
 | 
			
		||||
        value: 3.1415927,
 | 
			
		||||
        valueError: ERRORS.decimalNumber
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('isNullAddress', () => {
 | 
			
		||||
    it('verifies a prefixed null address', () => {
 | 
			
		||||
      expect(isNullAddress(`0x${NULL_ADDRESS}`)).to.be.true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('verifies a non-prefixed null address', () => {
 | 
			
		||||
      expect(isNullAddress(NULL_ADDRESS)).to.be.true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets false on a null value', () => {
 | 
			
		||||
      expect(isNullAddress(null)).to.be.false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets false on a non-full length 00..00 value', () => {
 | 
			
		||||
      expect(isNullAddress(NULL_ADDRESS.slice(2))).to.be.false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('sets false on a valid addess, non 00..00 value', () => {
 | 
			
		||||
      expect(isNullAddress('0x1234567890123456789012345678901234567890')).to.be.false;
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user