Golang Ethereum Scan 一些方法

yufei       1 年, 7 月 前       1745

Golang Ethereum Scan 一些方法

package main

import (
    "context"
    "crypto/ecdsa"
    "crypto/hmac"
    "crypto/rand"
    "crypto/sha256"
    "encoding/base64"
    "encoding/hex"
    "encoding/json"
    "errors"
    "fmt"
    "log"
    "math"
    "math/big"
    "strings"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/common/hexutil"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/ethclient"
    "github.com/forgoer/openssl"
    bigdecimal "github.com/pingcap/tidb/util/types"
)

var pow10 [19]int64 = [19]int64{
    0,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000,
    100000000,
    1000000000,
    10000000000,
    100000000000,
    1000000000000,
    10000000000000,
    100000000000000,
    1000000000000000,
    10000000000000000,
    100000000000000000,
    1000000000000000000,
}

// 支持两种key格式
const EncrypterKey = "base64:Z7zuNXGx1vdxG0HAyIIVh6Cy8TuTh9fimtpp1/V29Rc="

var zero *big.Int = big.NewInt(0)

var client *ethclient.Client

// Encrypt 加密
func Encrypt(value string) (string, error) {
    iv := make([]byte, 16)
    _, err := rand.Read(iv)
    if err != nil {
        return "", err
    }

    key := getKey()
    //加密value
    res, err := openssl.AesCBCEncrypt([]byte(value), []byte(key), iv, openssl.PKCS7_PADDING)
    if err != nil {
        return "", err
    }

    //base64加密
    resVal := base64.StdEncoding.EncodeToString(res)
    resIv := base64.StdEncoding.EncodeToString(iv)

    //生成mac值
    data := resIv + resVal
    mac := computeHmacSha256(data, key)

    //构造ticket结构
    ticket := make(map[string]interface{})
    ticket["iv"] = resIv
    ticket["mac"] = mac
    ticket["value"] = resVal

    //json序列化
    resTicket, err := json.Marshal(ticket)
    if err != nil {
        return "", err
    }
    //base64加密ticket
    ticketR := base64.StdEncoding.EncodeToString(resTicket)

    return ticketR, nil
}

// Decrypt 解密
func Decrypt(value string) (string, error) {
    //base64解密
    token, err := base64.StdEncoding.DecodeString(value)
    if err != nil {
        return "", err
    }

    //json反序列化
    tokenJson := make(map[string]string)
    err = json.Unmarshal(token, &tokenJson)
    if err != nil {
        return "", err
    }

    tokenJsonIv, okIv := tokenJson["iv"]
    tokenJsonValue, okValue := tokenJson["value"]
    tokenJsonMac, okMac := tokenJson["mac"]
    if !okIv || !okValue || !okMac {
        return "", errors.New("value is not full")
    }

    key := getKey()

    //mac检查,防止数据篡改
    data := tokenJsonIv + tokenJsonValue
    check := checkMAC(data, tokenJsonMac, key)
    if !check {
        return "", errors.New("mac valid failed")
    }

    //base64解密iv和value
    tokenIv, err := base64.StdEncoding.DecodeString(tokenJsonIv)
    if err != nil {
        return "", err
    }
    tokenValue, err := base64.StdEncoding.DecodeString(tokenJsonValue)
    if err != nil {
        return "", err
    }
    //aes解密value
    dst, err := openssl.AesCBCDecrypt(tokenValue, []byte(key), tokenIv, openssl.PKCS7_PADDING)
    if err != nil {
        return "", err
    }

    return string(dst), nil

}

// 比较预期的hash和实际的hash
func checkMAC(message, msgMac, secret string) bool {
    expectedMAC := computeHmacSha256(message, secret)
    return hmac.Equal([]byte(expectedMAC), []byte(msgMac))
}

// 计算mac值
func computeHmacSha256(message string, secret string) string {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    sha := hex.EncodeToString(h.Sum(nil))
    return sha
}

