From 2326dcdb129674677674690b300fec1245149a48 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Feb 2019 17:28:31 -0800 Subject: Handle NULL input for all data types --- .../abi_encoder/abstract_data_types/data_type.ts | 3 ++- .../abi_encoder/abstract_data_types/types/set.ts | 21 +++++++++++++++++++++ .../utils/src/abi_encoder/calldata/raw_calldata.ts | 5 +++++ .../utils/src/abi_encoder/evm_data_types/address.ts | 5 +++++ .../utils/src/abi_encoder/evm_data_types/bool.ts | 5 +++++ .../src/abi_encoder/evm_data_types/dynamic_bytes.ts | 5 +++++ .../utils/src/abi_encoder/evm_data_types/int.ts | 12 ++++++++++-- .../utils/src/abi_encoder/evm_data_types/pointer.ts | 5 +++++ .../src/abi_encoder/evm_data_types/static_bytes.ts | 7 +++++++ .../utils/src/abi_encoder/evm_data_types/string.ts | 5 +++++ .../utils/src/abi_encoder/evm_data_types/uint.ts | 12 ++++++++++-- packages/utils/src/abi_encoder/utils/constants.ts | 6 +++++- 12 files changed, 85 insertions(+), 6 deletions(-) (limited to 'packages/utils/src') diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts index f23324721..bd4711baf 100644 --- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts +++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts @@ -47,7 +47,7 @@ export abstract class DataType { const hasSelector = !_.isUndefined(selector); const rawCalldata = new RawCalldata(calldata, hasSelector); const rules_ = _.isUndefined(rules) ? constants.DEFAULT_DECODING_RULES : rules; - const value = this.generateValue(rawCalldata, rules_); + const value = rawCalldata.getSizeInBytes() > 0 ? this.generateValue(rawCalldata, rules_) : this.getDefaultValue(rules_); return value; } @@ -71,6 +71,7 @@ export abstract class DataType { public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock; public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any; + public abstract getDefaultValue(rules?: DecodingRules): any; public abstract getSignatureType(): string; public abstract isStatic(): boolean; } diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts index 2c6c4b0f6..d45088482 100644 --- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts +++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts @@ -97,6 +97,27 @@ export abstract class AbstractSetDataType extends DataType { return isStatic; } + public getDefaultValue(rules?: DecodingRules): any[] | object { + let defaultValue: any[] | object; + if (this._isArray && _.isUndefined(this._arrayLength)) { + defaultValue = []; + } else if (!_.isUndefined(rules) && rules.shouldConvertStructsToObjects && !this._isArray) { + defaultValue = {}; + _.each(this._memberIndexByName, (idx: number, key: string) => { + const member = this._members[idx]; + const memberValue = member.getDefaultValue(); + (defaultValue as { [key: string]: any })[key] = memberValue; + }); + } else { + defaultValue = []; + _.each(this._members, (member: DataType, idx: number) => { + const memberValue = member.getDefaultValue(); + (defaultValue as any[]).push(memberValue); + }); + } + return defaultValue; + } + protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): SetCalldataBlock { // Sanity check: if the set has a defined length then `value` must have the same length. if (!_.isUndefined(this._arrayLength) && value.length !== this._arrayLength) { diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index 189841989..dbc9d4942 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -79,4 +79,9 @@ export class RawCalldata { public getSelector(): string { return this._selector; } + + public getSizeInBytes(): number { + const sizeInBytes = this._value.byteLength; + return sizeInBytes; + } } diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts index 2278830eb..7e92d3888 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/address.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts @@ -12,6 +12,7 @@ export class AddressDataType extends AbstractBlobDataType { private static readonly _ADDRESS_SIZE_IN_BYTES = 20; private static readonly _DECODED_ADDRESS_OFFSET_IN_BYTES = constants.EVM_WORD_WIDTH_IN_BYTES - AddressDataType._ADDRESS_SIZE_IN_BYTES; + private static readonly _DEFAULT_VALUE = '0x0000000000000000000000000000000000000000'; public static matchType(type: string): boolean { return type === SolidityTypes.Address; @@ -43,6 +44,10 @@ export class AddressDataType extends AbstractBlobDataType { return valueLowercase; } + public getDefaultValue(): string { + return AddressDataType._DEFAULT_VALUE; + } + public getSignatureType(): string { return SolidityTypes.Address; } diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts index ffccd6e53..54b516bb0 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts @@ -10,6 +10,7 @@ import { constants } from '../utils/constants'; export class BoolDataType extends AbstractBlobDataType { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; + private static readonly _DEFAULT_VALUE: boolean =false; public static matchType(type: string): boolean { return type === SolidityTypes.Bool; @@ -47,6 +48,10 @@ export class BoolDataType extends AbstractBlobDataType { return value; } + public getDefaultValue(): boolean { + return BoolDataType._DEFAULT_VALUE; + } + public getSignatureType(): string { return SolidityTypes.Bool; } diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts index fa38b63c0..0dd40fed2 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts @@ -9,6 +9,7 @@ import { constants } from '../utils/constants'; export class DynamicBytesDataType extends AbstractBlobDataType { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false; + private static readonly _DEFAULT_VALUE = "0x"; public static matchType(type: string): boolean { return type === SolidityTypes.Bytes; @@ -65,6 +66,10 @@ export class DynamicBytesDataType extends AbstractBlobDataType { return value; } + public getDefaultValue(): string { + return DynamicBytesDataType._DEFAULT_VALUE; + } + public getSignatureType(): string { return SolidityTypes.Bytes; } diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts index f8be1f778..c7e4318eb 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/int.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts @@ -15,6 +15,7 @@ export class IntDataType extends AbstractBlobDataType { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; private static readonly _MAX_WIDTH: number = 256; private static readonly _DEFAULT_WIDTH: number = IntDataType._MAX_WIDTH; + private static readonly _DEFAULT_VALUE = new BigNumber(0); private readonly _width: number; private readonly _minValue: BigNumber; private readonly _maxValue: BigNumber; @@ -50,13 +51,20 @@ export class IntDataType extends AbstractBlobDataType { public decodeValue(calldata: RawCalldata): BigNumber | number { const valueBuf = calldata.popWord(); const value = EncoderMath.safeDecodeNumericValue(valueBuf, this._minValue, this._maxValue); - const numberOfBytesInUint8 = 8; - if (this._width === numberOfBytesInUint8) { + if (this._width === constants.NUMBER_OF_BYTES_IN_UINT8) { return value.toNumber(); } return value; } + public getDefaultValue(): BigNumber | number { + const defaultValue = IntDataType._DEFAULT_VALUE; + if (this._width === constants.NUMBER_OF_BYTES_IN_UINT8) { + return defaultValue.toNumber(); + } + return defaultValue; + } + public getSignatureType(): string { return `${SolidityTypes.Int}${this._width}`; } diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts index 250db7c64..50f68f5ea 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts @@ -18,4 +18,9 @@ export class PointerDataType extends AbstractPointerDataType { public getSignature(isDetailed?: boolean): string { return this._destination.getSignature(isDetailed); } + + public getDefaultValue(): any { + const defaultValue = this._destination.getDefaultValue(); + return defaultValue; + } } diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts index cbf1957d7..a965f6796 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts @@ -58,6 +58,13 @@ export class StaticBytesDataType extends AbstractBlobDataType { return value; } + public getDefaultValue(): string { + const valueBufPadded = constants.EMPTY_EVM_WORD_BUFFER; + const valueBuf = valueBufPadded.slice(0, this._width); + const value = ethUtil.bufferToHex(valueBuf); + return value; + } + private _sanityCheckValue(value: string | Buffer): void { if (typeof value === 'string') { if (!_.startsWith(value, '0x')) { diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts index 97ac46442..886f398f9 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/string.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts @@ -9,6 +9,7 @@ import { constants } from '../utils/constants'; export class StringDataType extends AbstractBlobDataType { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false; + private static readonly _DEFAULT_VALUE = ""; public static matchType(type: string): boolean { return type === SolidityTypes.String; @@ -52,6 +53,10 @@ export class StringDataType extends AbstractBlobDataType { return value; } + public getDefaultValue(): string { + return StringDataType._DEFAULT_VALUE; + } + public getSignatureType(): string { return SolidityTypes.String; } diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts index a82aa789e..9dc141a59 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts @@ -16,6 +16,7 @@ export class UIntDataType extends AbstractBlobDataType { private static readonly _MAX_WIDTH: number = 256; private static readonly _DEFAULT_WIDTH: number = UIntDataType._MAX_WIDTH; private static readonly _MIN_VALUE = new BigNumber(0); + private static readonly _DEFAULT_VALUE = new BigNumber(0); private readonly _width: number; private readonly _maxValue: BigNumber; @@ -49,13 +50,20 @@ export class UIntDataType extends AbstractBlobDataType { public decodeValue(calldata: RawCalldata): BigNumber | number { const valueBuf = calldata.popWord(); const value = EncoderMath.safeDecodeNumericValue(valueBuf, UIntDataType._MIN_VALUE, this._maxValue); - const numberOfBytesInUint8 = 8; - if (this._width === numberOfBytesInUint8) { + if (this._width === constants.NUMBER_OF_BYTES_IN_INT8) { return value.toNumber(); } return value; } + public getDefaultValue(): BigNumber | number { + const defaultValue = UIntDataType._DEFAULT_VALUE; + if (this._width === constants.NUMBER_OF_BYTES_IN_INT8) { + return defaultValue.toNumber(); + } + return defaultValue; + } + public getSignatureType(): string { return `${SolidityTypes.Uint}${this._width}`; } diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts index fc586f295..e14814e2e 100644 --- a/packages/utils/src/abi_encoder/utils/constants.ts +++ b/packages/utils/src/abi_encoder/utils/constants.ts @@ -14,4 +14,8 @@ export const constants = { DEFAULT_DECODING_RULES: { shouldConvertStructsToObjects: true } as DecodingRules, DEFAULT_ENCODING_RULES: { shouldOptimize: true, shouldAnnotate: false } as EncodingRules, /* tslint:enable no-object-literal-type-assertion */ -}; + EMPTY_EVM_WORD_STRING: '0x0000000000000000000000000000000000000000000000000000000000000000', + EMPTY_EVM_WORD_BUFFER: new Buffer('0x0000000000000000000000000000000000000000000000000000000000000000'), + NUMBER_OF_BYTES_IN_UINT8: 8, + NUMBER_OF_BYTES_IN_INT8: 8, +} -- cgit v1.2.3 From 2ad6bd394504fe8d89ce6189aef18bb705ad7625 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Feb 2019 18:01:38 -0800 Subject: Test cases for handling NULL input for all data types --- packages/utils/src/abi_encoder/utils/constants.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/utils/src') diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts index e14814e2e..db190c3a6 100644 --- a/packages/utils/src/abi_encoder/utils/constants.ts +++ b/packages/utils/src/abi_encoder/utils/constants.ts @@ -1,4 +1,5 @@ import { DecodingRules, EncodingRules } from './rules'; +import * as ethUtil from 'ethereumjs-util'; export const constants = { EVM_WORD_WIDTH_IN_BYTES: 32, @@ -15,7 +16,7 @@ export const constants = { DEFAULT_ENCODING_RULES: { shouldOptimize: true, shouldAnnotate: false } as EncodingRules, /* tslint:enable no-object-literal-type-assertion */ EMPTY_EVM_WORD_STRING: '0x0000000000000000000000000000000000000000000000000000000000000000', - EMPTY_EVM_WORD_BUFFER: new Buffer('0x0000000000000000000000000000000000000000000000000000000000000000'), + EMPTY_EVM_WORD_BUFFER: ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000000'), NUMBER_OF_BYTES_IN_UINT8: 8, NUMBER_OF_BYTES_IN_INT8: 8, } -- cgit v1.2.3 From 023ea5b3a13f015ffad037cc6f21a686d2b95023 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 5 Feb 2019 18:03:52 -0800 Subject: Ran prettier + linter --- packages/utils/src/abi_encoder/abstract_data_types/data_type.ts | 3 ++- packages/utils/src/abi_encoder/evm_data_types/bool.ts | 2 +- packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts | 2 +- packages/utils/src/abi_encoder/evm_data_types/int.ts | 4 ++-- packages/utils/src/abi_encoder/evm_data_types/string.ts | 2 +- packages/utils/src/abi_encoder/evm_data_types/uint.ts | 4 ++-- packages/utils/src/abi_encoder/utils/constants.ts | 5 +++-- 7 files changed, 12 insertions(+), 10 deletions(-) (limited to 'packages/utils/src') diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts index bd4711baf..db4f02b89 100644 --- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts +++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts @@ -47,7 +47,8 @@ export abstract class DataType { const hasSelector = !_.isUndefined(selector); const rawCalldata = new RawCalldata(calldata, hasSelector); const rules_ = _.isUndefined(rules) ? constants.DEFAULT_DECODING_RULES : rules; - const value = rawCalldata.getSizeInBytes() > 0 ? this.generateValue(rawCalldata, rules_) : this.getDefaultValue(rules_); + const value = + rawCalldata.getSizeInBytes() > 0 ? this.generateValue(rawCalldata, rules_) : this.getDefaultValue(rules_); return value; } diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts index 54b516bb0..24887c509 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts @@ -10,7 +10,7 @@ import { constants } from '../utils/constants'; export class BoolDataType extends AbstractBlobDataType { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; - private static readonly _DEFAULT_VALUE: boolean =false; + private static readonly _DEFAULT_VALUE: boolean = false; public static matchType(type: string): boolean { return type === SolidityTypes.Bool; diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts index 0dd40fed2..7a49a84b4 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts @@ -9,7 +9,7 @@ import { constants } from '../utils/constants'; export class DynamicBytesDataType extends AbstractBlobDataType { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false; - private static readonly _DEFAULT_VALUE = "0x"; + private static readonly _DEFAULT_VALUE = '0x'; public static matchType(type: string): boolean { return type === SolidityTypes.Bytes; diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts index c7e4318eb..02278f666 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/int.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts @@ -51,7 +51,7 @@ export class IntDataType extends AbstractBlobDataType { public decodeValue(calldata: RawCalldata): BigNumber | number { const valueBuf = calldata.popWord(); const value = EncoderMath.safeDecodeNumericValue(valueBuf, this._minValue, this._maxValue); - if (this._width === constants.NUMBER_OF_BYTES_IN_UINT8) { + if (this._width === constants.NUMBER_OF_BYTES_IN_INT8) { return value.toNumber(); } return value; @@ -59,7 +59,7 @@ export class IntDataType extends AbstractBlobDataType { public getDefaultValue(): BigNumber | number { const defaultValue = IntDataType._DEFAULT_VALUE; - if (this._width === constants.NUMBER_OF_BYTES_IN_UINT8) { + if (this._width === constants.NUMBER_OF_BYTES_IN_INT8) { return defaultValue.toNumber(); } return defaultValue; diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts index 886f398f9..f54d739b4 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/string.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts @@ -9,7 +9,7 @@ import { constants } from '../utils/constants'; export class StringDataType extends AbstractBlobDataType { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false; - private static readonly _DEFAULT_VALUE = ""; + private static readonly _DEFAULT_VALUE = ''; public static matchType(type: string): boolean { return type === SolidityTypes.String; diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts index 9dc141a59..d530606b9 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts @@ -50,7 +50,7 @@ export class UIntDataType extends AbstractBlobDataType { public decodeValue(calldata: RawCalldata): BigNumber | number { const valueBuf = calldata.popWord(); const value = EncoderMath.safeDecodeNumericValue(valueBuf, UIntDataType._MIN_VALUE, this._maxValue); - if (this._width === constants.NUMBER_OF_BYTES_IN_INT8) { + if (this._width === constants.NUMBER_OF_BYTES_IN_UINT8) { return value.toNumber(); } return value; @@ -58,7 +58,7 @@ export class UIntDataType extends AbstractBlobDataType { public getDefaultValue(): BigNumber | number { const defaultValue = UIntDataType._DEFAULT_VALUE; - if (this._width === constants.NUMBER_OF_BYTES_IN_INT8) { + if (this._width === constants.NUMBER_OF_BYTES_IN_UINT8) { return defaultValue.toNumber(); } return defaultValue; diff --git a/packages/utils/src/abi_encoder/utils/constants.ts b/packages/utils/src/abi_encoder/utils/constants.ts index db190c3a6..b45b5b8e8 100644 --- a/packages/utils/src/abi_encoder/utils/constants.ts +++ b/packages/utils/src/abi_encoder/utils/constants.ts @@ -1,6 +1,7 @@ -import { DecodingRules, EncodingRules } from './rules'; import * as ethUtil from 'ethereumjs-util'; +import { DecodingRules, EncodingRules } from './rules'; + export const constants = { EVM_WORD_WIDTH_IN_BYTES: 32, EVM_WORD_WIDTH_IN_BITS: 256, @@ -19,4 +20,4 @@ export const constants = { EMPTY_EVM_WORD_BUFFER: ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000000'), NUMBER_OF_BYTES_IN_UINT8: 8, NUMBER_OF_BYTES_IN_INT8: 8, -} +}; -- cgit v1.2.3