Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 111x 111x 111x 111x 5562059x 5562059x 386825x 386825x 386825x 386825x 386825x 37847x 19412x 19412x 37847x 348978x 3553x 3553x 3553x 3553x 3553x 4x 386825x 5166x 381659x 4982x 4983x 4982x 386825x 80x 1x | /** * Writes data from the VM step to the in-memory * coverage map constructed by the Instrumenter. */ class DataCollector { constructor(instrumentationData={}, viaIR){ this.instrumentationData = instrumentationData; this.validOpcodes = { "PUSH1": true, "DUP1": viaIR, "DUP2": viaIR, "DUP3": viaIR, "DUP4": viaIR, "DUP5": viaIR, "DUP6": viaIR, "DUP7": viaIR, "DUP8": viaIR, "DUP9": viaIR, "DUP10": viaIR, "DUP11": viaIR, "DUP12": viaIR, "DUP13": viaIR, "DUP14": viaIR, "DUP15": viaIR, "DUP16": viaIR, } this.lastHash = null; this.viaIR = viaIR; } /** * VM step event handler. Detects instrumentation hashes when they are pushed to the * top of the stack. This runs millions of times - trying to keep it fast. * @param {Object} info vm step info */ step(info){ try { if (this.validOpcodes[info.opcode.name] && info.stack.length > 0){ const idx = info.stack.length - 1; let hash = '0x' + info.stack[idx].toString(16); this._registerHash(hash) } } catch (err) { /*Ignore*/ }; } // Temporarily disabled because some relevant traces aren't available /** * Converts pushData value to string and registers in instrumentation map. * @param {HardhatEVMTraceInstruction} instruction */ /*trackHardhatEVMInstruction(instruction){ if (instruction && instruction.pushData){ let hash = `0x` + instruction.pushData.toString('hex'); this._registerHash(hash) } }*/ /** * Normalizes has string and marks hit. * @param {String} hash bytes32 hash */ _registerHash(hash){ hash = this._normalizeHash(hash); if(this.instrumentationData[hash]){ // abi.encode (used to circumvent viaIR) sometimes puts the hash on the stack twice if (this.lastHash !== hash) { this.lastHash = hash; this.instrumentationData[hash].hits++ } return; } // Detect and recover from viaIR mangled hashes by left-padding single `0` if(this.viaIR && hash.length === 18) { hash = hash.slice(2); hash = '0' + hash; hash = hash.slice(0,16); hash = '0x' + hash; if(this.instrumentationData[hash]){ Iif (this.lastHash !== hash) { this.lastHash = hash; this.instrumentationData[hash].hits++ } } } } /** * Left-pads zero prefixed bytes8 hashes to length 18. The '11' in the * comparison below is arbitrary. It provides a margin for recurring zeros * but prevents left-padding shorter irrelevant hashes * * @param {String} hash data hash from evm stack. * @return {String} 0x prefixed hash of length 18. */ _normalizeHash(hash){ // viaIR sometimes right-pads the hashes out to 32 bytes // but it doesn't preserve leading zeroes when it does this if (this.viaIR && hash.length >= 18) { hash = hash.slice(0,18); } else if (hash.length < 18 && hash.length > 11){ hash = hash.slice(2); while(hash.length < 16) hash = '0' + hash; hash = '0x' + hash } return hash; } /** * Unit test helper * @param {Object} data Instrumenter.instrumentationData */ _setInstrumentationData(data){ this.instrumentationData = data; } } module.exports = DataCollector; |