// 处理密钥
func getKey() string {
    appKey := EncrypterKey
    if strings.HasPrefix(appKey, "base64:") {
        split := appKey[7:]
        if key, err := base64.StdEncoding.DecodeString(split); err == nil {
            return string(key)
        }
        return split
    }
    return appKey
}

func main() {

    // 开始监听最新快
    SubscribeNewBlock()
    return

    raw := "1d2f29de47fd1bd8d33755de0d3e13e9ed5dd1ecb1abc94651d5e234f4edc053"
    de, err := Encrypt(raw)
    if err != nil {
        panic(de)
    }
    println(de)

    sst, err := Decrypt("eyJpdiI6ImlzXC8rMHozWWxTclhpNFBFRDBBbWx3PT0iLCJ2YWx1ZSI6IkFPSGRxekZlSUxsQWpLZkgwN0tRXC9JWWRraXErNFNrMUFONW04WTZrZUFlOWRFTTRJTGdiK2FPVU93VkNmV0VcL2tibE9obDhPR3lQY0wwT1U2Z01YS2Q3THpFV1FlK0JMNjdtRmlleTI1ajQ9IiwibWFjIjoiOGEzODU0NjI4ZWFkNTdjMGE2YzI0Zjc0Njc3MzY2NGE1OGEzYTQ2MDJkMGRlNjBkYTgwYTU4ZTYzZmUzZWYwYiJ9")
    if err != nil {
        panic(err)
    }
    println(sst)

    client, err = ethclient.Dial("http://127.0.0.1:8545")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("we have a connection")

    balance, err := getBalance("0x7354Bd0d54C6f67C735F3576bf4d2e3914bbf4E5", false)
    if err != nil {
        panic(err)
    }
    fmt.Println(balance)
    x, _ := ToEth(balance, 18)

    fixed, err := ToFixed(x, 8)
    if err != nil {
        panic(err)
    }
    fmt.Println(fixed)

    ss := new(bigdecimal.MyDecimal)
    ss.FromString([]byte("-31.4159286783993333"))

    for i := 8; i >= -4; i = i - 1 {
        fixed, err := ToFixed(ss, i)
        if err != nil {
            panic(err)
        }
        fmt.Println(i, ":", fixed)
    }

    // 最新块高
    headerBlock, err := blockNumber()
    if err != nil {
        panic(err)
    }
    println(headerBlock.String())

    // 获取块的信息
    block, err := getBlockByNumber(headerBlock.Int64(), true)
    if err != nil {
        panic(err)
    }
    fmt.Println(block.Number().Uint64())     // 5671744
    fmt.Println(block.Time())                // 1527211625
    fmt.Println(block.Difficulty().Uint64()) // 3217000136609065
    fmt.Println(block.Hash().Hex())          // 0x9e8751ebb5069389b855bba72d94902cc385042661498a415979b7b6ee9ba4b9
    fmt.Println(len(block.Transactions()))   // 144
    for _, tx := range block.Transactions() {
        println("---")
        fmt.Println(tx.Hash().Hex())           // 0x5d49fcaa394c97ec8a9c3e7bd9e8388d420fb050a52083ca52ff24b3b65bc9c2
        fmt.Println(tx.Value().String())       // 10000000000000000
        fmt.Println(tx.Gas())                  // 105000
        fmt.Println(tx.GasPrice().Uint64())    // 102000000000
        fmt.Println(tx.Nonce())                // 110644
        fmt.Println(hexutil.Encode(tx.Data())) // []
        fmt.Println(tx.To().Hex())

        from, _ := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)

        println(from.Hex())
        println("---\n\n")
    }

    // 获取块内的交易事物数量
    count, err := getBlockTransactionCountByNumber(block.Hash())
    if err != nil {
        panic(err)
    }
    println(count)

    // 获取交易信息
    tx, err := getTransaction(common.HexToHash("0xadf77ccfdc7aca967642a772d58034a7747a4d905ae34d667e625f275cdb6d46"))
    if err != nil {
        panic(err)
    }
    println("---")
    fmt.Println(tx.Hash().Hex())           // 0x5d49fcaa394c97ec8a9c3e7bd9e8388d420fb050a52083ca52ff24b3b65bc9c2
    fmt.Println(tx.Value().String())       // 10000000000000000
    fmt.Println(tx.Gas())                  // 105000
    fmt.Println(tx.GasPrice().Uint64())    // 102000000000
    fmt.Println(tx.Nonce())                // 110644
    fmt.Println(hexutil.Encode(tx.Data())) // []
    fmt.Println("to:", tx.To().Hex())

    from, _ := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)

    println(from.Hex())
    println("---\n\n")

    println("receipt----")
    // 获取 tx 确认
    receipt, err := getTransactionReceipt(common.HexToHash("0xadf77ccfdc7aca967642a772d58034a7747a4d905ae34d667e625f275cdb6d46"))
    if err != nil {
        panic(err)
    }
    fmt.Println(receipt.Status) // 1
    fmt.Println(receipt.ContractAddress.Hex())
    for _, log := range receipt.Logs {
        fmt.Println(hexutil.Encode(log.Data))
        fmt.Println(log.Topics[0])
        fmt.Println(log.Topics[1])
        fmt.Println(log.Topics[2].Hex())
        trueBalance, _ := ToEth(new(big.Int).SetBytes(log.Data), 18)
        fmt.Println(trueBalance)
    }

    token_balance, err := getTokenBalance(
        "0x69c9b0766b35aD76fAA9A627c2F49ed093F66aC6",
        "0x4f1Ec6073E4056Ea7c1172bB810Eaa6981297672",
        headerBlock.Int64(),
        true,
    )

    if err != nil {
        panic(err)
    }

    println("token_balance:", token_balance)
    trueBalance, _ := ToEth(token_balance, 18)
    savedBalance, _ := ToFixed(trueBalance, 8)
    println(token_balance.String(), trueBalance.String(), savedBalance)

    return
    amount2, _ := ToWei("0.153", 18)
    // 发送交易
    txx2, err := SendTokenRaw(
        "0x69c9b0766b35aD76fAA9A627c2F49ed093F66aC6",
        "f4e26e3648f9c730389cb73908cee6364671aa6f4ebd8dbb08b15336f6e0b68e",
        "0x7354Bd0d54C6f67C735F3576bf4d2e3914bbf4E5",
        "0x4f1Ec6073E4056Ea7c1172bB810Eaa6981297672",
        amount2.String(),
        0)
    if err != nil {
        panic(err)
    }
    fmt.Println("send hash:" + txx2.Hex())

    return

    return
    // 发送交易
    txx, err := SendEth(
        "0xe6Ec45704c9872041b9a18bbEd850de06B0F3c7A",
        "392bc46febcb4470c7c7a369acbc605e5431b2342698d0bc38ccd49c8a38e5cb",
        "0x7354Bd0d54C6f67C735F3576bf4d2e3914bbf4E5",
        "0.1345",
        0)
    if err != nil {
        panic(err)
    }
    fmt.Println("send hash:" + txx.Hex())

    return
    // 生成新地址
    address, err := Generate()
    if err != nil {
        panic(err)
    }

    t, err := json.Marshal(address)
    if err != nil {
        panic(err)
    }
    println(string(t))
}

