From aed8b083b587e7b420ac6129b04004dea95c3f3a Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 20 Nov 2018 13:24:45 -0800 Subject: Split Calldata into multiple files - 1 class per file --- .../utils/src/abi_encoder/calldata/calldata.ts | 224 +++++++++++++++++++++ .../src/abi_encoder/calldata/calldata_block.ts | 77 +++++++ .../src/abi_encoder/calldata/calldata_blocks.ts | 3 + .../calldata/dependent_calldata_block.ts | 59 ++++++ packages/utils/src/abi_encoder/calldata/index.ts | 6 + .../abi_encoder/calldata/member_calldata_block.ts | 48 +++++ .../abi_encoder/calldata/payload_calldata_block.ts | 20 ++ .../utils/src/abi_encoder/calldata/raw_calldata.ts | 82 ++++++++ 8 files changed, 519 insertions(+) create mode 100644 packages/utils/src/abi_encoder/calldata/calldata.ts create mode 100644 packages/utils/src/abi_encoder/calldata/calldata_block.ts create mode 100644 packages/utils/src/abi_encoder/calldata/calldata_blocks.ts create mode 100644 packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts create mode 100644 packages/utils/src/abi_encoder/calldata/index.ts create mode 100644 packages/utils/src/abi_encoder/calldata/member_calldata_block.ts create mode 100644 packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts create mode 100644 packages/utils/src/abi_encoder/calldata/raw_calldata.ts (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts new file mode 100644 index 000000000..5ac4c1fe7 --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -0,0 +1,224 @@ + +import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; + +import * as Constants from '../constants'; +import { Queue } from '../utils/queue'; +import { EncodingRules } from '../utils/rules'; + +import { CalldataBlock } from './calldata_block'; +import * as CalldataBlocks from './calldata_blocks'; + +export class Calldata { + private readonly _rules: EncodingRules; + private _selector: string; + private _sizeInBytes: number; + private _root: CalldataBlock | undefined; + + private static _createQueue(block: CalldataBlock): Queue { + const blockQueue = new Queue(); + + // Base Case + if (!(block instanceof CalldataBlocks.MemberCalldataBlock)) { + blockQueue.push(block); + return blockQueue; + } + + // This is a Member Block + const memberBlock = block; + _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => { + if (member instanceof CalldataBlocks.MemberCalldataBlock) { + blockQueue.mergeFront(Calldata._createQueue(member)); + } else { + blockQueue.pushFront(member); + } + }); + + // Children + _.each(memberBlock.getMembers(), (member: CalldataBlock) => { + if (member instanceof CalldataBlocks.DependentCalldataBlock && member.getAlias() === undefined) { + const dependency = member.getDependency(); + if (dependency instanceof CalldataBlocks.MemberCalldataBlock) { + blockQueue.merge(Calldata._createQueue(dependency)); + } else { + blockQueue.push(dependency); + } + } + }); + + blockQueue.pushFront(memberBlock); + return blockQueue; + } + + public constructor(rules: EncodingRules) { + this._rules = rules; + this._selector = ''; + this._sizeInBytes = 0; + this._root = undefined; + } + + public optimize(): void { + if (this._root === undefined) { + throw new Error('expected root'); + } + + const blocksByHash: { [key: string]: CalldataBlock } = {}; + + // 1. Create a queue of subtrees by hash + // Note that they are ordered the same as + const subtreeQueue = Calldata._createQueue(this._root); + let block: CalldataBlock | undefined; + for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) { + if (block instanceof CalldataBlocks.DependentCalldataBlock) { + const dependencyBlockHashBuf = block.getDependency().computeHash(); + const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf); + if (dependencyBlockHash in blocksByHash) { + const blockWithSameHash = blocksByHash[dependencyBlockHash]; + if (blockWithSameHash !== block.getDependency()) { + block.setAlias(blockWithSameHash); + } + } + continue; + } + + const blockHashBuf = block.computeHash(); + const blockHash = ethUtil.bufferToHex(blockHashBuf); + if (!(blockHash in blocksByHash)) { + blocksByHash[blockHash] = block; + } + } + } + + public toHexString(): string { + if (this._root === undefined) { + throw new Error('expected root'); + } + + if (this._rules.optimize) { + this.optimize(); + } + + const offsetQueue = Calldata._createQueue(this._root); + let block: CalldataBlock | undefined; + let offset = 0; + for (block = offsetQueue.pop(); block !== undefined; block = offsetQueue.pop()) { + block.setOffset(offset); + offset += block.getSizeInBytes(); + } + + const hexValue = this._rules.annotate ? this._generateAnnotatedHexString() : this._generateCondensedHexString(); + return hexValue; + } + + public getSelectorHex(): string { + return this._selector; + } + + public getSizeInBytes(): number { + return this._sizeInBytes; + } + + public setRoot(block: CalldataBlock): void { + this._root = block; + this._sizeInBytes += block.getSizeInBytes(); + } + + public setSelector(selector: string): void { + this._selector = selector.startsWith('0x') ? selector : `$0x${selector}`; + if (this._selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) { + throw new Error(`Invalid selector '${this._selector}'`); + } + this._sizeInBytes += Constants.HEX_SELECTOR_LENGTH_IN_BYTES; // @TODO: Used to be += 8. Bad? + } + + private _generateAnnotatedHexString(): string { + let hexValue = `${this._selector}`; + if (this._root === undefined) { + throw new Error('expected root'); + } + + const valueQueue = Calldata._createQueue(this._root); + + let block: CalldataBlock | undefined; + let offset = 0; + const functionBlock = valueQueue.peek(); + const functionName: string = functionBlock === undefined ? '' : functionBlock.getName(); + for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) { + // Process each block 1 word at a time + const size = block.getSizeInBytes(); + const name = block.getName(); + const parentName = block.getParentName(); + const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, ''); + + // Current offset + let offsetStr = ''; + + // If this block is empty then it's a newline + const offsetPadding = 10; + const valuePadding = 74; + const namePadding = 80; + const evmWordStartIndex = 0; + const emptySize = 0; + let value = ''; + let nameStr = ''; + let line = ''; + if (size === emptySize) { + offsetStr = ' '.repeat(offsetPadding); + value = ' '.repeat(valuePadding); + nameStr = `### ${prettyName.padEnd(namePadding)}`; + line = `\n${offsetStr}${value}${nameStr}`; + } else { + offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding); + value = ethUtil + .stripHexPrefix( + ethUtil.bufferToHex( + block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES), + ), + ) + .padEnd(valuePadding); + if (block instanceof CalldataBlocks.MemberCalldataBlock) { + nameStr = `### ${prettyName.padEnd(namePadding)}`; + line = `\n${offsetStr}${value}${nameStr}`; + } else { + nameStr = ` ${prettyName.padEnd(namePadding)}`; + line = `${offsetStr}${value}${nameStr}`; + } + } + + for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) { + offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding); + value = ethUtil + .stripHexPrefix( + ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)), + ) + .padEnd(valuePadding); + nameStr = ' '.repeat(namePadding); + line = `${line}\n${offsetStr}${value}${nameStr}`; + } + + // Append to hex value + hexValue = `${hexValue}\n${line}`; + offset += size; + } + + return hexValue; + } + + private _generateCondensedHexString(): string { + const selectorBuffer = ethUtil.toBuffer(this._selector); + if (this._root === undefined) { + throw new Error('expected root'); + } + + const valueQueue = Calldata._createQueue(this._root); + const valueBufs: Buffer[] = [selectorBuffer]; + let block: CalldataBlock | undefined; + for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) { + valueBufs.push(block.toBuffer()); + } + + const combinedBuffers = Buffer.concat(valueBufs); + const hexValue = ethUtil.bufferToHex(combinedBuffers); + return hexValue; + } +} diff --git a/packages/utils/src/abi_encoder/calldata/calldata_block.ts b/packages/utils/src/abi_encoder/calldata/calldata_block.ts new file mode 100644 index 000000000..35bd994e5 --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/calldata_block.ts @@ -0,0 +1,77 @@ +import * as ethUtil from 'ethereumjs-util'; + +export abstract class CalldataBlock { + private readonly _signature: string; + private readonly _parentName: string; + private _name: string; + private _offsetInBytes: number; + private _headerSizeInBytes: number; + private _bodySizeInBytes: number; + + constructor( + name: string, + signature: string, + parentName: string, + headerSizeInBytes: number, + bodySizeInBytes: number, + ) { + this._name = name; + this._signature = signature; + this._parentName = parentName; + this._offsetInBytes = 0; + this._headerSizeInBytes = headerSizeInBytes; + this._bodySizeInBytes = bodySizeInBytes; + } + + protected _setHeaderSize(headerSizeInBytes: number): void { + this._headerSizeInBytes = headerSizeInBytes; + } + + protected _setBodySize(bodySizeInBytes: number): void { + this._bodySizeInBytes = bodySizeInBytes; + } + + protected _setName(name: string): void { + this._name = name; + } + + public getName(): string { + return this._name; + } + + public getParentName(): string { + return this._parentName; + } + + public getSignature(): string { + return this._signature; + } + public getHeaderSizeInBytes(): number { + return this._headerSizeInBytes; + } + + public getBodySizeInBytes(): number { + return this._bodySizeInBytes; + } + + public getSizeInBytes(): number { + return this.getHeaderSizeInBytes() + this.getBodySizeInBytes(); + } + + public getOffsetInBytes(): number { + return this._offsetInBytes; + } + + public setOffset(offsetInBytes: number): void { + this._offsetInBytes = offsetInBytes; + } + + public computeHash(): Buffer { + const rawData = this.getRawData(); + const hash = ethUtil.sha3(rawData); + return hash; + } + + public abstract toBuffer(): Buffer; + public abstract getRawData(): Buffer; +} diff --git a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts new file mode 100644 index 000000000..37660ef21 --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts @@ -0,0 +1,3 @@ +export * from './dependent_calldata_block'; +export * from './member_calldata_block'; +export * from './payload_calldata_block'; \ No newline at end of file diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts new file mode 100644 index 000000000..d6870ec0b --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts @@ -0,0 +1,59 @@ +import * as ethUtil from 'ethereumjs-util'; + +import * as Constants from '../constants'; + +import { CalldataBlock } from './calldata_block'; + +export class DependentCalldataBlock extends CalldataBlock { + public static readonly RAW_DATA_START = new Buffer('<'); + public static readonly RAW_DATA_END = new Buffer('>'); + private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32; + private static readonly _EMPTY_HEADER_SIZE = 0; + private readonly _parent: CalldataBlock; + private readonly _dependency: CalldataBlock; + private _aliasFor: CalldataBlock | undefined; + + constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) { + const headerSizeInBytes = DependentCalldataBlock._EMPTY_HEADER_SIZE; + const bodySizeInBytes = DependentCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES; + super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); + this._parent = parent; + this._dependency = dependency; + this._aliasFor = undefined; + } + + public toBuffer(): Buffer { + const destinationOffset = + this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes(); + const parentOffset = this._parent.getOffsetInBytes(); + const parentHeaderSize = this._parent.getHeaderSizeInBytes(); + const pointer: number = destinationOffset - (parentOffset + parentHeaderSize); + const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(Constants.HEX_BASE)}`); + const evmWordWidthInBytes = 32; + const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes); + return pointerBufPadded; + } + + public getDependency(): CalldataBlock { + return this._dependency; + } + + public setAlias(block: CalldataBlock): void { + this._aliasFor = block; + this._setName(`${this.getName()} (alias for ${block.getName()})`); + } + + public getAlias(): CalldataBlock | undefined { + return this._aliasFor; + } + + public getRawData(): Buffer { + const dependencyRawData = this._dependency.getRawData(); + const rawDataComponents: Buffer[] = []; + rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START); + rawDataComponents.push(dependencyRawData); + rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END); + const rawData = Buffer.concat(rawDataComponents); + return rawData; + } +} \ No newline at end of file diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts new file mode 100644 index 000000000..0e1f57a2d --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/index.ts @@ -0,0 +1,6 @@ +export * from './calldata_block'; +export * from './dependent_calldata_block'; +export * from './payload_calldata_block'; +export * from './member_calldata_block'; +export * from './calldata'; +export * from './raw_calldata'; \ No newline at end of file diff --git a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts new file mode 100644 index 000000000..e9bcb2f34 --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts @@ -0,0 +1,48 @@ +import * as _ from 'lodash'; + +import { CalldataBlock } from './calldata_block'; + +export class MemberCalldataBlock extends CalldataBlock { + private _header: Buffer | undefined; + private _members: CalldataBlock[]; + + constructor(name: string, signature: string, parentName: string) { + super(name, signature, parentName, 0, 0); + this._members = []; + this._header = undefined; + } + + public getRawData(): Buffer { + const rawDataComponents: Buffer[] = []; + if (this._header !== undefined) { + rawDataComponents.push(this._header); + } + _.each(this._members, (member: CalldataBlock) => { + const memberBuffer = member.getRawData(); + rawDataComponents.push(memberBuffer); + }); + + const rawData = Buffer.concat(rawDataComponents); + return rawData; + } + + public setMembers(members: CalldataBlock[]): void { + this._members = members; + } + + public setHeader(header: Buffer): void { + this._setHeaderSize(header.byteLength); + this._header = header; + } + + public toBuffer(): Buffer { + if (this._header !== undefined) { + return this._header; + } + return new Buffer(''); + } + + public getMembers(): CalldataBlock[] { + return this._members; + } +} \ No newline at end of file diff --git a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts new file mode 100644 index 000000000..81a88bc19 --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts @@ -0,0 +1,20 @@ +import { CalldataBlock } from './calldata_block'; + +export class PayloadCalldataBlock extends CalldataBlock { + private readonly _payload: Buffer; + + constructor(name: string, signature: string, parentName: string, payload: Buffer) { + const headerSizeInBytes = 0; + const bodySizeInBytes = payload.byteLength; + super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); + this._payload = payload; + } + + public toBuffer(): Buffer { + return this._payload; + } + + public getRawData(): Buffer { + return this._payload; + } +} \ No newline at end of file diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts new file mode 100644 index 000000000..8b946ee4b --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -0,0 +1,82 @@ +import * as ethUtil from 'ethereumjs-util'; + +import * as Constants from '../constants'; +import { Queue } from '../utils/queue'; + +export class RawCalldata { + private static readonly _INITIAL_OFFSET = 0; + private readonly _value: Buffer; + private readonly _selector: string; + private readonly _scopes: Queue; + private _offset: number; // tracks current offset into raw calldata; used for parsing + + constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) { + if (typeof value === 'string' && !value.startsWith('0x')) { + throw new Error(`Expected raw calldata to start with '0x'`); + } + const valueBuf = ethUtil.toBuffer(value); + if (hasSelectorPrefix) { + this._selector = ethUtil.bufferToHex( + valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES), + ); + this._value = valueBuf.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); // disregard selector + } else { + this._selector = '0x'; + this._value = valueBuf; + } + + this._scopes = new Queue(); + this._scopes.push(RawCalldata._INITIAL_OFFSET); + this._offset = RawCalldata._INITIAL_OFFSET; + } + + public popBytes(lengthInBytes: number): Buffer { + const value = this._value.slice(this._offset, this._offset + lengthInBytes); + this.setOffset(this._offset + lengthInBytes); + return value; + } + + public popWord(): Buffer { + const wordInBytes = 32; + return this.popBytes(wordInBytes); + } + + public popWords(length: number): Buffer { + const wordInBytes = 32; + return this.popBytes(length * wordInBytes); + } + + public readBytes(from: number, to: number): Buffer { + const value = this._value.slice(from, to); + return value; + } + + public setOffset(offsetInBytes: number): void { + this._offset = offsetInBytes; + } + + public startScope(): void { + this._scopes.pushFront(this._offset); + } + + public endScope(): void { + this._scopes.pop(); + } + + public getOffset(): number { + return this._offset; + } + + public toAbsoluteOffset(relativeOffset: number): number { + const scopeOffset = this._scopes.peek(); + if (scopeOffset === undefined) { + throw new Error(`Tried to access undefined scope.`); + } + const absoluteOffset = relativeOffset + scopeOffset; + return absoluteOffset; + } + + public getSelector(): string { + return this._selector; + } +} \ No newline at end of file -- cgit v1.2.3 From d4d917f350fb6916df50f3aa5cf09ce68b316aa1 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 20 Nov 2018 13:25:49 -0800 Subject: Ran prettier --- packages/utils/src/abi_encoder/calldata/calldata.ts | 1 - packages/utils/src/abi_encoder/calldata/calldata_blocks.ts | 2 +- packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts | 2 +- packages/utils/src/abi_encoder/calldata/index.ts | 2 +- packages/utils/src/abi_encoder/calldata/member_calldata_block.ts | 2 +- packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts | 2 +- packages/utils/src/abi_encoder/calldata/raw_calldata.ts | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index 5ac4c1fe7..1abf1b681 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -1,4 +1,3 @@ - import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; diff --git a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts index 37660ef21..8d4e7d7ca 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts @@ -1,3 +1,3 @@ export * from './dependent_calldata_block'; export * from './member_calldata_block'; -export * from './payload_calldata_block'; \ No newline at end of file +export * from './payload_calldata_block'; diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts index d6870ec0b..4aec5eabc 100644 --- a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts +++ b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts @@ -56,4 +56,4 @@ export class DependentCalldataBlock extends CalldataBlock { const rawData = Buffer.concat(rawDataComponents); return rawData; } -} \ No newline at end of file +} diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts index 0e1f57a2d..2c786cd8d 100644 --- a/packages/utils/src/abi_encoder/calldata/index.ts +++ b/packages/utils/src/abi_encoder/calldata/index.ts @@ -3,4 +3,4 @@ export * from './dependent_calldata_block'; export * from './payload_calldata_block'; export * from './member_calldata_block'; export * from './calldata'; -export * from './raw_calldata'; \ No newline at end of file +export * from './raw_calldata'; diff --git a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts index e9bcb2f34..c35beb8de 100644 --- a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts +++ b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts @@ -45,4 +45,4 @@ export class MemberCalldataBlock extends CalldataBlock { public getMembers(): CalldataBlock[] { return this._members; } -} \ No newline at end of file +} diff --git a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts index 81a88bc19..0420b01d8 100644 --- a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts +++ b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts @@ -17,4 +17,4 @@ export class PayloadCalldataBlock extends CalldataBlock { public getRawData(): Buffer { return this._payload; } -} \ No newline at end of file +} diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index 8b946ee4b..b7bd35737 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -79,4 +79,4 @@ export class RawCalldata { public getSelector(): string { return this._selector; } -} \ No newline at end of file +} -- cgit v1.2.3 From a895dacd4e20238087245c274564f694c71f7f6e Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 20 Nov 2018 14:18:01 -0800 Subject: moved abi encoder constants into utils dir --- packages/utils/src/abi_encoder/calldata/calldata.ts | 2 +- packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts | 2 +- packages/utils/src/abi_encoder/calldata/raw_calldata.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index 1abf1b681..154a81b7f 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -1,7 +1,7 @@ import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import * as Constants from '../constants'; +import * as Constants from '../utils/constants'; import { Queue } from '../utils/queue'; import { EncodingRules } from '../utils/rules'; diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts index 4aec5eabc..16b9a6fe6 100644 --- a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts +++ b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts @@ -1,6 +1,6 @@ import * as ethUtil from 'ethereumjs-util'; -import * as Constants from '../constants'; +import * as Constants from '../utils/constants'; import { CalldataBlock } from './calldata_block'; diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index b7bd35737..27a59c6a3 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -1,6 +1,6 @@ import * as ethUtil from 'ethereumjs-util'; -import * as Constants from '../constants'; +import * as Constants from '../utils/constants'; import { Queue } from '../utils/queue'; export class RawCalldata { -- cgit v1.2.3 From 978a58105cd2d2f5d6ee3bcd870218fd357fb010 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 20 Nov 2018 16:34:41 -0800 Subject: Prepended `front` to function names in Queue --- packages/utils/src/abi_encoder/calldata/calldata.ts | 14 +++++++------- packages/utils/src/abi_encoder/calldata/raw_calldata.ts | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index 154a81b7f..3b85f821b 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -19,7 +19,7 @@ export class Calldata { // Base Case if (!(block instanceof CalldataBlocks.MemberCalldataBlock)) { - blockQueue.push(block); + blockQueue.pushBack(block); return blockQueue; } @@ -38,9 +38,9 @@ export class Calldata { if (member instanceof CalldataBlocks.DependentCalldataBlock && member.getAlias() === undefined) { const dependency = member.getDependency(); if (dependency instanceof CalldataBlocks.MemberCalldataBlock) { - blockQueue.merge(Calldata._createQueue(dependency)); + blockQueue.mergeBack(Calldata._createQueue(dependency)); } else { - blockQueue.push(dependency); + blockQueue.pushBack(dependency); } } }); @@ -100,7 +100,7 @@ export class Calldata { const offsetQueue = Calldata._createQueue(this._root); let block: CalldataBlock | undefined; let offset = 0; - for (block = offsetQueue.pop(); block !== undefined; block = offsetQueue.pop()) { + for (block = offsetQueue.popFront(); block !== undefined; block = offsetQueue.popFront()) { block.setOffset(offset); offset += block.getSizeInBytes(); } @@ -140,9 +140,9 @@ export class Calldata { let block: CalldataBlock | undefined; let offset = 0; - const functionBlock = valueQueue.peek(); + const functionBlock = valueQueue.peekFront(); const functionName: string = functionBlock === undefined ? '' : functionBlock.getName(); - for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) { + for (block = valueQueue.popFront(); block !== undefined; block = valueQueue.popFront()) { // Process each block 1 word at a time const size = block.getSizeInBytes(); const name = block.getName(); @@ -212,7 +212,7 @@ export class Calldata { const valueQueue = Calldata._createQueue(this._root); const valueBufs: Buffer[] = [selectorBuffer]; let block: CalldataBlock | undefined; - for (block = valueQueue.pop(); block !== undefined; block = valueQueue.pop()) { + for (block = valueQueue.popFront(); block !== undefined; block = valueQueue.popFront()) { valueBufs.push(block.toBuffer()); } diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index 27a59c6a3..9e72bbd62 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -26,7 +26,7 @@ export class RawCalldata { } this._scopes = new Queue(); - this._scopes.push(RawCalldata._INITIAL_OFFSET); + this._scopes.pushBack(RawCalldata._INITIAL_OFFSET); this._offset = RawCalldata._INITIAL_OFFSET; } @@ -60,7 +60,7 @@ export class RawCalldata { } public endScope(): void { - this._scopes.pop(); + this._scopes.popFront(); } public getOffset(): number { @@ -68,7 +68,7 @@ export class RawCalldata { } public toAbsoluteOffset(relativeOffset: number): number { - const scopeOffset = this._scopes.peek(); + const scopeOffset = this._scopes.peekFront(); if (scopeOffset === undefined) { throw new Error(`Tried to access undefined scope.`); } -- cgit v1.2.3 From 9a51af46ee4a35b3d1ce2fcdc6f561aa68307cf0 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Sun, 25 Nov 2018 18:24:46 -0800 Subject: Payload -> Blob, Dependent -> Pointer, Member -> Set --- .../utils/src/abi_encoder/calldata/blocks/blob.ts | 20 ++++++++ .../utils/src/abi_encoder/calldata/blocks/index.ts | 3 ++ .../src/abi_encoder/calldata/blocks/pointer.ts | 59 ++++++++++++++++++++++ .../utils/src/abi_encoder/calldata/blocks/set.ts | 47 +++++++++++++++++ .../utils/src/abi_encoder/calldata/calldata.ts | 14 ++--- .../src/abi_encoder/calldata/calldata_blocks.ts | 3 -- .../calldata/dependent_calldata_block.ts | 59 ---------------------- packages/utils/src/abi_encoder/calldata/index.ts | 7 ++- .../abi_encoder/calldata/member_calldata_block.ts | 48 ------------------ .../abi_encoder/calldata/payload_calldata_block.ts | 20 -------- .../utils/src/abi_encoder/calldata/raw_calldata.ts | 25 +++++---- 11 files changed, 151 insertions(+), 154 deletions(-) create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/blob.ts create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/index.ts create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/pointer.ts create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/set.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/calldata_blocks.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/member_calldata_block.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/blocks/blob.ts b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts new file mode 100644 index 000000000..210ef6420 --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts @@ -0,0 +1,20 @@ +import { CalldataBlock } from '../calldata_block'; + +export class Blob extends CalldataBlock { + private readonly _blob: Buffer; + + constructor(name: string, signature: string, parentName: string, blob: Buffer) { + const headerSizeInBytes = 0; + const bodySizeInBytes = blob.byteLength; + super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); + this._blob = blob; + } + + public toBuffer(): Buffer { + return this._blob; + } + + public getRawData(): Buffer { + return this._blob; + } +} diff --git a/packages/utils/src/abi_encoder/calldata/blocks/index.ts b/packages/utils/src/abi_encoder/calldata/blocks/index.ts new file mode 100644 index 000000000..958582dae --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/blocks/index.ts @@ -0,0 +1,3 @@ +export * from './blob'; +export * from './pointer'; +export * from './set'; diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts new file mode 100644 index 000000000..1c49a8c6c --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts @@ -0,0 +1,59 @@ +import * as ethUtil from 'ethereumjs-util'; + +import * as Constants from '../../utils/constants'; + +import { CalldataBlock } from '../calldata_block'; + +export class Pointer extends CalldataBlock { + public static readonly RAW_DATA_START = new Buffer('<'); + public static readonly RAW_DATA_END = new Buffer('>'); + private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32; + private static readonly _EMPTY_HEADER_SIZE = 0; + private readonly _parent: CalldataBlock; + private readonly _dependency: CalldataBlock; + private _aliasFor: CalldataBlock | undefined; + + constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) { + const headerSizeInBytes = Pointer._EMPTY_HEADER_SIZE; + const bodySizeInBytes = Pointer._DEPENDENT_PAYLOAD_SIZE_IN_BYTES; + super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); + this._parent = parent; + this._dependency = dependency; + this._aliasFor = undefined; + } + + public toBuffer(): Buffer { + const destinationOffset = + this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes(); + const parentOffset = this._parent.getOffsetInBytes(); + const parentHeaderSize = this._parent.getHeaderSizeInBytes(); + const pointer: number = destinationOffset - (parentOffset + parentHeaderSize); + const pointerHex = `0x${pointer.toString(Constants.HEX_BASE)}`; + const pointerBuf = ethUtil.toBuffer(pointerHex); + const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, Constants.EVM_WORD_WIDTH_IN_BYTES); + return pointerBufPadded; + } + + public getDependency(): CalldataBlock { + return this._dependency; + } + + public setAlias(block: CalldataBlock): void { + this._aliasFor = block; + this._setName(`${this.getName()} (alias for ${block.getName()})`); + } + + public getAlias(): CalldataBlock | undefined { + return this._aliasFor; + } + + public getRawData(): Buffer { + const dependencyRawData = this._dependency.getRawData(); + const rawDataComponents: Buffer[] = []; + rawDataComponents.push(Pointer.RAW_DATA_START); + rawDataComponents.push(dependencyRawData); + rawDataComponents.push(Pointer.RAW_DATA_END); + const rawData = Buffer.concat(rawDataComponents); + return rawData; + } +} diff --git a/packages/utils/src/abi_encoder/calldata/blocks/set.ts b/packages/utils/src/abi_encoder/calldata/blocks/set.ts new file mode 100644 index 000000000..e4de22c5c --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/blocks/set.ts @@ -0,0 +1,47 @@ +import * as _ from 'lodash'; + +import { CalldataBlock } from '../calldata_block'; + +export class Set extends CalldataBlock { + private _header: Buffer | undefined; + private _members: CalldataBlock[]; + + constructor(name: string, signature: string, parentName: string) { + super(name, signature, parentName, 0, 0); + this._members = []; + this._header = undefined; + } + + public getRawData(): Buffer { + const rawDataComponents: Buffer[] = []; + if (this._header) { + rawDataComponents.push(this._header); + } + _.each(this._members, (member: CalldataBlock) => { + const memberBuffer = member.getRawData(); + rawDataComponents.push(memberBuffer); + }); + const rawData = Buffer.concat(rawDataComponents); + return rawData; + } + + public setMembers(members: CalldataBlock[]): void { + this._members = members; + } + + public setHeader(header: Buffer): void { + this._setHeaderSize(header.byteLength); + this._header = header; + } + + public toBuffer(): Buffer { + if (this._header) { + return this._header; + } + return new Buffer(''); + } + + public getMembers(): CalldataBlock[] { + return this._members; + } +} diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index 3b85f821b..b2396ee8f 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -5,8 +5,8 @@ import * as Constants from '../utils/constants'; import { Queue } from '../utils/queue'; import { EncodingRules } from '../utils/rules'; +import * as CalldataBlocks from './blocks'; import { CalldataBlock } from './calldata_block'; -import * as CalldataBlocks from './calldata_blocks'; export class Calldata { private readonly _rules: EncodingRules; @@ -18,7 +18,7 @@ export class Calldata { const blockQueue = new Queue(); // Base Case - if (!(block instanceof CalldataBlocks.MemberCalldataBlock)) { + if (!(block instanceof CalldataBlocks.Set)) { blockQueue.pushBack(block); return blockQueue; } @@ -26,7 +26,7 @@ export class Calldata { // This is a Member Block const memberBlock = block; _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => { - if (member instanceof CalldataBlocks.MemberCalldataBlock) { + if (member instanceof CalldataBlocks.Set) { blockQueue.mergeFront(Calldata._createQueue(member)); } else { blockQueue.pushFront(member); @@ -35,9 +35,9 @@ export class Calldata { // Children _.each(memberBlock.getMembers(), (member: CalldataBlock) => { - if (member instanceof CalldataBlocks.DependentCalldataBlock && member.getAlias() === undefined) { + if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) { const dependency = member.getDependency(); - if (dependency instanceof CalldataBlocks.MemberCalldataBlock) { + if (dependency instanceof CalldataBlocks.Set) { blockQueue.mergeBack(Calldata._createQueue(dependency)); } else { blockQueue.pushBack(dependency); @@ -68,7 +68,7 @@ export class Calldata { const subtreeQueue = Calldata._createQueue(this._root); let block: CalldataBlock | undefined; for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) { - if (block instanceof CalldataBlocks.DependentCalldataBlock) { + if (block instanceof CalldataBlocks.Pointer) { const dependencyBlockHashBuf = block.getDependency().computeHash(); const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf); if (dependencyBlockHash in blocksByHash) { @@ -175,7 +175,7 @@ export class Calldata { ), ) .padEnd(valuePadding); - if (block instanceof CalldataBlocks.MemberCalldataBlock) { + if (block instanceof CalldataBlocks.Set) { nameStr = `### ${prettyName.padEnd(namePadding)}`; line = `\n${offsetStr}${value}${nameStr}`; } else { diff --git a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts deleted file mode 100644 index 8d4e7d7ca..000000000 --- a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './dependent_calldata_block'; -export * from './member_calldata_block'; -export * from './payload_calldata_block'; diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts deleted file mode 100644 index 16b9a6fe6..000000000 --- a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as ethUtil from 'ethereumjs-util'; - -import * as Constants from '../utils/constants'; - -import { CalldataBlock } from './calldata_block'; - -export class DependentCalldataBlock extends CalldataBlock { - public static readonly RAW_DATA_START = new Buffer('<'); - public static readonly RAW_DATA_END = new Buffer('>'); - private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32; - private static readonly _EMPTY_HEADER_SIZE = 0; - private readonly _parent: CalldataBlock; - private readonly _dependency: CalldataBlock; - private _aliasFor: CalldataBlock | undefined; - - constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) { - const headerSizeInBytes = DependentCalldataBlock._EMPTY_HEADER_SIZE; - const bodySizeInBytes = DependentCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES; - super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); - this._parent = parent; - this._dependency = dependency; - this._aliasFor = undefined; - } - - public toBuffer(): Buffer { - const destinationOffset = - this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes(); - const parentOffset = this._parent.getOffsetInBytes(); - const parentHeaderSize = this._parent.getHeaderSizeInBytes(); - const pointer: number = destinationOffset - (parentOffset + parentHeaderSize); - const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(Constants.HEX_BASE)}`); - const evmWordWidthInBytes = 32; - const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes); - return pointerBufPadded; - } - - public getDependency(): CalldataBlock { - return this._dependency; - } - - public setAlias(block: CalldataBlock): void { - this._aliasFor = block; - this._setName(`${this.getName()} (alias for ${block.getName()})`); - } - - public getAlias(): CalldataBlock | undefined { - return this._aliasFor; - } - - public getRawData(): Buffer { - const dependencyRawData = this._dependency.getRawData(); - const rawDataComponents: Buffer[] = []; - rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START); - rawDataComponents.push(dependencyRawData); - rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END); - const rawData = Buffer.concat(rawDataComponents); - return rawData; - } -} diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts index 2c786cd8d..2ef75e8d0 100644 --- a/packages/utils/src/abi_encoder/calldata/index.ts +++ b/packages/utils/src/abi_encoder/calldata/index.ts @@ -1,6 +1,5 @@ -export * from './calldata_block'; -export * from './dependent_calldata_block'; -export * from './payload_calldata_block'; -export * from './member_calldata_block'; export * from './calldata'; +export * from './calldata_block'; export * from './raw_calldata'; +import * as CalldataBlocks from './blocks'; +export { CalldataBlocks }; diff --git a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts deleted file mode 100644 index c35beb8de..000000000 --- a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as _ from 'lodash'; - -import { CalldataBlock } from './calldata_block'; - -export class MemberCalldataBlock extends CalldataBlock { - private _header: Buffer | undefined; - private _members: CalldataBlock[]; - - constructor(name: string, signature: string, parentName: string) { - super(name, signature, parentName, 0, 0); - this._members = []; - this._header = undefined; - } - - public getRawData(): Buffer { - const rawDataComponents: Buffer[] = []; - if (this._header !== undefined) { - rawDataComponents.push(this._header); - } - _.each(this._members, (member: CalldataBlock) => { - const memberBuffer = member.getRawData(); - rawDataComponents.push(memberBuffer); - }); - - const rawData = Buffer.concat(rawDataComponents); - return rawData; - } - - public setMembers(members: CalldataBlock[]): void { - this._members = members; - } - - public setHeader(header: Buffer): void { - this._setHeaderSize(header.byteLength); - this._header = header; - } - - public toBuffer(): Buffer { - if (this._header !== undefined) { - return this._header; - } - return new Buffer(''); - } - - public getMembers(): CalldataBlock[] { - return this._members; - } -} diff --git a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts deleted file mode 100644 index 0420b01d8..000000000 --- a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { CalldataBlock } from './calldata_block'; - -export class PayloadCalldataBlock extends CalldataBlock { - private readonly _payload: Buffer; - - constructor(name: string, signature: string, parentName: string, payload: Buffer) { - const headerSizeInBytes = 0; - const bodySizeInBytes = payload.byteLength; - super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); - this._payload = payload; - } - - public toBuffer(): Buffer { - return this._payload; - } - - public getRawData(): Buffer { - return this._payload; - } -} diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index 9e72bbd62..b13cbdfd9 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -8,26 +8,25 @@ export class RawCalldata { private readonly _value: Buffer; private readonly _selector: string; private readonly _scopes: Queue; - private _offset: number; // tracks current offset into raw calldata; used for parsing + private _offset: number; - constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) { + public constructor(value: string | Buffer, hasSelector: boolean = true) { + // Sanity check if (typeof value === 'string' && !value.startsWith('0x')) { throw new Error(`Expected raw calldata to start with '0x'`); } - const valueBuf = ethUtil.toBuffer(value); - if (hasSelectorPrefix) { - this._selector = ethUtil.bufferToHex( - valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES), - ); - this._value = valueBuf.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); // disregard selector - } else { - this._selector = '0x'; - this._value = valueBuf; - } - + // Construct initial values + this._value = ethUtil.toBuffer(value); + this._selector = '0x'; this._scopes = new Queue(); this._scopes.pushBack(RawCalldata._INITIAL_OFFSET); this._offset = RawCalldata._INITIAL_OFFSET; + // If there's a selector then slice it + if (hasSelector) { + const selectorBuf = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); + this._value = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); + this._selector = ethUtil.bufferToHex(selectorBuf); + } } public popBytes(lengthInBytes: number): Buffer { -- cgit v1.2.3 From 8f73f53c95d8ba887558863b8b726a2b3f5b7e2b Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Sun, 25 Nov 2018 20:05:41 -0800 Subject: Moved calldata iterator logic into its own iterator clas --- .../utils/src/abi_encoder/calldata/calldata.ts | 56 +++---------- .../utils/src/abi_encoder/calldata/iterator.ts | 94 ++++++++++++++++++++++ 2 files changed, 104 insertions(+), 46 deletions(-) create mode 100644 packages/utils/src/abi_encoder/calldata/iterator.ts (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index b2396ee8f..dd9d47def 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -2,11 +2,11 @@ import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; import * as Constants from '../utils/constants'; -import { Queue } from '../utils/queue'; import { EncodingRules } from '../utils/rules'; import * as CalldataBlocks from './blocks'; import { CalldataBlock } from './calldata_block'; +import { CalldataIterator, ReverseCalldataIterator } from './iterator'; export class Calldata { private readonly _rules: EncodingRules; @@ -14,41 +14,6 @@ export class Calldata { private _sizeInBytes: number; private _root: CalldataBlock | undefined; - private static _createQueue(block: CalldataBlock): Queue { - const blockQueue = new Queue(); - - // Base Case - if (!(block instanceof CalldataBlocks.Set)) { - blockQueue.pushBack(block); - return blockQueue; - } - - // This is a Member Block - const memberBlock = block; - _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => { - if (member instanceof CalldataBlocks.Set) { - blockQueue.mergeFront(Calldata._createQueue(member)); - } else { - blockQueue.pushFront(member); - } - }); - - // Children - _.each(memberBlock.getMembers(), (member: CalldataBlock) => { - if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) { - const dependency = member.getDependency(); - if (dependency instanceof CalldataBlocks.Set) { - blockQueue.mergeBack(Calldata._createQueue(dependency)); - } else { - blockQueue.pushBack(dependency); - } - } - }); - - blockQueue.pushFront(memberBlock); - return blockQueue; - } - public constructor(rules: EncodingRules) { this._rules = rules; this._selector = ''; @@ -65,9 +30,9 @@ export class Calldata { // 1. Create a queue of subtrees by hash // Note that they are ordered the same as - const subtreeQueue = Calldata._createQueue(this._root); + const iterator = new ReverseCalldataIterator(this._root); let block: CalldataBlock | undefined; - for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) { + while (block = iterator.next()) { if (block instanceof CalldataBlocks.Pointer) { const dependencyBlockHashBuf = block.getDependency().computeHash(); const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf); @@ -97,10 +62,10 @@ export class Calldata { this.optimize(); } - const offsetQueue = Calldata._createQueue(this._root); + const iterator = new CalldataIterator(this._root); let block: CalldataBlock | undefined; let offset = 0; - for (block = offsetQueue.popFront(); block !== undefined; block = offsetQueue.popFront()) { + while (block = iterator.next()) { block.setOffset(offset); offset += block.getSizeInBytes(); } @@ -136,13 +101,12 @@ export class Calldata { throw new Error('expected root'); } - const valueQueue = Calldata._createQueue(this._root); + const iterator = new CalldataIterator(this._root); let block: CalldataBlock | undefined; let offset = 0; - const functionBlock = valueQueue.peekFront(); - const functionName: string = functionBlock === undefined ? '' : functionBlock.getName(); - for (block = valueQueue.popFront(); block !== undefined; block = valueQueue.popFront()) { + const functionName: string = this._root.getName(); + while (block = iterator.next()) { // Process each block 1 word at a time const size = block.getSizeInBytes(); const name = block.getName(); @@ -209,10 +173,10 @@ export class Calldata { throw new Error('expected root'); } - const valueQueue = Calldata._createQueue(this._root); + const iterator = new CalldataIterator(this._root); const valueBufs: Buffer[] = [selectorBuffer]; let block: CalldataBlock | undefined; - for (block = valueQueue.popFront(); block !== undefined; block = valueQueue.popFront()) { + while (block = iterator.next()) { valueBufs.push(block.toBuffer()); } diff --git a/packages/utils/src/abi_encoder/calldata/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts new file mode 100644 index 000000000..3e3367e10 --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/iterator.ts @@ -0,0 +1,94 @@ +/* tslint:disable max-classes-per-file */ +import * as _ from 'lodash'; + +import { Queue } from '../utils/queue'; + +import * as CalldataBlocks from './blocks'; +import { CalldataBlock } from './calldata_block'; + +/** + * Iterator class for Calldata Blocks. Blocks follows the order + * they should be put into calldata that is passed to he EVM. + * + * Example #1: + * Let root = Set { + * Blob{} A, + * Pointer { + * Blob{} a + * } B, + * Blob{} C + * } + * It will iterate as follows: [A, B, C, B.a] + * + * Example #2: + * Let root = Set { + * Blob{} A, + * Pointer { + * Blob{} a + * Pointer { + * Blob{} b + * } + * } B, + * Pointer { + * Blob{} c + * } C + * } + * It will iterate as follows: [A, B, C, B.a, B.b, C.c] + */ +abstract class BaseIterator { + protected readonly _root: CalldataBlock; + protected readonly _queue: Queue; + + private static _createQueue(block: CalldataBlock): Queue { + const queue = new Queue(); + // Base case + if (!(block instanceof CalldataBlocks.Set)) { + queue.pushBack(block); + return queue; + } + // This is a set; add members + const set = block; + _.eachRight(set.getMembers(), (member: CalldataBlock) => { + queue.mergeFront(BaseIterator._createQueue(member)); + }); + // Add children + _.each(set.getMembers(), (member: CalldataBlock) => { + // Traverse child if it is a unique pointer. + // A pointer that is an alias for another pointer is ignored. + if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) { + const dependency = member.getDependency(); + queue.mergeBack(BaseIterator._createQueue(dependency)); + } + }); + // Put set block at the front of the queue + queue.pushFront(set); + return queue; + } + + public constructor(root: CalldataBlock) { + this._root = root; + this._queue = BaseIterator._createQueue(root); + } + + public abstract next(): CalldataBlock | undefined; +} + +export class CalldataIterator extends BaseIterator { + public constructor(root: CalldataBlock) { + super(root); + } + + public next(): CalldataBlock | undefined { + return this._queue.popFront(); + } +} + +export class ReverseCalldataIterator extends BaseIterator { + public constructor(root: CalldataBlock) { + super(root); + } + + public next(): CalldataBlock | undefined { + return this._queue.popBack(); + } +} -- cgit v1.2.3 From bab1c92c703ee53e77a56a7f7a5e3bba5b4a2306 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Sun, 25 Nov 2018 20:11:10 -0800 Subject: Linter for Calldata Block Iterator --- .../utils/src/abi_encoder/calldata/calldata.ts | 13 ++++------- .../utils/src/abi_encoder/calldata/iterator.ts | 26 ++++++++++++++++++---- 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index dd9d47def..50f0f0fad 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -31,8 +31,7 @@ export class Calldata { // 1. Create a queue of subtrees by hash // Note that they are ordered the same as const iterator = new ReverseCalldataIterator(this._root); - let block: CalldataBlock | undefined; - while (block = iterator.next()) { + for (const block of iterator) { if (block instanceof CalldataBlocks.Pointer) { const dependencyBlockHashBuf = block.getDependency().computeHash(); const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf); @@ -63,9 +62,8 @@ export class Calldata { } const iterator = new CalldataIterator(this._root); - let block: CalldataBlock | undefined; let offset = 0; - while (block = iterator.next()) { + for (const block of iterator) { block.setOffset(offset); offset += block.getSizeInBytes(); } @@ -102,11 +100,9 @@ export class Calldata { } const iterator = new CalldataIterator(this._root); - - let block: CalldataBlock | undefined; let offset = 0; const functionName: string = this._root.getName(); - while (block = iterator.next()) { + for (const block of iterator) { // Process each block 1 word at a time const size = block.getSizeInBytes(); const name = block.getName(); @@ -175,8 +171,7 @@ export class Calldata { const iterator = new CalldataIterator(this._root); const valueBufs: Buffer[] = [selectorBuffer]; - let block: CalldataBlock | undefined; - while (block = iterator.next()) { + for (const block of iterator) { valueBufs.push(block.toBuffer()); } diff --git a/packages/utils/src/abi_encoder/calldata/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts index 3e3367e10..8e2b16a5a 100644 --- a/packages/utils/src/abi_encoder/calldata/iterator.ts +++ b/packages/utils/src/abi_encoder/calldata/iterator.ts @@ -35,7 +35,7 @@ import { CalldataBlock } from './calldata_block'; * } * It will iterate as follows: [A, B, C, B.a, B.b, C.c] */ -abstract class BaseIterator { +abstract class BaseIterator implements Iterable { protected readonly _root: CalldataBlock; protected readonly _queue: Queue; @@ -70,7 +70,25 @@ abstract class BaseIterator { this._queue = BaseIterator._createQueue(root); } - public abstract next(): CalldataBlock | undefined; + public [Symbol.iterator](): { next: () => IteratorResult } { + return { + next: () => { + const nextBlock = this.nextBlock(); + if (nextBlock !== undefined) { + return { + value: nextBlock, + done: false, + }; + } + return { + done: true, + value: new CalldataBlocks.Blob('', '', '', new Buffer('')), + }; + }, + }; + } + + public abstract nextBlock(): CalldataBlock | undefined; } export class CalldataIterator extends BaseIterator { @@ -78,7 +96,7 @@ export class CalldataIterator extends BaseIterator { super(root); } - public next(): CalldataBlock | undefined { + public nextBlock(): CalldataBlock | undefined { return this._queue.popFront(); } } @@ -88,7 +106,7 @@ export class ReverseCalldataIterator extends BaseIterator { super(root); } - public next(): CalldataBlock | undefined { + public nextBlock(): CalldataBlock | undefined { return this._queue.popBack(); } } -- cgit v1.2.3 From 50344fa24a4a708ae90030af107afb15366f883f Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Sun, 25 Nov 2018 21:19:11 -0800 Subject: Added inline documentation for Calldata class --- .../utils/src/abi_encoder/calldata/calldata.ts | 227 +++++++++++++-------- 1 file changed, 145 insertions(+), 82 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index 50f0f0fad..da61b2256 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -11,27 +11,107 @@ import { CalldataIterator, ReverseCalldataIterator } from './iterator'; export class Calldata { private readonly _rules: EncodingRules; private _selector: string; - private _sizeInBytes: number; private _root: CalldataBlock | undefined; public constructor(rules: EncodingRules) { this._rules = rules; this._selector = ''; - this._sizeInBytes = 0; this._root = undefined; } - - public optimize(): void { + /** + * Sets the root calldata block. This block usually corresponds to a Method. + */ + public setRoot(block: CalldataBlock): void { + this._root = block; + } + /** + * Sets the selector to be prepended onto the calldata. + * If the root block was created by a Method then a selector will likely be set. + */ + public setSelector(selector: string): void { + if (!selector.startsWith('0x')) { + throw new Error(`Expected selector to be hex. Missing prefix '0x'`); + } else if (selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) { + throw new Error(`Invalid selector '${selector}'`); + } + this._selector = selector; + } + /** + * Iterates through the calldata blocks, starting from the root block, to construct calldata as a hex string. + * If the `optimize` flag is set then this calldata will be condensed, to save gas. + * If the `annotate` flag is set then this will return human-readable calldata. + * If the `annotate` flag is *not* set then this will return EVM-compatible calldata. + */ + public toString(): string { + // Sanity check: root block must be set + if (this._root === undefined) { + throw new Error('expected root'); + } + // Optimize, if flag set + if (this._rules.optimize) { + this._optimize(); + } + // Set offsets + const iterator = new CalldataIterator(this._root); + let offset = 0; + for (const block of iterator) { + block.setOffset(offset); + offset += block.getSizeInBytes(); + } + // Generate hex string + const hexString = this._rules.annotate ? this._toAnnotatedString() : this._toCondensedString(); + return hexString; + } + /** + * There are three types of calldata blocks: Blob, Set and Pointer. + * Scenarios arise where distinct pointers resolve to identical values. + * We optimize by keeping only one such instance of the identical value, and redirecting all pointers here. + * We keep the last such duplicate value because pointers can only be positive (they cannot point backwards). + * + * Example #1: + * function f(string[], string[]) + * f(["foo", "bar", "blitz"], ["foo", "bar", "blitz"]) + * The array ["foo", "bar", "blitz"] will only be included in the calldata once. + * + * Example #2: + * function f(string[], string) + * f(["foo", "bar", "blitz"], "foo") + * The string "foo" will only be included in the calldata once. + * + * Example #3: + * function f((string, uint, bytes), string, uint, bytes) + * f(("foo", 5, "0x05"), "foo", 5, "0x05") + * The string "foo" and bytes "0x05" will only be included in the calldata once. + * The duplicate `uint 5` values cannot be optimized out because they are static values (no pointer points to them). + * + * @TODO #1: + * This optimization strategy handles blocks that are exact duplicates of one another. + * But what if some block is a combination of two other blocks? Or a subset of another block? + * This optimization problem is not much different from the current implemetation. + * Instead of tracking "observed" hashes, at each node we would simply do pattern-matching on the calldata. + * This strategy would be applied after assigning offsets to the tree, rather than before (as in this strategy). + * Note that one consequence of this strategy is pointers may resolve to offsets that are not word-aligned. + * This shouldn't be a problem but further investigation should be done. + * + * @TODO #2: + * To be done as a follow-up to @TODO #1. + * Since we optimize from the bottom-up, we could be affecting the outcome of a later potential optimization. + * For example, what if by removing one duplicate value we miss out on optimizing another block higher in the tree. + * To handle this case, at each node we can store a candidate optimization in a priority queue (sorted by calldata size). + * At the end of traversing the tree, the candidate at the front of the queue will be the most optimal output. + * + */ + private _optimize(): void { + // Step 1/1 Create a reverse iterator (starts from the end of the calldata to the beginning) if (this._root === undefined) { throw new Error('expected root'); } - - const blocksByHash: { [key: string]: CalldataBlock } = {}; - - // 1. Create a queue of subtrees by hash - // Note that they are ordered the same as const iterator = new ReverseCalldataIterator(this._root); + // Step 2/2 Iterate over each block, keeping track of which blocks have been seen and pruning redundant blocks. + const blocksByHash: { [key: string]: CalldataBlock } = {}; for (const block of iterator) { + // If a block is a pointer and its value has already been observed, then update + // the pointer to resolve to the existing value. if (block instanceof CalldataBlocks.Pointer) { const dependencyBlockHashBuf = block.getDependency().computeHash(); const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf); @@ -43,7 +123,7 @@ export class Calldata { } continue; } - + // This block has not been seen. Record its hash. const blockHashBuf = block.computeHash(); const blockHash = ethUtil.bufferToHex(blockHashBuf); if (!(blockHash in blocksByHash)) { @@ -51,84 +131,85 @@ export class Calldata { } } } - - public toHexString(): string { + /** + * Returns EVM-compatible calldata as a Hex string. + */ + private _toCondensedString(): string { + // Sanity check: must have a root block. if (this._root === undefined) { throw new Error('expected root'); } - - if (this._rules.optimize) { - this.optimize(); - } - + // Construct an array of buffers (one buffer for each block). + const selectorBuffer = ethUtil.toBuffer(this._selector); + const valueBufs: Buffer[] = [selectorBuffer]; const iterator = new CalldataIterator(this._root); - let offset = 0; for (const block of iterator) { - block.setOffset(offset); - offset += block.getSizeInBytes(); + valueBufs.push(block.toBuffer()); } - - const hexValue = this._rules.annotate ? this._generateAnnotatedHexString() : this._generateCondensedHexString(); + // Create hex from buffer array. + const combinedBuffers = Buffer.concat(valueBufs); + const hexValue = ethUtil.bufferToHex(combinedBuffers); return hexValue; } - - public getSelectorHex(): string { - return this._selector; - } - - public getSizeInBytes(): number { - return this._sizeInBytes; - } - - public setRoot(block: CalldataBlock): void { - this._root = block; - this._sizeInBytes += block.getSizeInBytes(); - } - - public setSelector(selector: string): void { - this._selector = selector.startsWith('0x') ? selector : `$0x${selector}`; - if (this._selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) { - throw new Error(`Invalid selector '${this._selector}'`); - } - this._sizeInBytes += Constants.HEX_SELECTOR_LENGTH_IN_BYTES; // @TODO: Used to be += 8. Bad? - } - - private _generateAnnotatedHexString(): string { - let hexValue = `${this._selector}`; + /** + * Returns human-redable calldata. + * + * Example: + * simpleFunction(string[], string[]) + * strings = ["Hello", "World"] + * simpleFunction(strings, strings) + * + * Output: + * 0xbb4f12e3 + * ### simpleFunction + * 0x0 0000000000000000000000000000000000000000000000000000000000000040 ptr (alias for array2) + * 0x20 0000000000000000000000000000000000000000000000000000000000000040 ptr + * + * 0x40 0000000000000000000000000000000000000000000000000000000000000002 ### array2 + * 0x60 0000000000000000000000000000000000000000000000000000000000000040 ptr + * 0x80 0000000000000000000000000000000000000000000000000000000000000080 ptr + * 0xa0 0000000000000000000000000000000000000000000000000000000000000005 array2[0] + * 0xc0 48656c6c6f000000000000000000000000000000000000000000000000000000 + * 0xe0 0000000000000000000000000000000000000000000000000000000000000005 array2[1] + * 0x100 576f726c64000000000000000000000000000000000000000000000000000000 + */ + private _toAnnotatedString(): string { + // Sanity check: must have a root block. if (this._root === undefined) { throw new Error('expected root'); } - - const iterator = new CalldataIterator(this._root); + // Construct annotated calldata + let hexValue = `${this._selector}`; let offset = 0; const functionName: string = this._root.getName(); + const iterator = new CalldataIterator(this._root); for (const block of iterator) { // Process each block 1 word at a time const size = block.getSizeInBytes(); const name = block.getName(); const parentName = block.getParentName(); const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, ''); - - // Current offset - let offsetStr = ''; - - // If this block is empty then it's a newline const offsetPadding = 10; const valuePadding = 74; const namePadding = 80; const evmWordStartIndex = 0; const emptySize = 0; - let value = ''; + // Resulting line will be + let offsetStr = ''; + let valueStr = ''; let nameStr = ''; - let line = ''; + let lineStr = ''; if (size === emptySize) { + // This is a Set block with no header. + // For example, a tuple or an array with a defined length. offsetStr = ' '.repeat(offsetPadding); - value = ' '.repeat(valuePadding); + valueStr = ' '.repeat(valuePadding); nameStr = `### ${prettyName.padEnd(namePadding)}`; - line = `\n${offsetStr}${value}${nameStr}`; + lineStr = `\n${offsetStr}${valueStr}${nameStr}`; } else { + // This block has at least one word of value. offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding); - value = ethUtil + valueStr = ethUtil .stripHexPrefix( ethUtil.bufferToHex( block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES), @@ -137,46 +218,28 @@ export class Calldata { .padEnd(valuePadding); if (block instanceof CalldataBlocks.Set) { nameStr = `### ${prettyName.padEnd(namePadding)}`; - line = `\n${offsetStr}${value}${nameStr}`; + lineStr = `\n${offsetStr}${valueStr}${nameStr}`; } else { nameStr = ` ${prettyName.padEnd(namePadding)}`; - line = `${offsetStr}${value}${nameStr}`; + lineStr = `${offsetStr}${valueStr}${nameStr}`; } } - + // This block has a value that is more than 1 word. for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) { offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding); - value = ethUtil + valueStr = ethUtil .stripHexPrefix( ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)), ) .padEnd(valuePadding); nameStr = ' '.repeat(namePadding); - line = `${line}\n${offsetStr}${value}${nameStr}`; + lineStr = `${lineStr}\n${offsetStr}${valueStr}${nameStr}`; } - // Append to hex value - hexValue = `${hexValue}\n${line}`; + hexValue = `${hexValue}\n${lineStr}`; offset += size; } return hexValue; } - - private _generateCondensedHexString(): string { - const selectorBuffer = ethUtil.toBuffer(this._selector); - if (this._root === undefined) { - throw new Error('expected root'); - } - - const iterator = new CalldataIterator(this._root); - const valueBufs: Buffer[] = [selectorBuffer]; - for (const block of iterator) { - valueBufs.push(block.toBuffer()); - } - - const combinedBuffers = Buffer.concat(valueBufs); - const hexValue = ethUtil.bufferToHex(combinedBuffers); - return hexValue; - } } -- cgit v1.2.3 From 3bf5a4e83f57f82090a64fc76fcc7bf3f7c68607 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Sun, 25 Nov 2018 21:20:46 -0800 Subject: Moved some consts outside of a loop --- packages/utils/src/abi_encoder/calldata/calldata.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index da61b2256..668b92f06 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -178,6 +178,12 @@ export class Calldata { if (this._root === undefined) { throw new Error('expected root'); } + // Constants for constructing annotated string + const offsetPadding = 10; + const valuePadding = 74; + const namePadding = 80; + const evmWordStartIndex = 0; + const emptySize = 0; // Construct annotated calldata let hexValue = `${this._selector}`; let offset = 0; @@ -189,11 +195,6 @@ export class Calldata { const name = block.getName(); const parentName = block.getParentName(); const prettyName = name.replace(`${parentName}.`, '').replace(`${functionName}.`, ''); - const offsetPadding = 10; - const valuePadding = 74; - const namePadding = 80; - const evmWordStartIndex = 0; - const emptySize = 0; // Resulting line will be let offsetStr = ''; let valueStr = ''; -- cgit v1.2.3 From a8d707b4627b8997b02c53e670bd1f5636eced4c Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Sun, 25 Nov 2018 21:23:37 -0800 Subject: Linter on Calldata --- .../utils/src/abi_encoder/calldata/calldata.ts | 39 +++++++++++----------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index 668b92f06..a662f30b9 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -67,23 +67,23 @@ export class Calldata { * Scenarios arise where distinct pointers resolve to identical values. * We optimize by keeping only one such instance of the identical value, and redirecting all pointers here. * We keep the last such duplicate value because pointers can only be positive (they cannot point backwards). - * + * * Example #1: * function f(string[], string[]) * f(["foo", "bar", "blitz"], ["foo", "bar", "blitz"]) * The array ["foo", "bar", "blitz"] will only be included in the calldata once. - * + * * Example #2: * function f(string[], string) * f(["foo", "bar", "blitz"], "foo") * The string "foo" will only be included in the calldata once. - * + * * Example #3: * function f((string, uint, bytes), string, uint, bytes) * f(("foo", 5, "0x05"), "foo", 5, "0x05") * The string "foo" and bytes "0x05" will only be included in the calldata once. * The duplicate `uint 5` values cannot be optimized out because they are static values (no pointer points to them). - * + * * @TODO #1: * This optimization strategy handles blocks that are exact duplicates of one another. * But what if some block is a combination of two other blocks? Or a subset of another block? @@ -92,14 +92,14 @@ export class Calldata { * This strategy would be applied after assigning offsets to the tree, rather than before (as in this strategy). * Note that one consequence of this strategy is pointers may resolve to offsets that are not word-aligned. * This shouldn't be a problem but further investigation should be done. - * + * * @TODO #2: * To be done as a follow-up to @TODO #1. * Since we optimize from the bottom-up, we could be affecting the outcome of a later potential optimization. - * For example, what if by removing one duplicate value we miss out on optimizing another block higher in the tree. + * For example, what if by removing one duplicate value we miss out on optimizing another block higher in the tree. * To handle this case, at each node we can store a candidate optimization in a priority queue (sorted by calldata size). * At the end of traversing the tree, the candidate at the front of the queue will be the most optimal output. - * + * */ private _optimize(): void { // Step 1/1 Create a reverse iterator (starts from the end of the calldata to the beginning) @@ -153,25 +153,25 @@ export class Calldata { } /** * Returns human-redable calldata. - * + * * Example: * simpleFunction(string[], string[]) * strings = ["Hello", "World"] * simpleFunction(strings, strings) - * + * * Output: * 0xbb4f12e3 - * ### simpleFunction - * 0x0 0000000000000000000000000000000000000000000000000000000000000040 ptr (alias for array2) - * 0x20 0000000000000000000000000000000000000000000000000000000000000040 ptr + * ### simpleFunction + * 0x0 0000000000000000000000000000000000000000000000000000000000000040 ptr (alias for array2) + * 0x20 0000000000000000000000000000000000000000000000000000000000000040 ptr * - * 0x40 0000000000000000000000000000000000000000000000000000000000000002 ### array2 - * 0x60 0000000000000000000000000000000000000000000000000000000000000040 ptr - * 0x80 0000000000000000000000000000000000000000000000000000000000000080 ptr - * 0xa0 0000000000000000000000000000000000000000000000000000000000000005 array2[0] - * 0xc0 48656c6c6f000000000000000000000000000000000000000000000000000000 - * 0xe0 0000000000000000000000000000000000000000000000000000000000000005 array2[1] - * 0x100 576f726c64000000000000000000000000000000000000000000000000000000 + * 0x40 0000000000000000000000000000000000000000000000000000000000000002 ### array2 + * 0x60 0000000000000000000000000000000000000000000000000000000000000040 ptr + * 0x80 0000000000000000000000000000000000000000000000000000000000000080 ptr + * 0xa0 0000000000000000000000000000000000000000000000000000000000000005 array2[0] + * 0xc0 48656c6c6f000000000000000000000000000000000000000000000000000000 + * 0xe0 0000000000000000000000000000000000000000000000000000000000000005 array2[1] + * 0x100 576f726c64000000000000000000000000000000000000000000000000000000 */ private _toAnnotatedString(): string { // Sanity check: must have a root block. @@ -240,7 +240,6 @@ export class Calldata { hexValue = `${hexValue}\n${lineStr}`; offset += size; } - return hexValue; } } -- cgit v1.2.3 From f31d4ddffd8dd97f2b2dc226f4f132d1c3192c76 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 27 Nov 2018 13:10:34 -0800 Subject: Replaced null/undefined checks with lodash --- packages/utils/src/abi_encoder/calldata/blocks/pointer.ts | 3 ++- packages/utils/src/abi_encoder/calldata/calldata.ts | 8 ++++---- packages/utils/src/abi_encoder/calldata/iterator.ts | 4 ++-- packages/utils/src/abi_encoder/calldata/raw_calldata.ts | 3 ++- 4 files changed, 10 insertions(+), 8 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts index 1c49a8c6c..654cbe26c 100644 --- a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts +++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts @@ -1,4 +1,5 @@ import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; import * as Constants from '../../utils/constants'; @@ -24,7 +25,7 @@ export class Pointer extends CalldataBlock { public toBuffer(): Buffer { const destinationOffset = - this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes(); + !_.isUndefined(this._aliasFor) ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes(); const parentOffset = this._parent.getOffsetInBytes(); const parentHeaderSize = this._parent.getHeaderSizeInBytes(); const pointer: number = destinationOffset - (parentOffset + parentHeaderSize); diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index a662f30b9..e93d63803 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -44,7 +44,7 @@ export class Calldata { */ public toString(): string { // Sanity check: root block must be set - if (this._root === undefined) { + if (_.isUndefined(this._root)) { throw new Error('expected root'); } // Optimize, if flag set @@ -103,7 +103,7 @@ export class Calldata { */ private _optimize(): void { // Step 1/1 Create a reverse iterator (starts from the end of the calldata to the beginning) - if (this._root === undefined) { + if (_.isUndefined(this._root)) { throw new Error('expected root'); } const iterator = new ReverseCalldataIterator(this._root); @@ -136,7 +136,7 @@ export class Calldata { */ private _toCondensedString(): string { // Sanity check: must have a root block. - if (this._root === undefined) { + if (_.isUndefined(this._root)) { throw new Error('expected root'); } // Construct an array of buffers (one buffer for each block). @@ -175,7 +175,7 @@ export class Calldata { */ private _toAnnotatedString(): string { // Sanity check: must have a root block. - if (this._root === undefined) { + if (_.isUndefined(this._root)) { throw new Error('expected root'); } // Constants for constructing annotated string diff --git a/packages/utils/src/abi_encoder/calldata/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts index 8e2b16a5a..5307f7944 100644 --- a/packages/utils/src/abi_encoder/calldata/iterator.ts +++ b/packages/utils/src/abi_encoder/calldata/iterator.ts @@ -55,7 +55,7 @@ abstract class BaseIterator implements Iterable { _.each(set.getMembers(), (member: CalldataBlock) => { // Traverse child if it is a unique pointer. // A pointer that is an alias for another pointer is ignored. - if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) { + if (member instanceof CalldataBlocks.Pointer && _.isUndefined(member.getAlias())) { const dependency = member.getDependency(); queue.mergeBack(BaseIterator._createQueue(dependency)); } @@ -74,7 +74,7 @@ abstract class BaseIterator implements Iterable { return { next: () => { const nextBlock = this.nextBlock(); - if (nextBlock !== undefined) { + if (!_.isUndefined(nextBlock)) { return { value: nextBlock, done: false, diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index b13cbdfd9..dfd4cfa72 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -1,4 +1,5 @@ import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; import * as Constants from '../utils/constants'; import { Queue } from '../utils/queue'; @@ -68,7 +69,7 @@ export class RawCalldata { public toAbsoluteOffset(relativeOffset: number): number { const scopeOffset = this._scopes.peekFront(); - if (scopeOffset === undefined) { + if (_.isUndefined(scopeOffset)) { throw new Error(`Tried to access undefined scope.`); } const absoluteOffset = relativeOffset + scopeOffset; -- cgit v1.2.3 From 1f693ea12142bc761f4067871d92e7d2662cf256 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 27 Nov 2018 13:31:44 -0800 Subject: Changed from .startsWith to _.startsWith --- packages/utils/src/abi_encoder/calldata/calldata.ts | 2 +- packages/utils/src/abi_encoder/calldata/raw_calldata.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index e93d63803..c57ff08c2 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -29,7 +29,7 @@ export class Calldata { * If the root block was created by a Method then a selector will likely be set. */ public setSelector(selector: string): void { - if (!selector.startsWith('0x')) { + if (!_.startsWith(selector, '0x')) { throw new Error(`Expected selector to be hex. Missing prefix '0x'`); } else if (selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) { throw new Error(`Invalid selector '${selector}'`); diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index dfd4cfa72..fbe592fc7 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -13,7 +13,7 @@ export class RawCalldata { public constructor(value: string | Buffer, hasSelector: boolean = true) { // Sanity check - if (typeof value === 'string' && !value.startsWith('0x')) { + if (typeof value === 'string' && !_.startsWith(value, '0x')) { throw new Error(`Expected raw calldata to start with '0x'`); } // Construct initial values -- cgit v1.2.3 From ffb8b0a619be3b8fb30a6acc99f590a6b40d49e1 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 27 Nov 2018 13:35:39 -0800 Subject: Changed remaining instances of implicit `bool` casts to explicit lodash calls --- packages/utils/src/abi_encoder/calldata/blocks/set.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/blocks/set.ts b/packages/utils/src/abi_encoder/calldata/blocks/set.ts index e4de22c5c..81455b364 100644 --- a/packages/utils/src/abi_encoder/calldata/blocks/set.ts +++ b/packages/utils/src/abi_encoder/calldata/blocks/set.ts @@ -14,7 +14,7 @@ export class Set extends CalldataBlock { public getRawData(): Buffer { const rawDataComponents: Buffer[] = []; - if (this._header) { + if (!_.isUndefined(this._header)) { rawDataComponents.push(this._header); } _.each(this._members, (member: CalldataBlock) => { @@ -35,7 +35,7 @@ export class Set extends CalldataBlock { } public toBuffer(): Buffer { - if (this._header) { + if (!_.isUndefined(this._header)) { return this._header; } return new Buffer(''); -- cgit v1.2.3 From f479212410b238a7673983148f403b3a220083af Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 27 Nov 2018 15:28:26 -0800 Subject: Style cleanup. Improved wording of some error messages. --- packages/utils/src/abi_encoder/calldata/calldata.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index c57ff08c2..6d8814e06 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -59,7 +59,7 @@ export class Calldata { offset += block.getSizeInBytes(); } // Generate hex string - const hexString = this._rules.annotate ? this._toAnnotatedString() : this._toCondensedString(); + const hexString = this._rules.annotate ? this._toHumanReadableCallData() : this._toEvmCompatibeCallDataHex(); return hexString; } /** @@ -131,10 +131,7 @@ export class Calldata { } } } - /** - * Returns EVM-compatible calldata as a Hex string. - */ - private _toCondensedString(): string { + private _toEvmCompatibeCallDataHex(): string { // Sanity check: must have a root block. if (_.isUndefined(this._root)) { throw new Error('expected root'); @@ -152,7 +149,7 @@ export class Calldata { return hexValue; } /** - * Returns human-redable calldata. + * Returns human-readable calldata. * * Example: * simpleFunction(string[], string[]) @@ -173,7 +170,7 @@ export class Calldata { * 0xe0 0000000000000000000000000000000000000000000000000000000000000005 array2[1] * 0x100 576f726c64000000000000000000000000000000000000000000000000000000 */ - private _toAnnotatedString(): string { + private _toHumanReadableCallData(): string { // Sanity check: must have a root block. if (_.isUndefined(this._root)) { throw new Error('expected root'); -- cgit v1.2.3 From 029b8d59507df25aa9c7d1b096c8d873eb6ae4da Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 27 Nov 2018 17:11:15 -0800 Subject: Changed constants to an exported enum; this is 0x convention --- packages/utils/src/abi_encoder/calldata/blocks/pointer.ts | 6 +++--- packages/utils/src/abi_encoder/calldata/calldata.ts | 14 +++++++------- packages/utils/src/abi_encoder/calldata/raw_calldata.ts | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts index 654cbe26c..1daf33f7e 100644 --- a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts +++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts @@ -1,7 +1,7 @@ import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import * as Constants from '../../utils/constants'; +import { constants } from '../../utils/constants'; import { CalldataBlock } from '../calldata_block'; @@ -29,9 +29,9 @@ export class Pointer extends CalldataBlock { const parentOffset = this._parent.getOffsetInBytes(); const parentHeaderSize = this._parent.getHeaderSizeInBytes(); const pointer: number = destinationOffset - (parentOffset + parentHeaderSize); - const pointerHex = `0x${pointer.toString(Constants.HEX_BASE)}`; + const pointerHex = `0x${pointer.toString(constants.HEX_BASE)}`; const pointerBuf = ethUtil.toBuffer(pointerHex); - const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, Constants.EVM_WORD_WIDTH_IN_BYTES); + const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, constants.EVM_WORD_WIDTH_IN_BYTES); return pointerBufPadded; } diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index 6d8814e06..e5858b524 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -1,7 +1,7 @@ import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import * as Constants from '../utils/constants'; +import { constants } from '../utils/constants'; import { EncodingRules } from '../utils/rules'; import * as CalldataBlocks from './blocks'; @@ -31,7 +31,7 @@ export class Calldata { public setSelector(selector: string): void { if (!_.startsWith(selector, '0x')) { throw new Error(`Expected selector to be hex. Missing prefix '0x'`); - } else if (selector.length !== Constants.HEX_SELECTOR_LENGTH_IN_CHARS) { + } else if (selector.length !== constants.HEX_SELECTOR_LENGTH_IN_CHARS) { throw new Error(`Invalid selector '${selector}'`); } this._selector = selector; @@ -206,11 +206,11 @@ export class Calldata { lineStr = `\n${offsetStr}${valueStr}${nameStr}`; } else { // This block has at least one word of value. - offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding); + offsetStr = `0x${offset.toString(constants.HEX_BASE)}`.padEnd(offsetPadding); valueStr = ethUtil .stripHexPrefix( ethUtil.bufferToHex( - block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES), + block.toBuffer().slice(evmWordStartIndex, constants.EVM_WORD_WIDTH_IN_BYTES), ), ) .padEnd(valuePadding); @@ -223,11 +223,11 @@ export class Calldata { } } // This block has a value that is more than 1 word. - for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) { - offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding); + for (let j = constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += constants.EVM_WORD_WIDTH_IN_BYTES) { + offsetStr = `0x${(offset + j).toString(constants.HEX_BASE)}`.padEnd(offsetPadding); valueStr = ethUtil .stripHexPrefix( - ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)), + ethUtil.bufferToHex(block.toBuffer().slice(j, j + constants.EVM_WORD_WIDTH_IN_BYTES)), ) .padEnd(valuePadding); nameStr = ' '.repeat(namePadding); diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index fbe592fc7..189841989 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -1,7 +1,7 @@ import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import * as Constants from '../utils/constants'; +import { constants } from '../utils/constants'; import { Queue } from '../utils/queue'; export class RawCalldata { @@ -24,8 +24,8 @@ export class RawCalldata { this._offset = RawCalldata._INITIAL_OFFSET; // If there's a selector then slice it if (hasSelector) { - const selectorBuf = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); - this._value = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); + const selectorBuf = this._value.slice(constants.HEX_SELECTOR_LENGTH_IN_BYTES); + this._value = this._value.slice(constants.HEX_SELECTOR_LENGTH_IN_BYTES); this._selector = ethUtil.bufferToHex(selectorBuf); } } -- cgit v1.2.3 From 2da7cadefa877ff824da8fbaecd59dbff5028728 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 28 Nov 2018 13:47:01 -0800 Subject: Explicit imports for calldata --- packages/utils/src/abi_encoder/calldata/blocks/blob.ts | 2 +- packages/utils/src/abi_encoder/calldata/blocks/index.ts | 3 --- packages/utils/src/abi_encoder/calldata/blocks/pointer.ts | 10 +++++----- packages/utils/src/abi_encoder/calldata/blocks/set.ts | 2 +- packages/utils/src/abi_encoder/calldata/calldata.ts | 7 ++++--- packages/utils/src/abi_encoder/calldata/index.ts | 5 ----- packages/utils/src/abi_encoder/calldata/iterator.ts | 10 ++++++---- 7 files changed, 17 insertions(+), 22 deletions(-) delete mode 100644 packages/utils/src/abi_encoder/calldata/blocks/index.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/index.ts (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/blocks/blob.ts b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts index 210ef6420..219ea6c61 100644 --- a/packages/utils/src/abi_encoder/calldata/blocks/blob.ts +++ b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts @@ -1,6 +1,6 @@ import { CalldataBlock } from '../calldata_block'; -export class Blob extends CalldataBlock { +export class BlobCalldataBlock extends CalldataBlock { private readonly _blob: Buffer; constructor(name: string, signature: string, parentName: string, blob: Buffer) { diff --git a/packages/utils/src/abi_encoder/calldata/blocks/index.ts b/packages/utils/src/abi_encoder/calldata/blocks/index.ts deleted file mode 100644 index 958582dae..000000000 --- a/packages/utils/src/abi_encoder/calldata/blocks/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './blob'; -export * from './pointer'; -export * from './set'; diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts index 1daf33f7e..c706fe908 100644 --- a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts +++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts @@ -5,7 +5,7 @@ import { constants } from '../../utils/constants'; import { CalldataBlock } from '../calldata_block'; -export class Pointer extends CalldataBlock { +export class PointerCalldataBlock extends CalldataBlock { public static readonly RAW_DATA_START = new Buffer('<'); public static readonly RAW_DATA_END = new Buffer('>'); private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32; @@ -15,8 +15,8 @@ export class Pointer extends CalldataBlock { private _aliasFor: CalldataBlock | undefined; constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) { - const headerSizeInBytes = Pointer._EMPTY_HEADER_SIZE; - const bodySizeInBytes = Pointer._DEPENDENT_PAYLOAD_SIZE_IN_BYTES; + const headerSizeInBytes = PointerCalldataBlock._EMPTY_HEADER_SIZE; + const bodySizeInBytes = PointerCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES; super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); this._parent = parent; this._dependency = dependency; @@ -51,9 +51,9 @@ export class Pointer extends CalldataBlock { public getRawData(): Buffer { const dependencyRawData = this._dependency.getRawData(); const rawDataComponents: Buffer[] = []; - rawDataComponents.push(Pointer.RAW_DATA_START); + rawDataComponents.push(PointerCalldataBlock.RAW_DATA_START); rawDataComponents.push(dependencyRawData); - rawDataComponents.push(Pointer.RAW_DATA_END); + rawDataComponents.push(PointerCalldataBlock.RAW_DATA_END); const rawData = Buffer.concat(rawDataComponents); return rawData; } diff --git a/packages/utils/src/abi_encoder/calldata/blocks/set.ts b/packages/utils/src/abi_encoder/calldata/blocks/set.ts index 81455b364..d1abc4986 100644 --- a/packages/utils/src/abi_encoder/calldata/blocks/set.ts +++ b/packages/utils/src/abi_encoder/calldata/blocks/set.ts @@ -2,7 +2,7 @@ import * as _ from 'lodash'; import { CalldataBlock } from '../calldata_block'; -export class Set extends CalldataBlock { +export class SetCalldataBlock extends CalldataBlock { private _header: Buffer | undefined; private _members: CalldataBlock[]; diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index e5858b524..5f3eee94a 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -4,7 +4,8 @@ import * as _ from 'lodash'; import { constants } from '../utils/constants'; import { EncodingRules } from '../utils/rules'; -import * as CalldataBlocks from './blocks'; +import { PointerCalldataBlock } from './blocks/pointer'; +import { SetCalldataBlock } from './blocks/set'; import { CalldataBlock } from './calldata_block'; import { CalldataIterator, ReverseCalldataIterator } from './iterator'; @@ -112,7 +113,7 @@ export class Calldata { for (const block of iterator) { // If a block is a pointer and its value has already been observed, then update // the pointer to resolve to the existing value. - if (block instanceof CalldataBlocks.Pointer) { + if (block instanceof PointerCalldataBlock) { const dependencyBlockHashBuf = block.getDependency().computeHash(); const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf); if (dependencyBlockHash in blocksByHash) { @@ -214,7 +215,7 @@ export class Calldata { ), ) .padEnd(valuePadding); - if (block instanceof CalldataBlocks.Set) { + if (block instanceof SetCalldataBlock) { nameStr = `### ${prettyName.padEnd(namePadding)}`; lineStr = `\n${offsetStr}${valueStr}${nameStr}`; } else { diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts deleted file mode 100644 index 2ef75e8d0..000000000 --- a/packages/utils/src/abi_encoder/calldata/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './calldata'; -export * from './calldata_block'; -export * from './raw_calldata'; -import * as CalldataBlocks from './blocks'; -export { CalldataBlocks }; diff --git a/packages/utils/src/abi_encoder/calldata/iterator.ts b/packages/utils/src/abi_encoder/calldata/iterator.ts index 5307f7944..333b32b4f 100644 --- a/packages/utils/src/abi_encoder/calldata/iterator.ts +++ b/packages/utils/src/abi_encoder/calldata/iterator.ts @@ -3,7 +3,9 @@ import * as _ from 'lodash'; import { Queue } from '../utils/queue'; -import * as CalldataBlocks from './blocks'; +import { BlobCalldataBlock } from './blocks/blob'; +import { PointerCalldataBlock } from './blocks/pointer'; +import { SetCalldataBlock } from './blocks/set'; import { CalldataBlock } from './calldata_block'; /** @@ -42,7 +44,7 @@ abstract class BaseIterator implements Iterable { private static _createQueue(block: CalldataBlock): Queue { const queue = new Queue(); // Base case - if (!(block instanceof CalldataBlocks.Set)) { + if (!(block instanceof SetCalldataBlock)) { queue.pushBack(block); return queue; } @@ -55,7 +57,7 @@ abstract class BaseIterator implements Iterable { _.each(set.getMembers(), (member: CalldataBlock) => { // Traverse child if it is a unique pointer. // A pointer that is an alias for another pointer is ignored. - if (member instanceof CalldataBlocks.Pointer && _.isUndefined(member.getAlias())) { + if (member instanceof PointerCalldataBlock && _.isUndefined(member.getAlias())) { const dependency = member.getDependency(); queue.mergeBack(BaseIterator._createQueue(dependency)); } @@ -82,7 +84,7 @@ abstract class BaseIterator implements Iterable { } return { done: true, - value: new CalldataBlocks.Blob('', '', '', new Buffer('')), + value: new BlobCalldataBlock('', '', '', new Buffer('')), }; }, }; -- cgit v1.2.3 From 04503200e5eafda6617039b113ef26cf48184f62 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 28 Nov 2018 13:52:32 -0800 Subject: Linter / Prettier --- packages/utils/src/abi_encoder/calldata/blocks/pointer.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'packages/utils/src/abi_encoder/calldata') diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts index c706fe908..72d6a3173 100644 --- a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts +++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts @@ -24,8 +24,9 @@ export class PointerCalldataBlock extends CalldataBlock { } public toBuffer(): Buffer { - const destinationOffset = - !_.isUndefined(this._aliasFor) ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes(); + const destinationOffset = !_.isUndefined(this._aliasFor) + ? this._aliasFor.getOffsetInBytes() + : this._dependency.getOffsetInBytes(); const parentOffset = this._parent.getOffsetInBytes(); const parentHeaderSize = this._parent.getHeaderSizeInBytes(); const pointer: number = destinationOffset - (parentOffset + parentHeaderSize); -- cgit v1.2.3