Home Reference Source

lib/data/selectors/index.js

  1. import debugModule from "debug";
  2. const debug = debugModule("debugger:data:selectors");
  3.  
  4. import { createSelectorTree, createLeaf } from "reselect-tree";
  5. import jsonpointer from "json-pointer";
  6.  
  7. import ast from "lib/ast/selectors";
  8. import evm from "lib/evm/selectors";
  9. import solidity from "lib/solidity/selectors";
  10.  
  11. import decode from "../decode";
  12. import * as decodeUtils from "../decode/utils";
  13.  
  14. import { BigNumber } from "bignumber.js";
  15.  
  16. function createStateSelectors({ stack, memory, storage }) {
  17. return {
  18. /**
  19. * .stack
  20. */
  21. stack: createLeaf(
  22. [stack],
  23.  
  24. (words) => (words || []).map(
  25. (word) => decodeUtils.toBytes(decodeUtils.toBigNumber(word, decodeUtils.WORD_SIZE))
  26. )
  27. ),
  28.  
  29. /**
  30. * .memory
  31. */
  32. memory: createLeaf(
  33. [memory],
  34.  
  35. (words) => new Uint8Array(
  36. (words.join("").match(/.{1,2}/g) || [])
  37. .map( (byte) => parseInt(byte, 16) )
  38. )
  39. ),
  40.  
  41. /**
  42. * .storage
  43. */
  44. storage: createLeaf(
  45. [storage],
  46.  
  47. (mapping) => Object.assign(
  48. {}, ...Object.entries(mapping).map( ([ address, word ]) =>
  49. ({
  50. [`0x${address}`]: new Uint8Array(
  51. (word.match(/.{1,2}/g) || [])
  52. .map( (byte) => parseInt(byte, 16) )
  53. )
  54. })
  55. )
  56. )
  57. )
  58. };
  59. }
  60.  
  61. const data = createSelectorTree({
  62. state: (state) => state.data,
  63.  
  64. /**
  65. * data.views
  66. */
  67. views: {
  68. ast: createLeaf(
  69. [ast.current], (tree) => tree
  70. ),
  71.  
  72. atLastInstructionForSourceRange: createLeaf(
  73. [solidity.current.isSourceRangeFinal], (final) => final
  74. ),
  75.  
  76. /**
  77. * data.views.scopes
  78. */
  79. scopes: {
  80.  
  81. /**
  82. * data.views.scopes.inlined
  83. */
  84. inlined: createLeaf(
  85. ["/info/scopes", solidity.info.sources],
  86.  
  87. (scopes, sources) => Object.assign({},
  88. ...Object.entries(scopes).map(
  89. ([id, entry]) => ({
  90. [id]: {
  91. ...entry,
  92.  
  93. definition: jsonpointer.get(
  94. sources[entry.sourceId].ast, entry.pointer
  95. )
  96. }
  97. })
  98. )
  99. )
  100. )
  101. },
  102.  
  103. /**
  104. * data.views.decoder
  105. *
  106. * selector returns (ast node definition, data reference) => value
  107. */
  108. decoder: createLeaf(
  109. ["/views/scopes/inlined", "/current/state"],
  110.  
  111. (scopes, state) => {
  112. return (definition, ref) => decode(definition, ref, state, scopes)
  113. }
  114. )
  115. },
  116.  
  117. /**
  118. * data.info
  119. */
  120. info: {
  121.  
  122. /**
  123. * data.info.scopes
  124. */
  125. scopes: createLeaf(["/state"], (state) => state.info.scopes.byId)
  126. },
  127.  
  128. /**
  129. * data.proc
  130. */
  131. proc: {
  132.  
  133. /**
  134. * data.proc.assignments
  135. */
  136. assignments: createLeaf(["/state"], (state) => state.proc.assignments.byId)
  137. },
  138.  
  139. /**
  140. * data.current
  141. */
  142. current: {
  143. /**
  144. *
  145. * data.current.scope
  146. */
  147. scope: {
  148.  
  149. /**
  150. * data.current.scope.id
  151. */
  152. id: createLeaf(
  153. [ast.current.node], (node) => node.id
  154. )
  155. },
  156.  
  157. /**
  158. * data.current.state
  159. */
  160. state: createStateSelectors(evm.current.state),
  161.  
  162. /**
  163. * data.current.identifiers (namespace)
  164. */
  165. identifiers: {
  166.  
  167. /**
  168. * data.current.identifiers (selector)
  169. *
  170. * returns identifers and corresponding definition node ID
  171. */
  172. _: createLeaf(
  173. [
  174. "/views/scopes/inlined",
  175. "/current/scope",
  176. ],
  177.  
  178. (scopes, scope) => {
  179. let cur = scope.id;
  180. let variables = {};
  181.  
  182. do {
  183. variables = Object.assign(
  184. variables,
  185. ...(scopes[cur].variables || [])
  186. .filter( (v) => variables[v.name] == undefined )
  187. .map( (v) => ({ [v.name]: v.id }) )
  188. );
  189.  
  190. cur = scopes[cur].parentId;
  191. } while (cur != null);
  192.  
  193. return variables;
  194. }
  195. ),
  196.  
  197. /**
  198. * data.current.identifiers.definitions
  199. *
  200. * current variable definitions
  201. */
  202. definitions: createLeaf(
  203. [
  204. "/views/scopes/inlined",
  205. "./_"
  206. ],
  207.  
  208. (scopes, identifiers) => Object.assign({},
  209. ...Object.entries(identifiers)
  210. .map( ([identifier, id]) => {
  211. let { definition } = scopes[id];
  212.  
  213. return { [identifier]: definition };
  214. })
  215. )
  216. ),
  217.  
  218. /**
  219. * data.current.identifiers.refs
  220. *
  221. * current variables' value refs
  222. */
  223. refs: createLeaf(
  224. [
  225. "/proc/assignments",
  226. "./_"
  227. ],
  228.  
  229. (assignments, identifiers) => Object.assign({},
  230. ...Object.entries(identifiers)
  231. .map( ([identifier, id]) => {
  232. let { ref } = (assignments[id] || {})
  233. if (!ref) { return undefined };
  234.  
  235. return {
  236. [identifier]: ref
  237. };
  238. })
  239. )
  240. ),
  241.  
  242. decoded: createLeaf(
  243. [
  244. "/views/decoder",
  245. "./definitions",
  246. "./refs",
  247. ],
  248.  
  249. (decode, definitions, refs) => Object.assign({},
  250. ...Object.entries(refs)
  251. .map( ([identifier, ref]) => ({
  252. [identifier]: decode(definitions[identifier], ref)
  253. }) )
  254. )
  255. ),
  256.  
  257. native: createLeaf(['./decoded'], decodeUtils.cleanBigNumbers)
  258. }
  259. },
  260.  
  261. /**
  262. * data.next
  263. */
  264. next: {
  265.  
  266. /**
  267. * data.next.state
  268. */
  269. state: createStateSelectors(evm.next.state)
  270. }
  271. });
  272.  
  273. export default data;