Deploying A Smart Contract, The Hard Way

本文详细介绍了一种不依赖高级工具的手动方式,在以太坊虚拟机上部署智能合约的过程。从安装必要的软件开始,到编译合约文件,再到交易发送及交互,文章提供了详细的步骤说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

I am in favor of understanding the mechanics that goes under the hood of a tool, framework or technology that I am using. If not all of it, at least a general understanding so once a bugs appears I have an idea where to look at.

This post is an exercise on the steps that happen to deploy a smart contract on the Ethereum Virtual Machine. I will show here the repetitive manual manner which if you have used tools such as Truffle or Mist they are done in simple short commands.

For this, you need to install Geth and Solidity compiler.

$ sudo apt-get install -y software-properties-common
$ sudo add-apt-repository -y ppa:ethereum/ethereum
$ sudo apt-get update
$ sudo apt-get install -y ethereum
$ sudo apt-get install -y solc
Check if you have solc and geth installed
$ ~$ solc --version
solc, the solidity compiler commandline interface
Version: 0.4.11-develop.2017.4.24+commit.a9f42157.Linux.g++
$ geth version
Geth
Version: 1.6.0-stable
Git Commit: facc47cb5cec97b22c815a0a6118816a98f39876
Architecture: amd64
Protocol Versions: [63 62]
...

For this exercise I am going to run geth in my own private network. This post does not go into setting up your own private blockchain. However if you are interested you can set one up by following these instructions

Make sure you start geth with the console flag and if you have not done so already go ahead and create an wallet address so we can deploy the contract with it:

$ personal.newAccount()

This is the contract we will deploy the hard way:

pragma solidity ^0.4.10;
contract Storage {
  uint256 storedData;
  function set(uint256 data) {
    storedData = data;
  }
  function get() constant returns (uint256) {
    return storedData;
  }
}

Compilation

Create the file for the contract and add the code above to it.

$ touch Storage.sol

To compile this contract we will put it in a json format and assign a JavaScript variable, then we send it to an output file.

$ echo "var storageOutput=`solc --optimize --combined-json abi,bin,interface Storage.sol`" > storage.js
$ cat storage.js
var storageOutput={"contracts":{"Storage.sol:Storage":{"abi":"[{\"constant\":false,\"inputs\":[{\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"}]","bin":"60606040523415600b57fe5b5b60978061001a6000396000f300606060405263ffffffff60e060020a60003504166360fe47b18114602a5780636d4ce63c14603c575bfe5b3415603157fe5b603a600435605b565b005b3415604357fe5b60496064565b60408051918252519081900360200190f35b60008190555b50565b6000545b905600a165627a7a7230582052ccd035d0e1b92d60b2dbc6ffd8a86d947fcaa3199be580f3d95fc289b0c39a0029"}},"version":"0.4.11-develop.2017.4.24+commit.a9f42157.Linux.g++"}

Now in Geth console:

> loadScript('storage.js')
true
> storageOutput
{
  contracts: {
    Storage.sol:Storage: {
      abi: "[{\"constant\":false,\"inputs\":[{\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"}]",
      bin: "60606040523415600b57fe5b5b60978061001a6000396000f300606060405263ffffffff60e060020a60003504166360fe47b18114602a5780636d4ce63c14603c575bfe5b3415603157fe5b603a600435605b565b005b3415604357fe5b60496064565b60408051918252519081900360200190f35b60008190555b50565b6000545b905600a165627a7a7230582052ccd035d0e1b92d60b2dbc6ffd8a86d947fcaa3199be580f3d95fc289b0c39a0029"
    }
  },
  version: "0.4.11-develop.2017.4.24+commit.a9f42157.Linux.g++"
}

Notice how the root object is a map { contracts: Storage.sol:Storage: {...} }Storage.sol:Storage . The map keys identify the contract name, the abi in json, the bin code and lastly the solidity compile version.

Let’s prepare the variables that will help us interact with the contract.