func getBalance(addr string, pending bool) (*big.Int, error) {
    account := common.HexToAddress(addr)
    if !pending {
        return client.BalanceAt(context.Background(), account, nil)
    }
    return client.PendingBalanceAt(context.Background(), account)
}

func getTokenBalance(addr string, contract string, blockNum int64, pending bool) (*big.Int, error) {
    tokenAddress := common.HexToAddress(contract)
    toAddress := common.HexToAddress(addr)
    paddedAddress := common.LeftPadBytes(toAddress.Bytes(), 32)
    var data []byte
    methodId, _ := hexutil.Decode("0x70a08231")
    data = append(data, methodId...)
    data = append(data, paddedAddress...)

    callMsg := ethereum.CallMsg{
        To:   &tokenAddress,
        Data: data,
    }
    response, err := client.CallContract(context.Background(), callMsg, big.NewInt(blockNum))
    if err != nil {
        return nil, err
    }
    return new(big.Int).SetBytes(response), nil
}

func ToEth(fbalance *big.Int, precision int) (*bigdecimal.MyDecimal, error) {

    dec1 := new(bigdecimal.MyDecimal)
    err := dec1.FromString([]byte(fbalance.String()))
    if err != nil {
        return nil, errors.New("单位转换失败")
    }
    dec2 := new(bigdecimal.MyDecimal)
    dec2.FromFloat64(math.Pow10(precision))

    dec3 := new(bigdecimal.MyDecimal)
    err = bigdecimal.DecimalDiv(dec1, dec2, dec3, precision)
    if err != nil {
        return nil, errors.New("单位转化失败")
    }

    var ss bigdecimal.MyDecimal
    dec3.Round(&ss, precision, bigdecimal.ModeTruncate)
    return &ss, nil
}

