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

Commit

Permalink
Merge pull request #5286 from trufflesuite/panopticon
Browse files Browse the repository at this point in the history
Enhancement: Add `debug_storageRangeAt` integration to debugger library
  • Loading branch information
haltman-at committed Jul 14, 2022
2 parents c8b96f4 + 17ba791 commit 962ba25
Show file tree
Hide file tree
Showing 15 changed files with 605 additions and 112 deletions.
75 changes: 24 additions & 51 deletions packages/debugger/lib/data/sagas/index.js
Expand Up @@ -12,9 +12,8 @@ import {

import { TICK } from "lib/trace/actions";
import * as actions from "../actions";
import * as trace from "lib/trace/sagas";
import * as evm from "lib/evm/sagas";
import * as web3 from "lib/web3/sagas";
import * as trace from "lib/trace/sagas";

import data from "../selectors";

Expand Down Expand Up @@ -748,11 +747,22 @@ function* variablesAndMappingsSaga() {

function* decodeMappingKeySaga(indexDefinition, keyDefinition) {
//something of a HACK -- cleans any out-of-range booleans
//resulting from the main mapping key decoding loop
const indexValue = yield* decodeMappingKeyCore(
indexDefinition,
keyDefinition
);
//resulting from the main mapping key decoding loop,
//and also filters out errors
let indexValue = yield* decodeMappingKeyCore(indexDefinition, keyDefinition);
if (indexValue) {
indexValue = Codec.Conversion.cleanBool(indexValue);
switch (indexValue.kind) {
case "value":
return indexValue;
case "error":
//if it's still an error after cleaning booleans...
//let's not store it as a mapping key
return null;
}
} else {
return indexValue;
}
return indexValue ? Codec.Conversion.cleanBool(indexValue) : indexValue;
}

Expand Down Expand Up @@ -1029,12 +1039,7 @@ function fetchBasePath(
return null;
}

export function* decode(
definition,
ref,
compilationId,
indicateUnknown = false
) {
export function* decode(definition, ref, compilationId) {
const userDefinedTypes = yield select(data.views.userDefinedTypes);
const state = yield select(data.current.state);
const mappingKeys = yield select(data.views.mappingKeys);
Expand All @@ -1049,8 +1054,6 @@ export function* decode(
debug("ref: %o");
debug("compilationId: %s", compilationId);

const ZERO_WORD = new Uint8Array(Codec.Evm.Utils.WORD_SIZE); //automatically filled with zeroes

const decoder = Codec.decodeVariable(
definition,
ref,
Expand All @@ -1074,19 +1077,16 @@ export function* decode(
let response;
switch (request.type) {
case "storage":
//the debugger supplies all storage it knows at the beginning.
//any storage it does not know is presumed to be zero.
//(unlesss indicateUnknown is passed, in which case we use
//null as a deliberately invalid response)
response = indicateUnknown ? null : ZERO_WORD;
response = yield* evm.requestStorage(request.slot);
break;
case "code":
response = yield* requestCode(request.address);
response = yield* evm.requestCode(request.address);
break;
default:
debug("unrecognized request type!");
}
debug("sending response");
debug("response: %O", response);
result = decoder.next(response);
}
//at this point, result.value holds the final value
Expand Down Expand Up @@ -1132,7 +1132,7 @@ export function* decodeReturnValue() {
switch (request.type) {
//skip storage case, it won't happen here
case "code":
response = yield* requestCode(request.address);
response = yield* evm.requestCode(request.address);
break;
default:
debug("unrecognized request type!");
Expand Down Expand Up @@ -1197,7 +1197,7 @@ export function* decodeCall(decodeCurrent = false) {
switch (request.type) {
//skip storage case, it won't happen here
case "code":
response = yield* requestCode(request.address);
response = yield* evm.requestCode(request.address);
break;
default:
debug("unrecognized request type!");
Expand Down Expand Up @@ -1245,7 +1245,7 @@ export function* decodeLog() {
switch (request.type) {
//skip storage case, it won't happen here
case "code":
response = yield* requestCode(request.address);
response = yield* evm.requestCode(request.address);
break;
default:
debug("unrecognized request type!");
Expand All @@ -1259,33 +1259,6 @@ export function* decodeLog() {
return result.value;
}

//NOTE: calling this *can* add a new instance, which will not
//go away on a reset! Yes, this is a little weird, but we
//decided this is OK for now
function* requestCode(address) {
const NO_CODE = new Uint8Array(); //empty array
const blockNumber = yield select(data.views.blockNumber);
const instances = yield select(data.views.instances);

if (address in instances) {
return instances[address];
} else if (address === Codec.Evm.Utils.ZERO_ADDRESS) {
//HACK: to avoid displaying the zero address to the user as an
//affected address just because they decoded a contract or external
//function variable that hadn't been initialized yet, we give the
//zero address's codelessness its own private cache :P
return NO_CODE;
} else {
//I don't want to write a new web3 saga, so let's just use
//obtainBinaries with a one-element array
debug("fetching binary");
let binary = (yield* web3.obtainBinaries([address], blockNumber))[0];
debug("adding instance");
yield* evm.addInstance(address, binary);
return Codec.Conversion.toBytes(binary);
}
}

export function* reset() {
yield put(actions.reset());
}
Expand Down
16 changes: 13 additions & 3 deletions packages/debugger/lib/data/selectors/index.js
Expand Up @@ -373,15 +373,25 @@ const data = createSelectorTree({
.filter(slot => slot.key !== undefined)
),

/*
/**
* data.views.blockNumber
* returns block number as string
*/
blockNumber: createLeaf([evm.transaction.globals.block], block =>
block.number.toString()
),

/*
/**
* data.views.blockHash
*/
blockHash: createLeaf([evm.transaction.blockHash], identity),

/**
* data.views.txIndex
*/
txIndex: createLeaf([evm.transaction.txIndex], identity),

/**
* data.views.instances
* same as evm.current.codex.instances, but we just map address => binary,
* we don't bother with context, and also the code is a Uint8Array
Expand All @@ -395,7 +405,7 @@ const data = createSelectorTree({
)
),

/*
/**
* data.views.contexts
* same as evm.info.contexts, but:
* 1. we strip out fields irrelevant to codec
Expand Down
14 changes: 11 additions & 3 deletions packages/debugger/lib/debugger.js
Expand Up @@ -28,11 +28,17 @@ const Debugger = {
* @return {Debugger} instance
*/
forTx: async function (txHash, options = {}) {
let { contracts, files, provider, compilations, lightMode } = options;
let { contracts, files, provider, compilations, lightMode, storageLookup } =
options;
if (!compilations) {
compilations = Compilations.Utils.shimArtifacts(contracts, files);
}
let session = new Session(compilations, provider, { lightMode }, txHash);
let session = new Session(
compilations,
provider,
{ lightMode, storageLookup },
txHash
);

await session.ready();

Expand All @@ -50,7 +56,9 @@ const Debugger = {
if (!compilations) {
compilations = Compilations.Utils.shimArtifacts(contracts, files);
}
let session = new Session(compilations, provider, { lightMode });
let session = new Session(compilations, provider, {
lightMode
});

await session.ready();

Expand Down
25 changes: 25 additions & 0 deletions packages/debugger/lib/evm/actions/index.js
Expand Up @@ -53,6 +53,15 @@ export function saveGlobals(origin, gasprice, block) {
};
}

export const SAVE_TX_IDENTIFICATION = "EVM_SAVE_TX_IDENTIFICATION";
export function saveTxIdentification(blockHash, txIndex) {
return {
type: SAVE_TX_IDENTIFICATION,
blockHash,
txIndex
};
}

export const SAVE_STATUS = "EVM_SAVE_STATUS";
export function saveStatus(status) {
return {
Expand Down Expand Up @@ -142,3 +151,19 @@ export function unloadTransaction() {
type: UNLOAD_TRANSACTION
};
}

export const SET_STORAGE_LOOKUP = "EVM_SET_STORAGE_LOOKUP";
export function setStorageLookup(status) {
return {
type: SET_STORAGE_LOOKUP,
status
};
}

export const SET_STORAGE_LOOKUP_SUPPORT = "EVM_SET_STORAGE_LOOKUP_SUPPORT";
export function setStorageLookupSupport(status) {
return {
type: SET_STORAGE_LOOKUP_SUPPORT,
status
};
}
52 changes: 51 additions & 1 deletion packages/debugger/lib/evm/reducers.js
Expand Up @@ -87,6 +87,33 @@ const globals = combineReducers({
block
});

function blockHash(state = null, action) {
switch (action.type) {
case actions.SAVE_TX_IDENTIFICATION:
return action.blockHash;
case actions.UNLOAD_TRANSACTION:
return null;
default:
return state;
}
}

function txIndex(state = null, action) {
switch (action.type) {
case actions.SAVE_TX_IDENTIFICATION:
return action.txIndex;
case actions.UNLOAD_TRANSACTION:
return null;
default:
return state;
}
}

const txIdentification = combineReducers({
blockHash,
txIndex
});

function status(state = null, action) {
switch (action.type) {
case actions.SAVE_STATUS:
Expand Down Expand Up @@ -145,6 +172,7 @@ function affectedInstances(state = DEFAULT_AFFECTED_INSTANCES, action) {

const transaction = combineReducers({
globals,
txIdentification,
status,
initialCall,
affectedInstances
Expand Down Expand Up @@ -404,10 +432,32 @@ const proc = combineReducers({
codex
});

function storageLookup(state = null, action) {
if (action.type === actions.SET_STORAGE_LOOKUP) {
return Boolean(action.status); //force Boolean to prevent undefined
} else {
return state;
}
}

function storageLookupSupported(state = null, action) {
if (action.type === actions.SET_STORAGE_LOOKUP_SUPPORT) {
return action.status;
} else {
return state;
}
}

const application = combineReducers({
storageLookupSupported,
storageLookup
});

const reducer = combineReducers({
info,
transaction,
proc
proc,
application
});

export default reducer;

0 comments on commit 962ba25

Please sign in to comment.