Minimal SC sample exposing a way to get the bytecode and the hashed bytecode of a deployed smart contract.
This without the new OPCODE of EIP1052
pragma solidity ^0.4.24;
contract SomeContractInstance {
constructor () public {}
}
library GetCode {
function atReturningHash(address _addr) public view returns (bytes32 hash) {
bytes memory o_code;
assembly {
// retrieve the size of the code, this needs assembly
let size := extcodesize(_addr)
// allocate output byte array - this could also be done without assembly
// by using o_code = new bytes(size)
o_code := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// store length in memory
mstore(o_code, size)
// actually retrieve the code, this needs assembly
extcodecopy(_addr, add(o_code, 0x20), 0, size)
}
hash = keccak256(o_code);
}
function at(address _addr) public view returns (bytes o_code) {
assembly {
// retrieve the size of the code, this needs assembly
let size := extcodesize(_addr)
// allocate output byte array - this could also be done without assembly
// by using o_code = new bytes(size)
o_code := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// store length in memory
mstore(o_code, size)
// actually retrieve the code, this needs assembly
extcodecopy(_addr, add(o_code, 0x20), 0, size)
}
}
}
contract Checker {
constructor () public {}
function getCodeHashed(address _contractAddress) public view returns (bytes32) {
return GetCode.atReturningHash(_contractAddress);
}
function getCode(address _contractAddress) public view returns (bytes) {
return GetCode.at(_contractAddress);
}
}
As soon as you try to perform a compilation, e.g with Truffle, of the SomeContractInstance SC you will have at your disposal in the build
folder the deployedBytecode
key with the following value:
const truffleBytecode = "0x6080604052600080fd00a165627a7a7230582036e3d8f01ac39ad1d768c6a9262d6deb6b92c810dd909bea9b68716f3ded6ca50029"
This value will be the same value you can get by actually deploying SomeContractInstance and making a transactionCall to the Checker getCode
method passing the SomeContractInstance address.
Passing instead the SomeContractInstance address to the Checker getCodeHashed
method you will retrieve the hash of the SomeContractInstance bytecode.
The hashed value would be: 0x7fa374a961dedb32a7f0411a09663ed9887240911c24d700b63e0cb6f0003854
.
const ethereumUtil = require('ethereumjs-util')
const bytecodeFromTransactionCall = "0x6080604052600080fd00a165627a7a7230582036e3d8f01ac39ad1d768c6a9262d6deb6b92c810dd909bea9b68716f3ded6ca50029"
const bufferedBytecode = ethereumUtil.toBuffer(bytecodeFromTransactionCall)
const hashedBytecode = ethereumUtil.keccak256(bufferedBytecode)
// <Buffer 7f a3 74 a9 61 de db 32 a7 f0 41 1a 09 66 3e d9 88 72 40 91 1c 24 d7 00 b6 3e 0c b6 f0 00 38 54>
ethereumUtil.addHexPrefix(hashedBytecode.toString('hex'))
// '0x7fa374a961dedb32a7f0411a09663ed9887240911c24d700b63e0cb6f0003854'
What I'm trying to highlight is that it could be useful understand / filter smart contracts interactions based on their instance.
EIP1052