以太坊智能合约---helloworld

2019-09-29  本文已影响0人  JC86

以下会说两种方法部署智能合约
第一种使用以太坊客户端 deploy方法,这种方法比较繁琐复杂,但是对应理解部署原理比较有用
第二种是使用trffle框架,这种方法基本是配置+命令,部署起来比较方便,开发效率会较第一种高。

一、以太坊客户端(geth)

Environment:
Solidity v0.5.1

1、合约编写

创建helloworld.sol, 内容如下:

pragma solidity >=0.4.21 <0.6.0;

contract HelloWorld{
    address payable creator;
    string greeting;
    constructor() public {
        creator = msg.sender;
        greeting = "hello world";
    }
    function greet() view public returns (string memory) {
        return greeting;
    }
    function setGreeting(string memory _newgreeting) public {
        greeting = _newgreeting;
    }
    function kill() public{
        if (msg.sender == creator)
            selfdestruct(creator);  // kills this contract and sends remaining funds back to creator
    }
}

2、合约编译

执行以下命令,得出abi文件HelloWorld.abi和bytecode文件HelloWorld.bin
注意:我安装的是mac版的solidity编译器

solc helloworld.sol --abi --bin -o ./

3、连接私链

geth attach ipc://Users/JC/Documents/project/grg_blockchain/tmp/test/data1/geth.ipc
Welcome to the Geth JavaScript console!

 instance: Geth/v1.7.4-stable-03c7946b/darwin-amd64/go1.10.3
validator: 0x564eec478efa01313d458b7b6a2edf124cc51fbf
 coinbase: 0x564eec478efa01313d458b7b6a2edf124cc51fbf
 at block: 33 (Fri, 20 Sep 2019 14:52:07 CST)
  datadir: /Users/JC/Documents/project/grg_blockchain/tmp/test/data0
  modules: admin:1.0 debug:1.0 eth:1.0 gdpos:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

>

解锁账户

personal.unlockAccount(eth.coinbase, "123456", 0)

4、部署合约

把HelloWorld.abi文件的内容copy给变量api

