7

Consider the following solidity source file A.sol:

pragma solidity ^0.4.8;

contract A {}

and B.sol:

pragma solidity ^0.4.8;

contract A {}

contract B is A {}

Using solc version 0.4.8, the code produced for the two versions of contract A are not identical:

$ solc --bin A.sol 

======= A =======
Binary: 
6060604052346000575b60358060166000396000f30060606040525b60005600a165627a7a723058201f05fd362367eb20b594d9537e2d735626b1fc0909c76826b94103a678da6cf10029
$ solc --bin B.sol 

======= A =======
Binary: 
6060604052346000575b60358060166000396000f30060606040525b60005600a165627a7a723058207dd14680c4efdd761b8db9a748045c916aff2f0a11c4ee7b82731d287045f0540029

======= B =======
Binary: 
6060604052346000575b60358060166000396000f30060606040525b60005600a165627a7a72305820942c33894954b0c78b1da86869a47c578755a698e26f671c5b4450476a3d56bc0029

If you scan to the bytes 5820 in the compilations of A, you'll see the two versions differ just after.

I'd expected solc compilations to be repeatable (that seems important for verifying that code on the blockchain is consistent with public source), and don't understand why these two versions of A should differ. What am I missing?

Many thanks for any insight!

Update: I'm using the empty contract as an example here, but I first encountered inconsistent compilations with a less trivial contract. It's not just a quirk of the empty contract.

4

I do not have a full answer but I will share what I found out. I used Browser Solidity to compile contracts, and used Etherscan's disassembler to help me out with the result.

When I compiled contract A {} in Browser Solidity, I looked at "Assembly" (you need to "Toggle Details"). It shows:

.code
  PUSH 60           contract A {\n}
// Some Stuff...
  JUMPI             contract A {\n}
tag 1           contract A {\n}
  JUMPDEST          contract A {\n}
// Unpack contract for deployment...
  RETURN            contract A {\n}
.data
  0:
// Now we have the deployed contract here
    .code
      PUSH 60           contract A {\n}
      PUSH 40           contract A {\n}
      MSTORE            contract A {\n}
    tag 1           contract A {\n}
      JUMPDEST          contract A {\n}
      PUSH [ErrorTag]           contract A {\n}
      JUMP          contract A {\n}
    .data
// Oh nothing more to show here, but that's where it gets interesting for us.

Then I took the content of "Runtime Bytecode" and pasted it in the disassembler.

The lines:

[17] PUSH6 0x627a7a723058
[18] SHA3 // Its opcode is 0x20

Correspond to the xxxxx5820 that you identified. And guess what:

> web3.toUtf8("0x627a7a723058")
"bzzr0X"

Then what comes right after that, in my case 81ef35e9ce2010474897d82da20c73d954e24c1e93fceaca1da5d1ed75650a26 so 32 bytes which, if you go back to Solidity, are the same ones as under "Metadata location".

So my understanding is that the code of the contract has not changed; only its Swarm address has. And contract verifiers need to abstract that part away.

Edit: I just found this Encoding of the Metadata Hash in the Bytecode

  • Thanks for all the investigating! This looks consistent with the reddit thread @BokkyPooBah points to in a comment to the original post. I'll let this sit for a while in case others want to weigh in, but I think you and BokkyPooBah have basically figured this out. – Steve Waldman Jan 24 '17 at 10:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.