@@ -34,8 +34,7 @@ async function validateInputs(args) {
3434 } else {
3535 endBlock = parseInt ( args [ 1 ] , 10 ) ;
3636 }
37- opcode = parseInt ( args [ 2 ] , 16 ) ;
38-
37+ opcode = args [ 2 ] ;
3938 // Validate that the block number is a valid positive integer
4039 if (
4140 isNaN ( startBlock ) ||
@@ -50,142 +49,47 @@ async function validateInputs(args) {
5049 process . exit ( 1 ) ;
5150 }
5251
53- // Validate that the opcode is a valid hexadecimal string (optionally starting with "0x")
54- if ( ! / ^ 0 x [ a - f A - F 0 - 9 ] + $ / i. test ( opcode ) && ! / ^ [ a - f A - F 0 - 9 ] + $ / i. test ( opcode ) ) {
55- console . log (
56- "Opcode must be a valid hexadecimal string, optionally starting with '0x'."
57- ) ;
58- process . exit ( 1 ) ;
59- }
60-
6152 // If all validations pass
6253 validArgs . push ( startBlock , endBlock , opcode , rpcUrl ) ;
6354 return validArgs ;
6455}
6556
6657async function findContracts ( startBlockNumber , endBlockNumber ) {
67- let contractCount = 0 ;
68- let failedTxs = 0 ;
69-
7058 for ( let i = startBlockNumber ; i <= endBlockNumber ; i ++ ) {
7159 process . stdout . write (
72- `\rSearching for block ${ i } ,total found ${ contractCount } contracts, ${ matchContractCount } of which meet the criteria, ${ failedTxs } transactions queried failed `
60+ `\rSearching for block ${ i } , ${ matchContractCount } contracts match the criteria`
7361 ) ;
74- let block = await web3 . eth . getBlock ( i ) ;
75- if ( block != null ) {
76- if ( block . transactions != null ) {
77- let blockFinishedCount = block . transactions . length ;
78- //trace all the transactions in this block
79- for ( let txHash of block . transactions ) {
80- try {
81- //get the trace object of the transaction
82- const traceObject = await processTransactionsWithRetry ( txHash ) ;
83- //check if the transaction created a contract
84- if (
85- traceObject . result . type === "CREATE" ||
86- traceObject . result . type === "CREATE2"
87- ) {
88- getContractBytecode ( traceObject . result . to ) ;
89- contractCount ++ ;
90- }
91- // go through any nested calls within the trace.
92- if (
93- traceObject . result . calls &&
94- traceObject . result . calls . length > 0
95- ) {
96- contractCount += isContractCreation ( traceObject . result . calls ) ;
97- }
98- } catch ( error ) {
99- failedTxs ++ ;
100- }
101- blockFinishedCount -- ;
102- }
103- while ( blockFinishedCount > 0 ) {
104- console . log ( "waiting..." ) ;
105- }
106- }
107- }
108- }
109- console . log ( ) ;
110- }
111-
112- async function processTransactionsWithRetry (
113- txHash ,
114- maxRetries = 3 ,
115- initialDelay = 1000
116- ) {
117- let retries = 0 ;
118- while ( retries < maxRetries ) {
11962 try {
12063 let traceObject = await web3 . eth . currentProvider . sendAsync ( {
121- method : "debug_traceTransaction" ,
122- params : [ `${ txHash } ` , { tracer : "callTracer" } ] ,
64+ method : "debug_traceBlockByNumber" ,
65+ params : [
66+ `0x${ i . toString ( 16 ) } ` ,
67+ { tracer : "contractTracer" , tracerConfig : { opCode : `${ opCode } ` } } ,
68+ ] ,
12369 jsonrpc : "2.0" ,
12470 id : "1" ,
12571 } ) ;
126- //if the trace object is not found or there is an error, throw an error
12772 if ( ! traceObject || traceObject . error ) {
12873 throw new Error (
129- "Failed to get trace object: " +
130- ( traceObject . error ? traceObject . error . message : "unknown error" )
74+ traceObject . error ? traceObject . error . message : "unknown error"
13175 ) ;
13276 }
133- //if the trace object is found, return it
134- return traceObject ;
77+ //go through traceObject.result
78+ if ( traceObject . result . length === 0 ) continue ;
79+ // Loop through traceObject.result array
80+ traceObject . result . forEach ( ( item ) => {
81+ if ( item . result && item . result . length > 0 ) {
82+ item . result . forEach ( ( element ) => {
83+ if ( element && element . length > 0 ) saveTheContract ( element ) ;
84+ } ) ;
85+ }
86+ } ) ;
13587 } catch ( error ) {
136- //if the trace object is not found or there is an error, retry
137- retries ++ ;
138- //if the retries reach the maximum, handle failed transactions
139- if ( retries >= maxRetries ) {
140- fs . appendFile (
141- "failed-transactions.txt" ,
142- txHash + "\t" + error . message + "\n" ,
143- { encoding : "utf8" } ,
144- ( err ) => {
145- if ( err ) {
146- console . error ( "Error occurred while appending content." ) ;
147- return ;
148- }
149- }
150- ) ;
151- throw error ;
152- }
153- await new Promise ( ( resolve ) =>
154- setTimeout ( resolve , initialDelay * Math . pow ( 2 , retries ) )
155- ) ;
88+ //check if the error and throw a specific error message
89+ console . error ( "\nAn error occurred in block " + i + ":" + error . message ) ;
15690 }
15791 }
158- }
159-
160- //check if the tx created a contract
161- function isContractCreation ( traceRes ) {
162- let contractCount = 0 ;
163-
164- for ( let call of traceRes ) {
165- // check if the current call creates a contract.
166- if ( call . type === "CREATE" || call . type === "CREATE2" ) {
167- getContractBytecode ( call . to ) ;
168- contractCount ++ ;
169- }
170-
171- // if the current call has sub-calls, go through each sub-call.
172- if ( call . calls && call . calls . length > 0 ) {
173- contractCount += isContractCreation ( call . calls ) ;
174- }
175- }
176- return contractCount ;
177- }
178-
179- async function getContractBytecode ( contractArr ) {
180- try {
181- let bytecode = await web3 . eth . getCode ( contractArr ) ;
182- let isContainsTheOpCode = findOpcode ( stringToHexArray ( bytecode ) ) ;
183- if ( isContainsTheOpCode ) {
184- saveTheContract ( contractArr ) ; //saveTheContract in a txt file
185- }
186- } catch ( error ) {
187- console . error ( "Error fetching contract bytecode:" , error ) ;
188- }
92+ console . log ( ) ;
18993}
19094
19195function saveTheContract ( contractAddress ) {
@@ -203,48 +107,6 @@ function saveTheContract(contractAddress) {
203107 matchContractCount ++ ;
204108}
205109
206- function stringToHexArray ( hexString ) {
207- // Remove the "0x" prefix
208- hexString = hexString . replace ( / ^ 0 x / , "" ) ;
209- // Ensure the string length is even
210- if ( hexString . length % 2 !== 0 ) {
211- throw new Error ( "Invalid hex string length" ) ;
212- }
213- // Convert each pair of characters to hexadecimal values
214- let hexArray = [ ] ;
215- for ( let i = 0 ; i < hexString . length ; i += 2 ) {
216- let hexByte = hexString . substring ( i , i + 2 ) ;
217- hexArray . push ( "0x" + hexByte ) ;
218- }
219- return hexArray ;
220- }
221-
222- function findOpcode ( bytecode ) {
223- for ( let i = 0 ; i < bytecode . length ; ) {
224- let op = bytecode [ i ] ;
225- // skip PUSH opcodes
226- if ( isPushOpcode ( op ) ) {
227- // increment i, skipping PUSH argument
228- i += skipPush ( op , i ) ;
229- } else if ( op == opCode ) {
230- return true ;
231- }
232- i ++ ;
233- }
234- return false ;
235- }
236-
237- // Check if the opcode is a PUSH opcode
238- function isPushOpcode ( op ) {
239- return op >= 0x5f && op <= 0x7f ; // PUSH1 (0x5f) to PUSH32 (0x7f)
240- }
241- // Example skipPush function
242- function skipPush ( op ) {
243- // The PUSH opcodes are consecutive, so we can use the opcode to determine how many bytes to skip
244- // For example, PUSH1 (0x5f) skips 1 byte, PUSH32 (0x7f) skips 32 bytes
245- return op - 0x60 + 1 ;
246- }
247-
248110async function main ( ) {
249111 const args = process . argv . slice ( 2 ) ;
250112 const validArgs = await validateInputs ( args ) ;
0 commit comments