bitcoin,btc比特币 转账,jsonrpc功能,开发语言golang

功能列表
  • 创建地址
  • 统计某个地址收到指定币数以上的币总量
  • 获取账户余额–根据节点确认数提取未消费记录,统计
  • 返回钱包中所有账户(或者指定账户)的btc数量
  • 返回账户未消费记录,根据确认数提取
  • 创建裸交易
  • 填充找零地址
  • 签名交易
  • 广播交易到p2p网络中
  • 发起交易 --(外部调用方法)

本文使用的Bitcoin版本: v0.20.0

package ltc

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"service/app/core/db"
	"service/app/core/model"
	"service/config"
	"strconv"
	"time"
)

const (
	//RPCURL url
	RPCURL = "http://x.x.x.x:9332"
	//JSONRpcVersion 版本
	JSONRpcVersion = "2.0"
	//COMPONY 公司拨款地址
	COMPONY = "xxxxxxxxxxxxxxxxxxxxxxxxx"
)

var (
	//ID 自增id
	ID int
)

//GetNewAddress 创建地址
func GetNewAddress(name string) (string, error) {
	var (
		params = []interface{}{
			name, //新地址所属账户,可选,默认值:""
		}

		jsonData map[string]interface{}
		result   []byte
		err      error
	)

	result = JSONRPCPost("getnewaddress", params)
	err = json.Unmarshal(result, &jsonData)
	if err != nil {
		return "", err
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			return "", errors.New(e.(string))
		}
	}
	return jsonData["result"].(string), nil
}

//GetReceivedByAddress 调用返回指定地址收到的达到指定确认数的比特币总数量, 其中不包括币基交易。
func GetReceivedByAddress(address string) float64 {
	var (
		params = []interface{}{
			address, //要进行统计的钱包地址
			6,       //所需要的最小确认数,默认:6
		}
		jsonData  map[string]interface{}
		result    []byte
		newAmount float64
		err       error
	)
	result = JSONRPCPost("getreceivedbyaddress", params)
	err = json.Unmarshal(result, &jsonData)
	if err != nil {
		log.Print(err.Error())
		return 0
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			log.Print(err.Error())

			return 0
		}
	}
	// log.Print(jsonData)
	//根据最小充值数量,保留小数位数 TODO:
	newAmount, err = strconv.ParseFloat(fmt.Sprintf("%.2f", jsonData["result"]), 64)
	if err != nil {
		return 0
	}
	return newAmount
}

//GetBalanceByAddress 获取账户余额,根据确认数提取未消费记录,统计交易额
func GetBalanceByAddress(address []string) float64 {
	var (
		params = []interface{}{
			6,        //交易最少确认数,默认值:1
			99999999, //交易最多确认数,默认值:9999999
			address,  //交易输出中应当包含的地址数组
		}
		jsonData map[string]interface{}
		result   []byte
		err      error
		amount   float64
	)
	result = JSONRPCPost("listunspent", params)
	err = json.Unmarshal(result, &jsonData)
	log.Print(jsonData)
	if err != nil {
		return 0
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			return 0
		}
	}
	log.Print(jsonData["result"])
	for _, v := range jsonData["result"].([]interface{}) {
		newV := v.(map[string]interface{})
		num := newV["amount"].(float64)
		if num > 0 && num >= minNum {
			amount += num
		}
	}
	return amount

}

//GetBalance 调用返回钱包中所有账户(或指定账户)的ltc数量
func GetBalance(label string) float64 {
	var (
		params = []interface{}{
			label, //要查看余额的钱包账户,可选,默认值为*,表示全部账户
			6,     //可计入余额的UTXO所需要的最小确认数,可选,默认值:6
			true,  //是否包含那些仅用于跟踪的地址,可选,默认值:true
		}
		jsonData map[string]interface{}
		result   []byte
		err      error
	)
	result = JSONRPCPost("getbalance", params)
	err = json.Unmarshal(result, &jsonData)
	if err != nil {
		return 0
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			return 0
		}
	}
	return jsonData["result"].(float64)
}

//GetUTXORecordByAddress 获取账户余额,根据确认数提取未消费记录
func GetUTXORecordByAddress(address []string) []interface{} {
	var (
		params = []interface{}{
			6,        //交易最少确认数,默认值:1
			99999999, //交易最多确认数,默认值:9999999
			address,  //交易输出中应当包含的地址数组
		}
		jsonData map[string]interface{}
		result   []byte
		err      error
	)
	result = JSONRPCPost("listunspent", params)
	err = json.Unmarshal(result, &jsonData)
	if err != nil {
		log.Print(err.Error())
		return nil
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			log.Print(e.(map[string]interface{})["message"])
			return nil
		}
	}
	return jsonData["result"].([]interface{})
}

// 创建裸交易
//@param     input   拨款地址的所有UTXO的记录的txid,vout   output 收款地址信息  格式 收款地址:收款数量
func createRawtransaction(input, output []map[string]interface{}) (interface{}, error) {
	var (
		params   []interface{}
		result   []byte
		err      error
		jsonData map[string]interface{}
	)
	params = append(params, input)
	params = append(params, output)
	result = JSONRPCPost("createrawtransaction", params)
	err = json.Unmarshal(result, &jsonData)
	if err != nil {
		return nil, err
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			return nil, errors.New(e.(map[string]interface{})["message"].(string))
		}
	}
	return jsonData["result"], nil
}

