aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils/src/abi_encoder
diff options
context:
space:
mode:
authorGreg Hysen <greg.hysen@gmail.com>2018-11-26 12:05:41 +0800
committerGreg Hysen <greg.hysen@gmail.com>2018-11-29 08:38:11 +0800
commit8f73f53c95d8ba887558863b8b726a2b3f5b7e2b (patch)
treed819b2412b59e484fffea54701f5441108ce122d /packages/utils/src/abi_encoder
parent9a51af46ee4a35b3d1ce2fcdc6f561aa68307cf0 (diff)
downloaddexon-0x-contracts-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar
dexon-0x-contracts-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.gz
dexon-0x-contracts-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.bz2
dexon-0x-contracts-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.lz
dexon-0x-contracts-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.xz
dexon-0x-contracts-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.zst
dexon-0x-contracts-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.zip
Moved calldata iterator logic into its own iterator clas
Diffstat (limited to 'packages/utils/src/abi_encoder')
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts8
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts21
-rw-r--r--packages/utils/src/abi_encoder/calldata/calldata.ts56
-rw-r--r--packages/utils/src/abi_encoder/calldata/iterator.ts94
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types/pointer.ts2
5 files changed, 119 insertions, 62 deletions
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
index f4246c893..35ccc0586 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts
@@ -8,11 +8,11 @@ import { DataType } from '../data_type';
import { DataTypeFactory } from '../interfaces';
export abstract class Blob extends DataType {
- protected _hasConstantSize: boolean;
+ protected _sizeKnownAtCompileTime: boolean;
- public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
+ public constructor(dataItem: DataItem, factory: DataTypeFactory, sizeKnownAtCompileTime: boolean) {
super(dataItem, factory);
- this._hasConstantSize = hasConstantSize;
+ this._sizeKnownAtCompileTime = sizeKnownAtCompileTime;
}
public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Blob {
@@ -30,7 +30,7 @@ export abstract class Blob extends DataType {
}
public isStatic(): boolean {
- return this._hasConstantSize;
+ return this._sizeKnownAtCompileTime;
}
public abstract encodeValue(value: any): Buffer;
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
index 47efac521..46e60979a 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts
@@ -1,3 +1,4 @@
+/* tslint:disable prefer-function-over-method */
import { DataItem } from 'ethereum-types';
import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
@@ -10,26 +11,24 @@ import { DataType } from '../data_type';
import { DataTypeFactory } from '../interfaces';
export abstract class Pointer extends DataType {
- protected _dependency: DataType;
+ protected _destination: DataType;
protected _parent: DataType;
- private readonly _isStatic: boolean;
- public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
+ public constructor(dataItem: DataItem, factory: DataTypeFactory, destination: DataType, parent: DataType) {
super(dataItem, factory);
- this._dependency = dependency;
+ this._destination = destination;
this._parent = parent;
- this._isStatic = true;
}
public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Pointer {
- if (parentBlock === undefined) {
+ if (!parentBlock) {
throw new Error(`DependentDataType requires a parent block to generate its block`);
}
- const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
+ const destinationBlock = this._destination.generateCalldataBlock(value, parentBlock);
const name = this.getDataItem().name;
const signature = this.getSignature();
- const parentName = parentBlock ? parentBlock.getName() : '';
- const block = new CalldataBlocks.Pointer(name, signature, parentName, dependencyBlock, parentBlock);
+ const parentName = parentBlock.getName();
+ const block = new CalldataBlocks.Pointer(name, signature, parentName, destinationBlock, parentBlock);
return block;
}
@@ -40,12 +39,12 @@ export abstract class Pointer extends DataType {
const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
const currentOffset = calldata.getOffset();
calldata.setOffset(destinationOffsetAbsolute);
- const value = this._dependency.generateValue(calldata, rules);
+ const value = this._destination.generateValue(calldata, rules);
calldata.setOffset(currentOffset);
return value;
}
public isStatic(): boolean {
- return this._isStatic;
+ return true;
}
}
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<CalldataBlock> {
- const blockQueue = new Queue<CalldataBlock>();
-
- // 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<CalldataBlock>;
+
+ private static _createQueue(block: CalldataBlock): Queue<CalldataBlock> {
+ const queue = new Queue<CalldataBlock>();
+ // 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();
+ }
+}
diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
index 00c743d2b..e7c172afb 100644
--- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts
@@ -10,6 +10,6 @@ export class Pointer extends AbstractDataTypes.Pointer {
}
public getSignature(): string {
- return this._dependency.getSignature();
+ return this._destination.getSignature();
}
}