func ToWei(fbalance string, precision int) (*big.Int, error) {

    dec1 := new(bigdecimal.MyDecimal)
    err := dec1.FromString([]byte(fbalance))
    if err != nil {
        return nil, errors.New("单位转换失败")
    }
    dec2 := new(bigdecimal.MyDecimal)
    dec2.FromFloat64(math.Pow10(precision))

    dec3 := new(bigdecimal.MyDecimal)
    err = bigdecimal.DecimalMul(dec1, dec2, dec3)
    if err != nil {
        return nil, errors.New("单位转化失败")
    }

    var ss bigdecimal.MyDecimal
    dec3.Round(&ss, 0, bigdecimal.ModeTruncate)
    rs, _ := new(big.Int).SetString(ss.String(), 10)
    return rs, nil
}

func IntPow(n int64, m int) int64 {
    if m == 0 {
        return 1
    }
    result := n
    for i := 2; i <= m; i++ {
        result *= n
    }
    return result
}

func ToFixed(src *bigdecimal.MyDecimal, prec int) (string, error) {
    var ss bigdecimal.MyDecimal
    err := src.Round(&ss, prec, bigdecimal.ModeTruncate)
    if err != nil {
        return "", err
    }
    return ss.String(), nil
}

type NewAddress struct {
    Address    string `json:"address"`
    PrivateKey string `json:"private_pey"`
}

func Generate() (*NewAddress, error) {
    privateKey, err := crypto.GenerateKey()
    if err != nil {
        return nil, err
    }

    address := &NewAddress{}

    privateKeyBytes := crypto.FromECDSA(privateKey)
    address.PrivateKey = hexutil.Encode(privateKeyBytes)[2:]

    publicKey := privateKey.Public()
    publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
    if !ok {
        return nil, errors.New("error casting public key to ECDSA")
    }
    address.Address = crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
    return address, nil
}

func blockNumber() (*big.Int, error) {
    header, err := client.HeaderByNumber(context.Background(), nil)
    if err != nil {
        return nil, err
    }
    return header.Number, nil
}

func getBlockByNumber(block_num int64, returnTx bool) (*types.Block, error) {
    blockNumber := big.NewInt(block_num)
    block, err := client.BlockByNumber(context.Background(), blockNumber)
    return block, err
}

func getBlockTransactionCountByNumber(hash common.Hash) (uint, error) {
    count, err := client.TransactionCount(context.Background(), hash)
    return count, err
}

func getTransaction(hash common.Hash) (*types.Transaction, error) {
    tx, _, err := client.TransactionByHash(context.Background(), hash)
    return tx, err
}

func getTransactionReceipt(hash common.Hash) (*types.Receipt, error) {
    return client.TransactionReceipt(context.Background(), hash)
}

func SendEth(from string, private_key string, to string, amount string, gas_price int64) (*common.Hash, error) {
    privateKey, err := crypto.HexToECDSA(private_key)
    if err != nil {
        return nil, err
    }

    fromAddress := common.HexToAddress(from)
    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        return nil, err
    }

    value, _ := ToWei(amount, 18)
    gasLimit := uint64(1000000) // in units
    gasPrice, err := client.SuggestGasPrice(context.Background())
    fmt.Println(value.String())
    if err != nil {
        return nil, errors.New("获取 gasPrice 失败")
    }

    toAddress := common.HexToAddress(to)
    var data []byte
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, data)

    chainID, err := client.NetworkID(context.Background())
    if err != nil {
        return nil, errors.New("获取网络ID 失败")
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        return nil, errors.New("签名失败")
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        return nil, errors.New("发送交易失败:" + err.Error())
    }

    hash := signedTx.Hash()
    return &hash, nil

}

