Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 8826bf5

Browse files
authored
Merge pull request #1900 from trufflesuite/star-decode
Move from promise-based decoder that makes web3 calls to generator-based decoder that makes requests to caller
2 parents 9eb3a53 + 65967b4 commit 8826bf5

File tree

23 files changed

+310
-384
lines changed

23 files changed

+310
-384
lines changed

packages/truffle-debugger/lib/data/actions/index.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@ export function mapPathAndAssign(
4343
};
4444
}
4545

46-
export const MAP_KEY_DECODING = "MAP_KEY_DECODING";
47-
export function mapKeyDecoding(started) {
48-
return {
49-
type: MAP_KEY_DECODING,
50-
started
51-
};
52-
}
53-
5446
export const RESET = "DATA_RESET";
5547
export function reset() {
5648
return { type: RESET };

packages/truffle-debugger/lib/data/reducers.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ function assignments(state = DEFAULT_ASSIGNMENTS, action) {
156156
}
157157

158158
const DEFAULT_PATHS = {
159-
decodingStarted: 0,
160159
byAddress: {}
161160
};
162161

@@ -166,15 +165,6 @@ const DEFAULT_PATHS = {
166165
//which is fine, as that's all we need it for.
167166
function mappedPaths(state = DEFAULT_PATHS, action) {
168167
switch (action.type) {
169-
case actions.MAP_KEY_DECODING:
170-
debug(
171-
"decoding started: %d",
172-
state.decodingStarted + (action.started ? 1 : -1)
173-
);
174-
return {
175-
...state,
176-
decodingStarted: state.decodingStarted + (action.started ? 1 : -1)
177-
};
178168
case actions.MAP_PATH_AND_ASSIGN:
179169
let { address, slot, typeIdentifier, parentType } = action;
180170
//how this case works: first, we find the spot in our table (based on

packages/truffle-debugger/lib/data/sagas/index.js

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import debugModule from "debug";
22
const debug = debugModule("debugger:data:sagas");
33

4-
import { put, takeEvery, select, call } from "redux-saga/effects";
4+
import { put, takeEvery, select } from "redux-saga/effects";
55

66
import { prefixName, stableKeccak256, makeAssignment } from "lib/helpers";
77

@@ -19,7 +19,8 @@ import {
1919
getMemoryAllocations,
2020
getCalldataAllocations,
2121
readStack,
22-
storageSize
22+
storageSize,
23+
forEvmState
2324
} from "truffle-decoder";
2425
import BN from "bn.js";
2526

@@ -42,9 +43,48 @@ function* tickSaga() {
4243
yield* trace.signalTickSagaCompletion();
4344
}
4445

46+
export function* decode(definition, ref) {
47+
let referenceDeclarations = yield select(data.views.referenceDeclarations);
48+
let state = yield select(data.current.state);
49+
let mappingKeys = yield select(data.views.mappingKeys);
50+
let allocations = yield select(data.info.allocations);
51+
52+
let ZERO_WORD = new Uint8Array(DecodeUtils.EVM.WORD_SIZE);
53+
ZERO_WORD.fill(0);
54+
55+
let decoder = forEvmState(definition, ref, {
56+
referenceDeclarations,
57+
state,
58+
mappingKeys,
59+
storageAllocations: allocations.storage,
60+
memoryAllocations: allocations.memory,
61+
calldataAllocations: allocations.calldata
62+
});
63+
64+
let result = decoder.next();
65+
while (!result.done) {
66+
let request = result.value;
67+
let response;
68+
switch (request.type) {
69+
//yes, this is a little silly right now
70+
case "storage":
71+
//the debugger supplies all storage it knows at the beginning.
72+
//any storage it does not know is presumed to be zero.
73+
response = ZERO_WORD;
74+
break;
75+
default:
76+
debug("unrecognized request type!");
77+
}
78+
result = decoder.next(response);
79+
}
80+
//at this point, result.value holds the final value
81+
//note: we're still using the old decoder output format, so we need to clean
82+
//containers before returning something the debugger can use
83+
return DecodeUtils.Conversion.cleanContainers(result.value);
84+
}
85+
4586
function* variablesAndMappingsSaga() {
4687
let node = yield select(data.current.node);
47-
let decode = yield select(data.views.decoder);
4888
let scopes = yield select(data.views.scopes.inlined);
4989
let referenceDeclarations = yield select(data.views.referenceDeclarations);
5090
let allocations = yield select(data.info.allocations.storage);
@@ -267,7 +307,6 @@ function* variablesAndMappingsSaga() {
267307
//begin subsection: key decoding
268308
//(I tried factoring this out into its own saga but it didn't work when I
269309
//did :P )
270-
yield put(actions.mapKeyDecoding(true));
271310

272311
let indexValue;
273312
let indexDefinition = node.indexExpression;
@@ -291,7 +330,7 @@ function* variablesAndMappingsSaga() {
291330
//value will go on the stack *left*-padded instead of right-padded,
292331
//so looking for a prior assignment will read the wrong value.
293332
//so instead it's preferable to use the constant directly.
294-
indexValue = yield call(decode, keyDefinition, {
333+
indexValue = yield* decode(keyDefinition, {
295334
definition: indexDefinition
296335
});
297336
} else if (indexReference) {
@@ -311,7 +350,7 @@ function* variablesAndMappingsSaga() {
311350
} else {
312351
splicedDefinition = keyDefinition;
313352
}
314-
indexValue = yield call(decode, splicedDefinition, indexReference);
353+
indexValue = yield* decode(splicedDefinition, indexReference);
315354
} else if (
316355
indexDefinition.referencedDeclaration &&
317356
scopes[indexDefinition.referenceDeclaration]
@@ -333,7 +372,7 @@ function* variablesAndMappingsSaga() {
333372
if (
334373
DecodeUtils.Definition.isSimpleConstant(indexConstantDefinition)
335374
) {
336-
indexValue = yield call(decode, keyDefinition, {
375+
indexValue = yield* decode(keyDefinition, {
337376
definition: indexConstantDeclaration.value
338377
});
339378
}
@@ -362,7 +401,6 @@ function* variablesAndMappingsSaga() {
362401
//now, as mentioned, retry in the typeConversion case
363402
}
364403

365-
yield put(actions.mapKeyDecoding(false));
366404
//end subsection: key decoding
367405

368406
debug("index value %O", indexValue);

packages/truffle-debugger/lib/data/selectors/index.js

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import evm from "lib/evm/selectors";
1010
import solidity from "lib/solidity/selectors";
1111

1212
import * as DecodeUtils from "truffle-decode-utils";
13-
import { forEvmState } from "truffle-decoder";
1413

1514
/**
1615
* @private
@@ -120,33 +119,6 @@ const data = createSelectorTree({
120119
}
121120
},
122121

123-
/**
124-
* data.views.decoder
125-
*
126-
* selector returns (ast node definition, data reference) => Promise<value>
127-
*/
128-
decoder: createLeaf(
129-
[
130-
"/views/referenceDeclarations",
131-
"/current/state",
132-
"/views/mappingKeys",
133-
"/info/allocations"
134-
],
135-
136-
(referenceDeclarations, state, mappingKeys, allocations) => (
137-
definition,
138-
ref
139-
) =>
140-
forEvmState(definition, ref, {
141-
referenceDeclarations,
142-
state,
143-
mappingKeys,
144-
storageAllocations: allocations.storage,
145-
memoryAllocations: allocations.memory,
146-
calldataAllocations: allocations.calldata
147-
})
148-
),
149-
150122
/*
151123
* data.views.userDefinedTypes
152124
*/
@@ -717,30 +689,6 @@ const data = createSelectorTree({
717689
}
718690
)
719691
)
720-
),
721-
722-
/**
723-
* data.current.identifiers.decoded
724-
*
725-
* Returns an object with values as Promises
726-
*/
727-
decoded: createLeaf(
728-
["/views/decoder", "./definitions", "./refs"],
729-
730-
async (decode, definitions, refs) => {
731-
debug("setting up keyedPromises");
732-
const keyedPromises = Object.entries(refs).map(
733-
async ([identifier, ref]) => ({
734-
[identifier]: await decode(definitions[identifier], ref)
735-
})
736-
);
737-
debug("set up keyedPromises");
738-
const keyedResults = await Promise.all(keyedPromises);
739-
debug("got keyedResults");
740-
return DecodeUtils.Conversion.cleanContainers(
741-
Object.assign({}, ...keyedResults)
742-
);
743-
}
744692
)
745693
}
746694
},

packages/truffle-debugger/lib/session/index.js

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import configureStore from "lib/store";
66
import * as controller from "lib/controller/actions";
77
import * as actions from "./actions";
88
import data from "lib/data/selectors";
9+
import { decode } from "lib/data/sagas";
910
import controllerSelector from "lib/controller/selectors";
1011

1112
import rootSaga from "./sagas";
@@ -26,7 +27,9 @@ export default class Session {
2627
/**
2728
* @private
2829
*/
29-
this._store = configureStore(reducer, rootSaga);
30+
let { store, sagaMiddleware } = configureStore(reducer, rootSaga);
31+
this._store = store;
32+
this._sagaMiddleware = sagaMiddleware;
3033

3134
let { contexts, sources } = Session.normalize(contracts, files);
3235

@@ -145,6 +148,16 @@ export default class Session {
145148
return true;
146149
}
147150

151+
/**
152+
* @private
153+
* Allows running any saga -- for internal use only!
154+
* Using this could seriously screw up the debugger state if you
155+
* don't know what you're doing!
156+
*/
157+
async _runSaga(saga, ...args) {
158+
return await this._sagaMiddleware.run(saga, ...args).toPromise();
159+
}
160+
148161
async interrupt() {
149162
return this.dispatch(controller.interrupt());
150163
}
@@ -219,49 +232,29 @@ export default class Session {
219232
return this.dispatch(controller.removeAllBreakpoints());
220233
}
221234

235+
//deprecated -- decode is now *always* ready!
222236
async decodeReady() {
223-
return new Promise(resolve => {
224-
let haveResolved = false;
225-
const unsubscribe = this._store.subscribe(() => {
226-
const subscriptionDecodingStarted = this.view(data.proc.decodingKeys);
227-
228-
debug("following decoding started: %d", subscriptionDecodingStarted);
229-
230-
if (subscriptionDecodingStarted <= 0 && !haveResolved) {
231-
haveResolved = true;
232-
unsubscribe();
233-
resolve();
234-
}
235-
});
236-
237-
const decodingStarted = this.view(data.proc.decodingKeys);
238-
239-
debug("initial decoding started: %d", decodingStarted);
240-
241-
if (decodingStarted <= 0) {
242-
haveResolved = true;
243-
unsubscribe();
244-
resolve();
245-
}
246-
});
237+
return true;
247238
}
248239

249240
async variable(name) {
250-
await this.decodeReady();
251-
252241
const definitions = this.view(data.current.identifiers.definitions);
253242
const refs = this.view(data.current.identifiers.refs);
254243

255-
const decode = this.view(data.views.decoder);
256-
return await decode(definitions[name], refs[name]);
244+
return await this._runSaga(decode, definitions[name], refs[name]);
257245
}
258246

259247
async variables() {
260-
debug("awaiting decodeReady");
261-
await this.decodeReady();
262-
debug("decode now ready");
263-
264-
return await this.view(data.current.identifiers.decoded);
265-
debug("got variables");
248+
let definitions = this.view(data.current.identifiers.definitions);
249+
let refs = this.view(data.current.identifiers.refs);
250+
let decoded = {};
251+
for (let [identifier, ref] of Object.entries(refs)) {
252+
decoded[identifier] = await this._runSaga(
253+
decode,
254+
definitions[identifier],
255+
ref
256+
);
257+
}
258+
return decoded;
266259
}
267260
}

0 commit comments

Comments
 (0)