本文使用的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
}
基于比特币开发的代币,节点功能方法几乎一样,可以共用