abi=[{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_newgreeting","type":"string"}],"name":"setGreeting","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"greet","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]

把HelloWorld.bin文件的内容copy给变量bytecode
注意: 前面要加'0x'

bytecode="0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040805190810160405280600b81526020017f68656c6c6f20776f726c640000000000000000000000000000000000000000008152506001908051906020019061009c9291906100a2565b50610147565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e357805160ff1916838001178555610111565b82800160010185558215610111579182015b828111156101105782518255916020019190600101906100f5565b5b50905061011e9190610122565b5090565b61014491905b80821115610140576000816000905550600101610128565b5090565b90565b6103e3806101566000396000f3fe608060405260043610610051576000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610056578063a41368621461006d578063cfae321714610135575b600080fd5b34801561006257600080fd5b5061006b6101c5565b005b34801561007957600080fd5b506101336004803603602081101561009057600080fd5b81019080803590602001906401000000008111156100ad57600080fd5b8201836020820111156100bf57600080fd5b803590602001918460018302840111640100000000831117156100e157600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610256565b005b34801561014157600080fd5b5061014a610270565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561018a57808201518184015260208101905061016f565b50505050905090810190601f1680156101b75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610254576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b565b806001908051906020019061026c929190610312565b5050565b606060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103085780601f106102dd57610100808354040283529160200191610308565b820191906000526020600020905b8154815290600101906020018083116102eb57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061035357805160ff1916838001178555610381565b82800160010185558215610381579182015b82811115610380578251825591602001919060010190610365565b5b50905061038e9190610392565b5090565b6103b491905b808211156103b0576000816000905550600101610398565b5090565b9056fea165627a7a7230582049b29deb586ec1f5d654c4051b8d48cab7b2609190191cb5a1c39455b70ad0290029"

创建一个contact对象:

helloworldContract=eth.contract(abi)

创建一个实例:

helloworld = helloworldContract.new(
   {
     from: eth.coinbase, 
     data: bytecode, 
     gas: '4300000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

得到的结果:

> helloworld = helloworldContract.new(
...    {
......      from: eth.coinbase,
......      data: bytecode,
......      gas: '4300000'
......    }, function (e, contract){
......     console.log(e, contract);
......     if (typeof contract.address !== 'undefined') {
.........          console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
.........     }
......  })
null [object Object]
{
 abi: [{
     constant: false,
     inputs: [],
     name: "kill",
     outputs: [],
     payable: false,
     stateMutability: "nonpayable",
     type: "function"
 }, {
     constant: false,
     inputs: [{...}],
     name: "setGreeting",
     outputs: [],
     payable: false,
     stateMutability: "nonpayable",
     type: "function"
 }, {
     constant: true,
     inputs: [],
     name: "greet",
     outputs: [{...}],
     payable: false,
     stateMutability: "view",
     type: "function"
 }, {
     inputs: [],
     payable: false,
     stateMutability: "nonpayable",
     type: "constructor"
 }],
 address: undefined,
 transactionHash: "0xfaf6fa7c57ec8394da2e3650ec39da3ce681cb2182c26dc627c256f18cfb09e7"
}
> null [object Object]
Contract mined! address: 0xbc7384998a5453a41bc51c1aa0f252034b57b986 transactionHash: 0xfaf6fa7c57ec8394da2e3650ec39da3ce681cb2182c26dc627c256f18cfb09e7

结果打印了合约地址和交易hash
可以用实例调用合约函数

> helloworld.greet.call()
"hello world"

如果有上面结果,证明合约部署已经成功

5、其他账户调用合约

跟步骤3一样连接另外一个节点
执行一下命令:

> abi=[{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_newgreeting","type":"string"}],"name":"setGreeting","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"greet","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]

> MyContract = eth.contract(abi)   #这时候就体现了abi的重要性,相当于接口的描述文档
> contractAddress = "0xbc7384998a5453a41bc51c1aa0f252034b57b986" #这个地址就是合约地址
> myContract = MyContract.at(contractAddress)
> myContract.greet.call()
"hello world"

如果出现上述结果,证明调用也成功了。
注意: Solidity我这里用了v0.5.1, 开始我用v0.5.11没成功,原因我没去找

二、使用Truffle框架

Environment:
Truffle v5.0.35 (core: 5.0.35)
Solidity v0.5.8 (solc-js)
Node v12.10.0
Web3.js v1.2.1

1、Truffle安装

npm install -g truffle@5.0.35

2、Truffle客户端

我这里选择的了第二种

3、 创建工程目录

打开你的terminal选择好你放合约工程的目录

mkdir HelloWorld

4、初始化工程

cd HelloWorld
truffle init

执行完后看到以下目录结构:

├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
└── truffle-config.js

5、编写自己的合约

在目录contracts里创建HelloWorld.sol文件,内容为:

pragma solidity >=0.4.21 <0.6.0;

contract HelloWorld{
    address payable creator;
    string greeting;
    constructor() public {
        creator = msg.sender;
        greeting = "hello world";
    }
    function greet() view public returns (string memory) {
        return greeting;
    }
    function setGreeting(string memory _newgreeting) public {
        greeting = _newgreeting;
    }
    function kill() public{
        if (msg.sender == creator)
            selfdestruct(creator);  // kills this contract and sends remaining funds back to creator
    }
}

6、增加发布脚本

在目录migrations里创建2_initial_helloworld.js文件,内容为

const HelloWorld = artifacts.require("HelloWorld");
module.exports = function(deployer) {
  deployer.deploy(HelloWorld);
};

7、编译

在工程目录HelloWorld目录下,执行:

truffle compile

打印一下信息代表编译通过:

➜  HelloWorld truffle compile

Compiling your contracts...
===========================
> Compiling ./contracts/HelloWorld.sol
> Compiling ./contracts/Migrations.sol
> Artifacts written to /Users/JC/Documents/project/grg_blockchain/tmp/test/contract/HelloWorld/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang

8、启动geth客户端

这是我启动的geth客户端,rpc端口为8100
geth_test --datadir ./data0 --targetgaslimit 0x5000000000 --nmsaddr 127.0.0.1:9100 --rpc --rpcaddr 127.0.0.1 --rpcport 8100 --port 30300 --rpccorsdomain data0 data1 data2 gdpos_genesis.json --rpcapi db,eth,net,web3,personal --networkid 10001

修改配置文件truffle-config.js

  networks: {
    // Useful for testing. The `development` name is special - truffle uses it by default
    // if it's defined here and no other network is specified at the command line.
    // You should run a client (like ganache-cli, geth or parity) in a separate terminal
    // tab if you use this network and you must also set the `host`, `port` and `network_id`
    // options below to some value.
    //
    development: {
      host: "127.0.0.1",     // Localhost (default: none)
      port: 8100,            // Standard Ethereum port (default: none)
      network_id: "*",       // Any network (default: none)
    },

9、部署合约

truffle migrate

出现以下错误:

HelloWorld truffle migrate

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.



Starting migrations...
======================
> Network name:    'development'
> Network id:      1357
> Block gas limit: 0x5000000000


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------

Error: Error: Error:  *** Deployment Failed ***

"Migrations" -- Returned error: authentication needed: password or unlock.

    at Object.run (/Users/JC/.nvm/versions/node/v12.10.0/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:96:1)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
Truffle v5.0.35 (core: 5.0.35)
Node v12.10.0

原因是账号没有解锁
解锁如下:

geth_test attach ipc://Users/JC/Documents/project/grg_blockchain/tmp/test/data0/geth.ipc
Welcome to the Geth JavaScript console!

 instance: Geth/v1.7.4-stable-03c7946b/darwin-amd64/go1.10.3
validator: 0x564eec478efa01313d458b7b6a2edf124cc51fbf
 coinbase: 0x564eec478efa01313d458b7b6a2edf124cc51fbf
 at block: 2674 (Sun, 08 Sep 2019 15:05:28 CST)
  datadir: /Users/JC/Documents/project/grg_blockchain/tmp/test/data0
  modules: admin:1.0 debug:1.0 eth:1.0 gdpos:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

> personal.unlockAccount(eth.coinbase)
Unlock account 0x564eec478efa01313d458b7b6a2edf124cc51fbf
Passphrase:
true

账号解锁完后重新执行truffle migrate

HelloWorld truffle migrate

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.



Starting migrations...
======================
> Network name:    'development'
> Network id:      1357
> Block gas limit: 0x5000000000


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > transaction hash:    0x5383f376c5e4b8250720c420265892094ed4f840606b52a2528842cd4757a866
   > Blocks: 0            Seconds: 4
   > contract address:    0x9beed20097892e30918E211434aE75b85B58C871
   > block number:        2830
   > block timestamp:     1567926878
   > account:             0x76EFB705ccE44Eb65e684c4bFa8ebDa6EbF5baFd
   > balance:             4382.72737498
   > gas used:            251300
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.005026 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:            0.005026 ETH


2_initial_helloworld.js
=======================

   Deploying 'HelloWorld'
   ----------------------
   > transaction hash:    0xa6c1bcce50a03dd20b2d50f11221df0ef8dce5a1ebd3a50279489f8e04c30a01
   > Blocks: 0            Seconds: 0
   > contract address:    0x9171D0789DF9F488321D07C404A2A6F9b3d9737A
   > block number:        2832
   > block timestamp:     1567926880
   > account:             0x76EFB705ccE44Eb65e684c4bFa8ebDa6EbF5baFd
   > balance:             4382.71963578
   > gas used:            344932
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.00689864 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.00689864 ETH


Summary
=======
> Total deployments:   2
> Final cost:          0.01192464 ETH

10、运行合约

truffle console       # 进入命令行模式
truffle(development)> helloworld=await HelloWorld.deployed()
undefined
truffle(development)> helloworld.greet.call()
'hello world'
truffle(development)> helloworld.setGreeting("Hi world")
{
  tx: '0x4a518f5fad55e087cb058dc84aaa2e61d5c94fa735ea54a6439cf0e1cd36f68f',
  receipt: {
    blockHash: '0x6a2a41ac78f7f469ab4d4add98be0a5ab1b0079d7566ce2be37715e1877cb919',
    blockNumber: 2890,
    contractAddress: null,
    cumulativeGasUsed: 33464,
    from: '0x76efb705cce44eb65e684c4bfa8ebda6ebf5bafd',
    gasUsed: 33464,
    logs: [],
    logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    status: true,
    to: '0x9171d0789df9f488321d07c404a2a6f9b3d9737a',
    transactionHash: '0x4a518f5fad55e087cb058dc84aaa2e61d5c94fa735ea54a6439cf0e1cd36f68f',
    transactionIndex: 0,
    type: 0,
    rawLogs: []
  },
  logs: []
}
truffle(development)> helloworld.greet.call()
'Hi world'

参考:
github原文链接
以太坊智能合约Hello World示例程序
以太坊私有链下智能合约部署
用Solidity在Truffle上构建一个HelloWorld智能合约
solidity中文文档
solidity英文版

上一篇 下一篇

猜你喜欢

热点阅读