1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
/* 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 implements Iterable<CalldataBlock> {
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 [Symbol.iterator](): { next: () => IteratorResult<CalldataBlock> } {
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 {
public constructor(root: CalldataBlock) {
super(root);
}
public nextBlock(): CalldataBlock | undefined {
return this._queue.popFront();
}
}
export class ReverseCalldataIterator extends BaseIterator {
public constructor(root: CalldataBlock) {
super(root);
}
public nextBlock(): CalldataBlock | undefined {
return this._queue.popBack();
}
}
|