aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils/src/abi_encoder/calldata
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/calldata
parent9a51af46ee4a35b3d1ce2fcdc6f561aa68307cf0 (diff)
downloaddexon-sol-tools-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar
dexon-sol-tools-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.gz
dexon-sol-tools-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.bz2
dexon-sol-tools-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.lz
dexon-sol-tools-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.xz
dexon-sol-tools-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.tar.zst
dexon-sol-tools-8f73f53c95d8ba887558863b8b726a2b3f5b7e2b.zip
Moved calldata iterator logic into its own iterator clas
Diffstat (limited to 'packages/utils/src/abi_encoder/calldata')
-rw-r--r--packages/utils/src/abi_encoder/calldata/calldata.ts56
-rw-r--r--packages/utils/src/abi_encoder/calldata/iterator.ts94
2 files changed, 104 insertions, 46 deletions
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();
+ }
+}