16

When I deploy a contract from node.js using the web3 JavaScript API (connected to a locally running geth), and then check the deployed bytecode using eth.getCode(address) (either from the JS console or in node, both connected to a locally running geth), the deployed code sometimes differs from the code that was used when deploying (the former is a trailing substring of the latter, i.e. missing some data at the beginning).

Is this normal? Why does this happen?

The deployed contract works as expected though.

The script used for deploying is something like this:

web3.eth.contract(abi).new({from: addr, data: originalBin, gas: 4700000})

I am deploying a ETH/ETC splitter contract similar to this.

Eg. this bytecode:

6060604052732bd2326c993dfaef84f696526064ff22eba5b362600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690830217905550610163806100516000396000f36060604052361561003d576000357c010000000000000000000000000000000000000000000000000000000090048063d264e05e1461004a5761003d565b6100485b610002565b565b005b610057600480505061006f565b60405180821515815260200191505060405180910390f35b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166316c72721604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506020604051808303816000876161da5a03f115610002575050506040518051906020015015801561014d575073901e93811ef02ce5e34b6f4ac2722a3ed6a1501273ffffffffffffffffffffffffffffffffffffffff16600034604051809050600060405180830381858888f193505050505b1561015b5760019050610160565b610002565b9056

got deployed at 0xde8e581f96707add7ebbeb678a0ba36778b96540 as:

0x6060604052361561003d576000357c010000000000000000000000000000000000000000000000000000000090048063d264e05e1461004a5761003d565b6100485b610002565b565b005b610057600480505061006f565b60405180821515815260200191505060405180910390f35b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166316c72721604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506020604051808303816000876161da5a03f115610002575050506040518051906020015015801561014d575073901e93811ef02ce5e34b6f4ac2722a3ed6a1501273ffffffffffffffffffffffffffffffffffffffff16600034604051809050600060405180830381858888f193505050505b1561015b5760019050610160565b610002565b9056

Edit: added bytcode examples

eth
  • 85,679
  • 53
  • 285
  • 406
mazi
  • 443
  • 4
  • 10

1 Answers1

14

Yes, it is normal and the code on the blockchain is always a subset of the compiled (byte)code, because the compiled code includes initialization code. The compiled code is/executes a function which returns the blockchain code, but as part of the execution also initializes the contract being deployed.

For your contract, look at its transaction 1 and you can see the invocation data, the payload and the return value. The compiled code is the payload, and executing it produces the return value.

enter image description here

Related: How can I verify that a contract on the blockchain matches the source code?


To help explain above, the following is for illustration purposes only. Imagine that the blockchain stored JavaScript and that we want to deploy this function:

function hi() { return "hi" }

(Recall that a contract is created by sending a transaction to address 0.) We may think that to do this we would send a transaction with the basic details:

to: 0
data: `function hi() { return "hi" }`

However, that's not how the EVM is specified and the transaction needs to look more like this:

to: 0
data: 
`(function() {
    return 'function hi() { return "hi" }';
}());`

This shows what's meant by the return bolded above, but to see initialization, it may be clearer to study actual bytecode.


For reference, the specification from the Yellow Paper https://ethereum.github.io/yellowpaper/paper.pdf explains it as:

init: An unlimited size byte array specifying the EVM-code for the account initialisation procedure, formally Ti. init is an EVM-code fragment; it returns the body, a second fragment of code that executes each time the account receives a message call (either through a transaction or due to the internal execution of code). init is executed only once at account creation and gets discarded immediately thereafter.

eth
  • 85,679
  • 53
  • 285
  • 406
  • It seems redeploying a contract using bytecode on the blockchain is not possible (assuming ABI is known). If it is possible to reconstruct and redeploy with information already extant on the chain, let me know and I'll open a new question. – Garen Vartanian Oct 05 '18 at 03:59
  • 1
    @Gviz: I added an illustration to help explain the idea more to others. I think it is worthwhile to ask your question anew. – eth Oct 06 '18 at 06:24