Skip to content

Commit 5c8bf24

Browse files
committed
using contractTracer
1 parent 9cdbf0b commit 5c8bf24

File tree

1 file changed

+21
-159
lines changed

1 file changed

+21
-159
lines changed

src/opCodeFinder.js

Lines changed: 21 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -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 (!/^0x[a-fA-F0-9]+$/i.test(opcode) && !/^[a-fA-F0-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

6657
async 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

19195
function 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(/^0x/, "");
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-
248110
async function main() {
249111
const args = process.argv.slice(2);
250112
const validArgs = await validateInputs(args);

0 commit comments

Comments
 (0)