> var storageContractAbi = storageOutput.contracts['Storage.sol:Storage'].abi
"[{\"constant\":false,\"inputs\":[{\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"}]"
>var storageContract = eth.contract(JSON.parse(storageContractAbi))
undefined
> var storageBinCode = "0x" + storageOutput.contracts['Storage.sol:Storage'].bin
"0x60606040523415600b57fe5b5b60978061001a6000396000f300606060405263ffffffff60e060020a60003504166360fe47b18114602a5780636d4ce63c14603c575bfe5b3415603157fe5b603a600435605b565b005b3415604357fe5b60496064565b60408051918252519081900360200190f35b60008190555b50565b6000545b905600a165627a7a7230582052ccd035d0e1b92d60b2dbc6ffd8a86d947fcaa3199be580f3d95fc289b0c39a0029"

Notice that to get the web3 contract object we need to use eth.contract + the parsed storageContractAbi from the compilation.

We also get store the bin code value in a variable. Notice that in order to have the expected hex value we need to add the "0x" at the beginning of it.

Deployment

Geth provides a facility to deploy a compiled contract. you need some ether for this step, plus it only works when you mine, so let’s start the miner:

> miner.start(1)

Now it is time to deploy. Make sure you unlock your account by typing and typing the password you assigned to it.

> personal.unlockAccount(eth.accounts[0])

>var deployTransationObject = { from: eth.accounts[0], data: storageBinCode, gas: 1000000 };
undefined
> var storageInstance = storageContract.new(deployTransationObject)
undefined
> storageInstance
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "set",
      outputs: [],
      payable: false,
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "get",
      outputs: [{...}],
      payable: false,
      type: "function"
  }],
  address: undefined,
  transactionHash: "0xcbe9921400083ca543e4e62386e3a02eed6cb327f23c9a445f3ec81a3bfad830"
}

So the contract sent a transaction to deploy an instance and returned a web3 contract instance, which unfortunately lacks an address. It should know the address but it did not because it was not mined yet. To fix it, let’s get the address by doing:

> eth.getTransactionReceipt(storageInstance.transactionHash);
{
  blockHash: "0x5712473e4b60e5c58648daee420427133db4c048a11193330a6c26b6101e5206",
  blockNumber: 11,
  contractAddress: "0xc05c7ee9b13dd103581accfead6074e0522475e0",
  cumulativeGasUsed: 94673,
  from: "0x7f77d5c8639d04f7efb221079cac40dca1a37f43",
  gasUsed: 94673,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0xd2945007d43f6d05def2d48b5c369e61915b9c3cedde933e26a5469b241e7106",
  to: null,
  transactionHash: "0xcbe9921400083ca543e4e62386e3a02eed6cb327f23c9a445f3ec81a3bfad830",
  transactionIndex: 0
}

The address returned is the unique, immutable address of the contract, it is calculated from the hash of the sender address and the transaction nonce. When you interact with this contract instance you need to mention this address. So let’s save it:

> var storageAddress = eth.getTransactionReceipt(storageInstance.transactionHash).contractAddress
undefined
> storageAddress
"0xc05c7ee9b13dd103581accfead6074e0522475e0"

Voilá, the contract is deployed.

Let’s interact with the contract:

> var storage = storageContract.at(storageAddress);
undefined
> storage
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "set",
      outputs: [],
      payable: false,
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "get",
      outputs: [{...}],
      payable: false,
      type: "function"
  }],
  address: "0xc05c7ee9b13dd103581accfead6074e0522475e0",
  transactionHash: null,
  allEvents: function(),
  get: function(),
  set: function()
}

Here are the JavaScript functions that will let us call the same ones in the contract. Let’s call a function. By the way are you mining? ;-)

> storage.get.call()
0
> storage.set.sendTransaction(42, {from: eth.accounts[0], gas: 1000000})
"0x7a54ab329fcbf551432eb78c4b2a1ff48fc8b9f9aa23d94fa86330e5c1d711f3"
> storage.get.call()
42

Success!

We just saw here a long and winding path of deploying a contract to the Ethereum Virtual Machine. Tools such a Truffle does all that for you under the hood with commands such as truffle compile and truffle migrate. But I believe it is good to know the inwards so you are on the right track to become proficient in this new field. Hope you enjoyed this blog post. Next one I will talk about deploying smart contracts using Truffle.

原文地址: https://medium.com/@gus_tavo_guim/deploying-a-smart-contract-the-hard-way-8aae778d4f2a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值