本文编写于 1058 天前,最后修改于 1044 天前,其中某些信息可能已经过时。

随着瞎搞随着更新吧

环境搭建

从一开始,就已经在采坑了……

solc的正确打开方式

使用snap(x
使用ppa(x
使用solc-select(√
参照usage就可以了,主要是solc这鬼玩意儿,版本之间相差巨大,所以版本管理就非常重要(

abigen

go get -u github.com/ethereum/go-ethereum
$GOPATH/src/github.com/ethereum/go-ethereum
make

无事发生

搭建私链

同abigen,使用make geth编译geth,然后丢到GOBIN

创建私链

配置创世的JSON,这里随便写个chainId 10

{
    "config": {
        "chainId": 10,
        "homesteadBlock": 0,
        "byzantiumBlock": 0,
        "constantinopleBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0,
        "eip150Block": 0,
        "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000"
    },
    "coinbase": "0x0000000000000000000000000000000000000000",
    "difficulty": "0x20000",
    "extraData": "",
    "gasLimit": "0xffffffff",
    "nonce": "0x0000000000000042",
    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp": "0x00",
    "alloc": {}
}

然后geth --datadir chain init genesis.json初始化
之后就可以geth --datadir chain --networkid 1108 console --rpc --rpccorsdomain "*"启动rpc和console了,也随便指定一个networkid,CORS直接*了,反正是测试瞎搞就完事儿了(
console里新建或者导入几个账户用于测试,然后miner.start(1)用一个核心挖着矿打包区块就好了

MetaMask连接私链RPC的坑

连接本身到是还好,但是用起来之后,问题就比较多了……大部分其实都是geth那边创世的问题,上面的JSON已经是改好的了,真正metamask的锅也就这一个

重设创世区块导致的交易问题

当我试着转账时,看到getheth_sendRawTransaction报错already known
一开始是莫名其妙的……后来搜了下,因为我重置了创世区块,之前的交易记录冲突了,去metamask里设置->高级->重设账户

区块浏览器

感觉区块浏览器的需求还是挺强的,但是目前好用的没几个……
etherscan啥时候开源啊(x
找了一圈,就expedition感觉还可

合约部署

先随便撸一个简单的合约

pragma solidity ^0.8.1;

contract Sell {
    address public seller;
    address public buyer;
    uint256 public value;
    enum Status {Created, Paid}
    Status public state;

    constructor(uint256 amount) {
        seller = msg.sender;
        value = amount;
        state = Status.Created;
    }

    event Paid();

    function pay() public payable {
        require(state == Status.Created, "Invalid state");
        require(msg.value == value, "Amount not match");
        state = Status.Paid;
        buyer = msg.sender;
        payable(seller).transfer(msg.value);
        emit Paid();
    }
}

然后用abigen生成go文件

abigen -sol ./contract/sell.sol -pkg contract -out ./contract/sell.go

然后用就完事儿了

package main

import (
    "contract-demo/contract"
    "fmt"
    "io/ioutil"
    "log"
    "math/big"
    "strings"

    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/ethclient"
)

const sellerKey = "UTC--2021-02-27T16-36-04.819Z--0af52345495c7bb2335905aedd117ff2d671eccc"
const buyerKey = "UTC--2021-02-27T16-36-04.819Z--0af52345495c7bb2335905aedd117ff2d671eccc"

func main() {
    // 连接到rpc
    blockchain, err := ethclient.Dial("http://127.0.0.1:8545")
    if err != nil {
        log.Fatalf("Unable to connect to network:%v \n", err)
    }

    // 卖家auth
    sellerData, _ := ioutil.ReadFile(sellerKey)
    sellerAuth, err := bind.NewTransactorWithChainID(strings.NewReader(string(sellerData)), "password", big.NewInt(int64(10)))
    if err != nil {
        log.Fatalf("Failed to create authorized transactor:%v \n", err)
    }
    // 创建合约Sell
    contractAddress, _, _, err := contract.DeploySell(
        sellerAuth,
        blockchain,
        big.NewInt(int64(1000)),
    )
    if err != nil {
        log.Fatalf("deploy %v \n", err)
    }
    // INFO [06-02|12:58:13.916] Submitted contract creation
    // hash=0x21acfcfbcb748fb1cad84471914d630ad5dbd3aaa833a2b80b0c8bb2efa0e962
    // from=0x0AF52345495c7Bb2335905AEDD117FF2d671EcCC
    // nonce=5
    // contract=0x03594C94f2B8936b204f5D0bE2052B9ca46bf002 value=0
    fmt.Printf("Contract pending deploy:0x%x \n", contractAddress)
    // Contract pending deploy:0x03594c94f2b8936b204f5d0be2052b9ca46bf002

    // 买家auth
    buyerData, _ := ioutil.ReadFile(buyerKey)
    buyerAuth, err := bind.NewTransactorWithChainID(strings.NewReader(string(buyerData)), "password", big.NewInt(int64(10)))
    if err != nil {
        log.Fatalf("Failed to create authorized transactor:%v \n", err)
    }
    // 调用pay支付
    // contractObj, err := contract.NewSell(common.HexToAddress("0x03594C94f2B8936b204f5D0bE2052B9ca46bf002"), blockchain)
    contractObj, err := contract.NewSell(contractAddress, blockchain)
    if err != nil {
        log.Fatalf("conn contract: %v \n", err)
    }
    // 附加transact
    transact := &bind.TransactOpts{
        From:   buyerAuth.From,
        Signer: buyerAuth.Signer,
        Value:  big.NewInt(int64(1000)),
    }

    fmt.Println(contractObj.Pay(transact))
}