func SendTokenRaw(from string, private_key string, to string, contract string, amount string, gas_price int64) (*common.Hash, error) {

    privateKey, err := crypto.HexToECDSA(private_key)
    if err != nil {
        return nil, err
    }

    fromAddress := common.HexToAddress(from)
    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        return nil, err
    }

    gasLimit := uint64(1000000) // in units
    value, _ := new(big.Int).SetString(amount, 10)

    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        return nil, err
    }

    toAddress := common.HexToAddress(to)
    tokenAddress := common.HexToAddress(contract)

    paddedAddress := common.LeftPadBytes(toAddress.Bytes(), 32)
    fmt.Println(hexutil.Encode(paddedAddress)) // 0x0000000000000000000000004592d8f8d7b001e72cb26a73e4fa1806a51ac79d

    paddedAmount := common.LeftPadBytes(value.Bytes(), 32)
    fmt.Println(hexutil.Encode(paddedAmount)) // 0x00000000000000000000000000000000000000000000003635c9adc5dea00000

    var data []byte
    methodId, _ := hexutil.Decode("0xa9059cbb")
    data = append(data, methodId...)
    data = append(data, paddedAddress...)
    data = append(data, paddedAmount...)
    tx := types.NewTransaction(nonce, tokenAddress, zero, gasLimit, gasPrice, data)

    chainID, err := client.NetworkID(context.Background())
    if err != nil {
        return nil, errors.New("获取网络ID 失败")
    }

    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
    if err != nil {
        return nil, errors.New("签名失败")
    }

    err = client.SendTransaction(context.Background(), signedTx)
    if err != nil {
        return nil, errors.New("发送交易失败:" + err.Error())
    }

    hash := signedTx.Hash()
    return &hash, nil
}

func SubscribeNewBlock() {
    ws, err := ethclient.Dial("")
    if err != nil {
        log.Fatal(err)
    }

    println("websocket dial ok")
    headers := make(chan *types.Header)
    sub, err := ws.SubscribeNewHead(context.Background(), headers)
    if err != nil {
        log.Fatal(err)
    }

    println("subscribe ok")

    for {
        select {
        case err := <-sub.Err():
            println("error")
            log.Fatal(err)
            break
        case header := <-headers:
            fmt.Println(header.Hash().Hex()) // 0xbc10defa8dda384c96a17640d84de5578804945d347072e091b4e5f390ddea7f

            block, err := ws.BlockByHash(context.Background(), header.Hash())
            if err != nil {
                println("error")
                log.Fatal(err)
            }

            fmt.Println(block.Hash().Hex())        // 0xbc10defa8dda384c96a17640d84de5578804945d347072e091b4e5f390ddea7f
            fmt.Println(block.Number().Uint64())   // 3477413
            fmt.Println(block.Time())              // 1529525947
            fmt.Println(block.Nonce())             // 130524141876765836
            fmt.Println(len(block.Transactions())) // 7
            for _, tx := range block.Transactions() {
                println("---")
                fmt.Println(tx.Hash().Hex())           // 0x5d49fcaa394c97ec8a9c3e7bd9e8388d420fb050a52083ca52ff24b3b65bc9c2
                fmt.Println(tx.Value().String())       // 10000000000000000
                fmt.Println(tx.Gas())                  // 105000
                fmt.Println(tx.GasPrice().Uint64())    // 102000000000
                fmt.Println(tx.Nonce())                // 110644
                fmt.Println(hexutil.Encode(tx.Data())) // []
                if tx.To() != nil {
                    fmt.Println(tx.To().Hex())
                }

                from, _ := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)

                println(from.Hex())
                println("---\n\n")
            }
        }
    }
}
目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.