//填充找零地址
//@param hex    createrawtransaction 返回的未签名交易的字符串
//@param options  设置找零地址和其余配置
func fundRawtransaction(hex interface{}) (interface{}, error) {
	var (
		options = map[string]interface{}{
			"changeAddress":   COMPONY,
			"changePosition":  1,
			"includeWatching": false,
			"lockUnspents":    false,
			"feeRate":         0.00002,
		}
		params = []interface{}{
			hex,
			options,
		}
		result   []byte
		err      error
		jsonData map[string]interface{}
	)
	result = JSONRPCPost("fundrawtransaction", params)
	err = json.Unmarshal(result, &jsonData)
	if err != nil {
		return nil, err
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			return nil, errors.New(e.(map[string]interface{})["message"].(string))
		}
	}

	return jsonData["result"].(map[string]interface{})["hex"], nil
}

//签名交易
//@param  hex  fundrawtransaction返回的hex字符串
func signRawtransactionwallet(hex interface{}) (interface{}, error) {
	var (
		params = []interface{}{
			hex,
		}
		result   []byte
		err      error
		jsonData map[string]interface{}
	)
	result = JSONRPCPost("signrawtransactionwithwallet", params)
	err = json.Unmarshal(result, &jsonData)
	if err != nil {
		return nil, err
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			return nil, errors.New(e.(map[string]interface{})["message"].(string))
		}
	}
	returnData := jsonData["result"].(map[string]interface{})
	if !returnData["complete"].(bool) {
		return nil, errors.New("No complete signature set")
	}
	return returnData["hex"], nil
}

//广播交易到P2P网络中
//@param  hex signrawtransactionwithwallet返回的hex字符串
func sendRawtransaction(hex interface{}) (interface{}, error) {
	var (
		params = []interface{}{
			hex,
		}
		result   []byte
		err      error
		jsonData map[string]interface{}
	)
	result = JSONRPCPost("sendrawtransaction", params)
	err = json.Unmarshal(result, &jsonData)
	if err != nil {
		return nil, err
	}
	if e, ok := jsonData["error"]; ok {
		if e != nil {
			return nil, errors.New(e.(map[string]interface{})["message"].(string))
		}
	}
	return jsonData["result"], nil
}

//SendTransaction 交易
//@param address 收款地址  string
//@param amount 收款数量 float64
func SendTransaction(address string, amount float64) (string, error) {
	var (
		list                                             []interface{}
		input                                            []map[string]interface{}
		output                                           []map[string]interface{}
		amountAll                                        float64
		createResult, fundResult, signResult, sendResult interface{}
		err                                              error
	)

	list = GetUTXORecordByAddress([]string{COMPONY})
	if len(list) <= 0 {
		return "", errors.New("暂无UTXO未消费记录")
	}
	for _, v := range list {
		newV := v.(map[string]interface{})
		input = append(input, map[string]interface{}{
			"txid": newV["txid"],
			"vout": newV["vout"],
		})
		amountAll += newV["amount"].(float64)
	}
	if amountAll < amount {
		return "", errors.New("地址余额不足")
	}
	output = append(output, map[string]interface{}{
		address: amount,
	})
	createResult, err = createRawtransaction(input, output)
	if err != nil {
		return "", errors.New("createRawtransaction" + err.Error())
	}
	fundResult, err = fundRawtransaction(createResult)
	if err != nil {
		return "", errors.New("fundRawtransaction" + err.Error())
	}
	signResult, err = signRawtransactionwallet(fundResult)
	if err != nil {
		return "", errors.New("signRawtransactionwallet" + err.Error())
	}
	sendResult, err = sendRawtransaction(signResult)
	if err != nil {
		return "", errors.New("sendRawtransaction" + err.Error())
	}
	return sendResult.(string), nil
}

//JSONRPCPost post请求
func JSONRPCPost(method string, params []interface{}) []byte {
	var (
		formData = map[string]interface{}{
			"jsonrpc": JSONRpcVersion,
			"id":      ID + 1,
			"method":  method,
			"params":  params,
		}
		httpClient    = &http.Client{}
		reqJSON, data []byte
		req           *http.Request
		resp          *http.Response

		err error
	)
	reqJSON, err = json.Marshal(formData)
	payloadBuffer := bytes.NewReader(reqJSON)
	req, err = http.NewRequest("POST", RPCURL, payloadBuffer)
	if err != nil {
		log.Print(err.Error())
		return nil
	}
	req.Header.Add("Content-Type", "application/json;charset=utf-8")
	req.Header.Add("Accept", "application/json")
	req.SetBasicAuth("test", "testpassword")
	resp, err = httpClient.Do(req)
	if err != nil {
		fmt.Println(err.Error())
		return nil
	}
	defer resp.Body.Close()
	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err.Error())
		return nil
	}
	return data
}

基于比特币开发的代币,节点功能方法几乎一样,可以共用

你可能感兴趣的:(go,区块链)