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") } } } }
目前尚无回复