diff --git a/packages/analyzer/src/txAnalyzer.ts b/packages/analyzer/src/txAnalyzer.ts index 5ae8d042..6da04c50 100644 --- a/packages/analyzer/src/txAnalyzer.ts +++ b/packages/analyzer/src/txAnalyzer.ts @@ -40,25 +40,12 @@ export class TxAnalyzer { for (const address of contractsAddresses) { const structLogsForAddress = getStructLogsForContractAddress(traceLogs, structlogs, address) - const dissasembleBytecode = this.dataLoader.analyzerContractData.get(address, 'disassembledBytecode') - - // eslint-disable-next-line - const SOLC_BYTECODE_FLAG = true - - if (SOLC_BYTECODE_FLAG) { - const isContractVerified = this.dataLoader.isContractVerified(address) - if (!isContractVerified) continue - } + const dissasembleBytecode = this.dataLoader.analyzerContractData.get(address, 'disassembledEtherscanBytecode') structLogsForAddress.forEach((structLog: TIndexedStructLog) => { - try { - const operand = dissasembleBytecode[structLog?.pc]?.value || undefined - if (operand) { - structlogs[structLog.index].operand = operand - } - } catch (error) { - console.log(address) - // console.error('Error while extending struct logs with operand values', error) + const operand = dissasembleBytecode[structLog.pc]?.value || undefined + if (operand) { + structlogs[structLog.index].operand = operand } }) } diff --git a/packages/analyzer/src/utils/dataLoader.ts b/packages/analyzer/src/utils/dataLoader.ts index 88ba0219..c906106f 100644 --- a/packages/analyzer/src/utils/dataLoader.ts +++ b/packages/analyzer/src/utils/dataLoader.ts @@ -181,8 +181,8 @@ export class DataLoader { ), contractsDisassembledBytecodes: Object.values(this.analyzerData.contracts).reduce< TAnalyzerAnalysisOutput['contractsDisassembledBytecodes'] - >((accumulator, { address, disassembledBytecode }) => { - accumulator[address] = { disassembledBytecode, address } + >((accumulator, { address, disassembledEtherscanBytecode }) => { + accumulator[address] = { disassembledBytecode: disassembledEtherscanBytecode, address } return accumulator }, {}), contractsBaseData: Object.values(this.analyzerData.contracts).reduce( diff --git a/packages/analyzer/src/utils/functionManager.ts b/packages/analyzer/src/utils/functionManager.ts index 7f5049d0..99677986 100644 --- a/packages/analyzer/src/utils/functionManager.ts +++ b/packages/analyzer/src/utils/functionManager.ts @@ -121,7 +121,7 @@ export class FunctionManager { const initialContractFunctions = this.dataLoader.analyzerContractData.get(contractAddress, 'functions') const contractFunctions: Record = { ...initialContractFunctions } - const dissasembledBytecode = this.dataLoader.analyzerContractData.get(contractAddress, 'disassembledBytecode') + const dissasembledBytecode = this.dataLoader.analyzerContractData.get(contractAddress, 'disassembledEtherscanBytecode') const contractSourceFiles = this.dataLoader.analyzerContractData.get(contractAddress, 'sourceFiles') const contractInstructions = this.dataLoader.analyzerContractData.get(contractAddress, 'instructions') diff --git a/packages/analyzer/src/utils/sourceLineParser.ts b/packages/analyzer/src/utils/sourceLineParser.ts index 3c47fc08..e6f228f0 100644 --- a/packages/analyzer/src/utils/sourceLineParser.ts +++ b/packages/analyzer/src/utils/sourceLineParser.ts @@ -68,7 +68,7 @@ export class SourceLineParser { const uniqueSoruceMapsCodeLinesDictionary = createSourceMapToSourceCodeDictionary(contractSourceFiles, uniqueSourceMaps) - const disassembledBytecode = this.dataLoader.analyzerContractData.get(contractAddress, 'disassembledBytecode') + const disassembledBytecode = this.dataLoader.analyzerContractData.get(contractAddress, 'disassembledEtherscanBytecode') const mapDisasemlbedBytecodeToIndex = Object.values(disassembledBytecode).reduce>( (accumulator, disassembledBytecodeEntry, index) => { diff --git a/packages/frontend/src/store/analyzer/saga/initializeTransactionProcessing/initializeTransactionProcessing.saga.spec.ts b/packages/frontend/src/store/analyzer/saga/initializeTransactionProcessing/initializeTransactionProcessing.saga.spec.ts index 026a96f5..4b5a18e0 100644 --- a/packages/frontend/src/store/analyzer/saga/initializeTransactionProcessing/initializeTransactionProcessing.saga.spec.ts +++ b/packages/frontend/src/store/analyzer/saga/initializeTransactionProcessing/initializeTransactionProcessing.saga.spec.ts @@ -1,6 +1,7 @@ import { expectSaga } from 'redux-saga-test-plan' import { ChainId } from '@evm-debuger/types' import { combineReducers } from 'redux' +import * as matchers from 'redux-saga-test-plan/matchers' import { transactionConfigActions, transactionConfigReducer } from '../../../transactionConfig/transactionConfig.slice' import { analyzerActions, analyzerReducer } from '../../analyzer.slice' @@ -11,10 +12,11 @@ import { AnalyzerStages, AnalyzerStagesStatus } from '../../analyzer.const' import { createInfoLogMessage, createSuccessLogMessage } from '../../analyzer.utils' import { createLogMessageActionForTests, mockLogsInAnalyer, testLogMessages } from '../../../../helpers/sagaTests' -import { initializeTransactionProcessingSaga } from './initializeTransactionProcessing.saga' +import { estimateGasUsage, initializeTransactionProcessingSaga } from './initializeTransactionProcessing.saga' const TRANSACTION_HASH = '0x1234567890' const CHAIN_ID = ChainId.mainnet +const GAS_USED = BigInt(1000) describe('initializeTransactionProcessingSaga', () => { it('should initialize transaction processing', async () => { @@ -46,7 +48,7 @@ describe('initializeTransactionProcessingSaga', () => { [StoreKeys.TRANSACTION_CONFIG]: { ...initialState[StoreKeys.TRANSACTION_CONFIG], transactionHash: TRANSACTION_HASH, - gasUsed: '100000', + gasUsed: GAS_USED.toString(), chainId: CHAIN_ID, }, } @@ -56,13 +58,15 @@ describe('initializeTransactionProcessingSaga', () => { analyzerActions.initializeTransactionProcessing({ transactionHash: TRANSACTION_HASH, chainId: CHAIN_ID }), ) .withReducer(combineReducers({ [StoreKeys.TRANSACTION_CONFIG]: transactionConfigReducer, [StoreKeys.ANALYZER]: analyzerReducer })) + .provide([[matchers.call.fn(estimateGasUsage), BigInt(1000)]]) .withState(initialState) .put(analyzerActions.updateStage(inProgresStage)) .put.like({ action: addFirstLogAction }) .put(transactionConfigActions.setChainId({ chainId: CHAIN_ID })) .put(transactionConfigActions.setTransactionHash({ transactionHash: TRANSACTION_HASH })) .put.like({ action: addSecondLogAction }) - .put(transactionConfigActions.setGasUsed({ gasUsed: '100000' })) + .call(estimateGasUsage, CHAIN_ID, TRANSACTION_HASH) + .put(transactionConfigActions.setGasUsed({ gasUsed: GAS_USED.toString() })) .put(analyzerActions.updateStage(successStage)) .put.like({ action: addThirdLogAction }) .run() diff --git a/packages/frontend/src/store/analyzer/saga/initializeTransactionProcessing/initializeTransactionProcessing.saga.ts b/packages/frontend/src/store/analyzer/saga/initializeTransactionProcessing/initializeTransactionProcessing.saga.ts index ebd34f5b..fff94cb4 100644 --- a/packages/frontend/src/store/analyzer/saga/initializeTransactionProcessing/initializeTransactionProcessing.saga.ts +++ b/packages/frontend/src/store/analyzer/saga/initializeTransactionProcessing/initializeTransactionProcessing.saga.ts @@ -37,13 +37,13 @@ export function* initializeTransactionProcessingSaga({ yield* put(analyzerActions.addLogMessage(createInfoLogMessage('Calculating gas usage of transaction'))) - // const gasUsed = yield* call(estimateGasUsage, chainId, transactionHash) + const gasUsed = yield* call(estimateGasUsage, chainId, transactionHash) - // if (gasUsed > BigInt(2000000)) { - // throw new Error(`Currently, we do not support transactions with over 2 milion gas usage. Your transaction used ${gasUsed} gas`) - // } + if (gasUsed > BigInt(2000000)) { + throw new Error(`Currently, we do not support transactions with over 2 milion gas usage. Your transaction used ${gasUsed} gas`) + } - yield* put(transactionConfigActions.setGasUsed({ gasUsed: '100000' })) + yield* put(transactionConfigActions.setGasUsed({ gasUsed: gasUsed.toString() })) yield* put(analyzerActions.updateStage({ stageStatus: AnalyzerStagesStatus.SUCCESS, stageName: AnalyzerStages.INITIALIZING_ANALYZER })) yield* put(analyzerActions.addLogMessage(createSuccessLogMessage('Analyzer initialized'))) diff --git a/packages/frontend/src/store/contractRaw/saga/fetchBytecodes/fetchBytecodes.saga.spec.ts b/packages/frontend/src/store/contractRaw/saga/fetchBytecodes/fetchBytecodes.saga.spec.ts new file mode 100644 index 00000000..2ff08537 --- /dev/null +++ b/packages/frontend/src/store/contractRaw/saga/fetchBytecodes/fetchBytecodes.saga.spec.ts @@ -0,0 +1,81 @@ +import { expectSaga } from 'redux-saga-test-plan' +import * as matchers from 'redux-saga-test-plan/matchers' +import { ChainId } from '@evm-debuger/types' +import { combineReducers } from 'redux' + +import { transactionConfigReducer } from '../../../transactionConfig/transactionConfig.slice' +import { analyzerActions, analyzerReducer } from '../../../analyzer/analyzer.slice' +import { TransactionConfigState } from '../../../transactionConfig/transactionConfig.state' +import { AnalyzerState, analyzerStagesAdapter } from '../../../analyzer/analyzer.state' +import { StoreKeys } from '../../../store.keys' +import { AnalyzerStages, AnalyzerStagesStatus } from '../../../analyzer/analyzer.const' +import { createInfoLogMessage, createSuccessLogMessage, getAnalyzerInstance } from '../../../analyzer/analyzer.utils' +import { createLogMessageActionForTests, mockLogsInAnalyer, testLogMessages } from '../../../../helpers/sagaTests' +import { createMockedContractBase } from '../../../contractBase/contractBase.mock' +import { contractBaseAdapter, contractBaseReducer } from '../../../contractBase/contractBase.slice' +import { createMockedContractRawData } from '../../contractRaw.mock' + +import { fetchBytecode, fetchBytecodesSaga } from './fetchBytecodes.saga' + +const TRANSACTION_HASH = '0x1234567890' +const CHAIN_ID = ChainId.mainnet + +const mockedContractBase = createMockedContractBase() +const mockedContractRaw = createMockedContractRawData(mockedContractBase.address) +describe('fetchBytecodesSaga', () => { + it('should fetch bytecodes', async () => { + const analyzerInstance = getAnalyzerInstance() + analyzerInstance.dataLoader.setEmptyContracts([mockedContractBase.address]) + + const initialState = { + [StoreKeys.TRANSACTION_CONFIG]: { ...new TransactionConfigState(), transactionHash: TRANSACTION_HASH, chainId: CHAIN_ID }, + [StoreKeys.CONTRACT_BASE]: contractBaseAdapter.addOne(contractBaseAdapter.getInitialState(), mockedContractBase), + [StoreKeys.ANALYZER]: { ...new AnalyzerState() }, + } + + const inProgresStage = { stageStatus: AnalyzerStagesStatus.IN_PROGRESS, stageName: AnalyzerStages.FETCHING_BYTECODES } + const successStage = { stageStatus: AnalyzerStagesStatus.SUCCESS, stageName: AnalyzerStages.FETCHING_BYTECODES } + + const firstLogMessage = createInfoLogMessage('Fetching bytecodes') + const secondLogMessage = createSuccessLogMessage('Fetching bytecodes success') + + const addFirstLogAction = createLogMessageActionForTests(analyzerActions.addLogMessage(firstLogMessage)) + const addSecondLogAction = createLogMessageActionForTests(analyzerActions.addLogMessage(secondLogMessage)) + + const expectedState = { + ...initialState, + [StoreKeys.ANALYZER]: { + ...initialState[StoreKeys.ANALYZER], + stages: analyzerStagesAdapter.updateOne(initialState[StoreKeys.ANALYZER].stages, { + id: AnalyzerStages.FETCHING_BYTECODES, + changes: successStage, + }), + logMessages: mockLogsInAnalyer(), + }, + } + + const { storeState } = await expectSaga(fetchBytecodesSaga) + .withReducer( + combineReducers({ + [StoreKeys.TRANSACTION_CONFIG]: transactionConfigReducer, + [StoreKeys.ANALYZER]: analyzerReducer, + [StoreKeys.CONTRACT_BASE]: contractBaseReducer, + }), + ) + .withState(initialState) + .provide([ + [matchers.call.fn(fetchBytecode), mockedContractRaw.etherscanBytecode], + [matchers.call.fn(getAnalyzerInstance), analyzerInstance], + ]) + .put.like({ action: addFirstLogAction }) + .put(analyzerActions.updateStage(inProgresStage)) + .call(getAnalyzerInstance) + .call(fetchBytecode, CHAIN_ID, mockedContractBase.address) + .put(analyzerActions.updateStage(successStage)) + .put.like({ action: addSecondLogAction }) + .run() + + expect(storeState).toEqual(expectedState) + testLogMessages(storeState[StoreKeys.ANALYZER], [firstLogMessage, secondLogMessage]) + }) +}) diff --git a/packages/frontend/src/store/contractRaw/saga/fetchBytecodes/fetchBytecodes.saga.ts b/packages/frontend/src/store/contractRaw/saga/fetchBytecodes/fetchBytecodes.saga.ts index 5f12f7da..4c17952d 100644 --- a/packages/frontend/src/store/contractRaw/saga/fetchBytecodes/fetchBytecodes.saga.ts +++ b/packages/frontend/src/store/contractRaw/saga/fetchBytecodes/fetchBytecodes.saga.ts @@ -1,11 +1,13 @@ /* eslint-disable no-return-await */ -import { type SagaGenerator, put, call } from 'typed-redux-saga' +import { select, type SagaGenerator, put, call, apply } from 'typed-redux-saga' import type { ChainId } from '@evm-debuger/types' import { jsonRpcProvider } from '../../../../config' +import { transactionConfigSelectors } from '../../../transactionConfig/transactionConfig.selectors' import { analyzerActions } from '../../../analyzer/analyzer.slice' import { AnalyzerStages, AnalyzerStagesStatus } from '../../../analyzer/analyzer.const' -import { createInfoLogMessage, createSuccessLogMessage } from '../../../analyzer/analyzer.utils' +import { createInfoLogMessage, createSuccessLogMessage, getAnalyzerInstance } from '../../../analyzer/analyzer.utils' +import { contractBaseSelectors } from '../../../contractBase/contractBase.selectors' import { handleStageFailSaga } from '../../../analyzer/saga/handleStageFail/handleStageFail.saga' export async function fetchBytecode(chainId: ChainId, address: string): Promise { @@ -18,15 +20,15 @@ export function* fetchBytecodesSaga(): SagaGenerator { yield* put(analyzerActions.addLogMessage(createInfoLogMessage('Fetching bytecodes'))) yield* put(analyzerActions.updateStage({ stageStatus: AnalyzerStagesStatus.IN_PROGRESS, stageName: AnalyzerStages.FETCHING_BYTECODES })) - // const chainId = yield* select(transactionConfigSelectors.selectChainId) - // const contractAddresses = yield* select(contractBaseSelectors.selectAllAddresses) + const chainId = yield* select(transactionConfigSelectors.selectChainId) + const contractAddresses = yield* select(contractBaseSelectors.selectAllAddresses) - // const analyzer = yield* call(getAnalyzerInstance) + const analyzer = yield* call(getAnalyzerInstance) - // for (const address of contractAddresses) { - // const bytecode = yield* call(fetchBytecode, chainId, address) - // yield* apply(analyzer.dataLoader, analyzer.dataLoader.inputContractData.set, [address, 'etherscanBytecode', bytecode]) - // } + for (const address of contractAddresses) { + const bytecode = yield* call(fetchBytecode, chainId, address) + yield* apply(analyzer.dataLoader, analyzer.dataLoader.inputContractData.set, [address, 'etherscanBytecode', bytecode]) + } yield* put( analyzerActions.updateStage({