<|start_filename|>tracker/tracker_server.go<|end_filename|>
package main

import (
	"github.com/lestrrat-go/file-rotatelogs"
	"github.com/omnilaboratory/obd/tool"
	"github.com/omnilaboratory/obd/tracker/config"
	"github.com/omnilaboratory/obd/tracker/router"
	"github.com/omnilaboratory/obd/tracker/rpc"
	"github.com/omnilaboratory/obd/tracker/service"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

func initTrackerLog() {
	_dir := "log"
	_ = tool.PathExistsAndCreate(_dir)
	path := "log/tracker"
	writer, err := rotatelogs.New(
		path+".%Y%m%d%H%M.log",
		rotatelogs.WithMaxAge(30*24*time.Hour),
		rotatelogs.WithRotationTime(4*time.Hour),
	)
	if err != nil {
		panic(err)
	}
	writers := []io.Writer{
		os.Stdout,
		writer,
	}
	fileAndStdoutWriter := io.MultiWriter(writers...)
	log.SetOutput(fileAndStdoutWriter)
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

// gox -os "windows linux darwin" -arch amd64
// gox -os "linux" -arch amd64
func main() {
	initTrackerLog()

	err := rpc.NewClient().CheckVersion()
	if err != nil {
		log.Println(err)
		log.Println("because get wrong omniCore version, tracker fail to start")
		return
	}
	service.Start(cfg.ChainNode_Type)

	service.StartP2PNode()

	routersInit := router.InitRouter()
	if routersInit == nil {
		log.Println("fail to start tracker")
		return
	}
	addr := ":" + strconv.Itoa(cfg.TrackerServerPort)
	server := &http.Server{
		Addr:           addr,
		Handler:        routersInit,
		ReadTimeout:    cfg.ReadTimeout,
		WriteTimeout:   cfg.WriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}

	log.Println("tracker " + service.GetTrackerNodeId() + " start at port: " + strconv.Itoa(cfg.TrackerServerPort) + " in " + cfg.ChainNode_Type)
	log.Fatal(server.ListenAndServe())
}


<|start_filename|>omnicore/CreateRawOmniTransaction.go<|end_filename|>
package omnicore

import (
	"encoding/json"
	"io"
	"log"
	"strings"

	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
)

type Unspent struct {
	TxID     string `json:"txid"`
	VOut     uint32 `json:"vout"`
	Sequence uint32 `json:"sequence"`
}

type PrevTx struct {
	TxID         string `json:"txid"`
	VOut         uint32 `json:"vout"`
	ScriptPubKey string `json:"scriptPubKey"`
	Value        string `json:"value"`
}

func CheckUnspent(unspent_json_list string) (string, error) {

	return "", nil
}

/*
 * https://github.com/OmniLayer/omnicore/wiki/Use-the-raw-transaction-API-to-create-a-Simple-Send-transaction
 */

/*
 * step 3) Construct transaction base
 * omnicore-cli "createrawtransaction" '[{"txid":"c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de","vout":0},{"txid":"ee1673b09b0edaf7aaf8eb0bfd53a5a2757eb3e342e731bfc960b869aa0ab6b3","vout":2}]' '{}'
 *
 */
func CreateRawTransaction(unspent_json_list string, btc_version int32) (*wire.MsgTx, string, error) {
	// txFee := 10000
	// weird, there is no definition of TxVersion = 2, but version 2 works.
	//tx := wire.NewMsgTx(wire.TxVersion + 1)
	tx := wire.NewMsgTx(btc_version)

	decoder := json.NewDecoder(strings.NewReader(unspent_json_list))
	for {
		var unspentTx Unspent
		if err := decoder.Decode(&unspentTx); err == io.EOF {
			break
		} else if err != nil {
			log.Fatal(err)
		}

		hash, err := chainhash.NewHashFromStr(unspentTx.TxID)
		if err != nil {
			log.Fatalf("could not get hash from transaction ID: %v", err)
		}
		outPoint := wire.NewOutPoint(hash, unspentTx.VOut)
		txIn := wire.NewTxIn(outPoint, nil, nil)

		if unspentTx.Sequence != 0 {
			txIn.Sequence = unspentTx.Sequence
		}

		tx.AddTxIn(txIn)

		//fmt.Printf("%s \n ", txToHex(tx))

		//fmt.Printf("%s: %d \n ", unspentTx.TxID, unspentTx.VOut)

	}

	return tx, TxToHex(tx), nil
}


<|start_filename|>proxy/rpc/channel.go<|end_filename|>
package rpc

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/proxy/pb"
	"github.com/omnilaboratory/obd/service"
	"github.com/omnilaboratory/obd/tool"
	"log"
)

func (s *RpcServer) OpenChannel(ctx context.Context, in *pb.OpenChannelRequest) (*pb.OpenChannelResponse, error) {
	log.Println("OpenChannel")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}

	if tool.CheckIsString(&in.RecipientInfo.RecipientNodePeerId) == false {
		return nil, errors.New("wrong recipient_node_peer_id")
	}

	if tool.CheckIsString(&in.RecipientInfo.RecipientUserPeerId) == false {
		return nil, errors.New("wrong recipient_user_peer_id")
	}

	if tool.CheckIsString(&in.NodePubkeyString) == false {
		return nil, errors.New("wrong node_pubkey_string")
	}

	nodePubKeyIndex := -1
	for i := 0; i < obcClient.User.CurrAddrIndex; i++ {
		wallet, _ := service.HDWalletService.GetAddressByIndex(obcClient.User, uint32(i))
		if wallet.PubKey == in.NodePubkeyString {
			nodePubKeyIndex = i
			break
		}
	}
	if nodePubKeyIndex == -1 {
		return nil, errors.New("NodePubkeyString not found in current Mnemonic")
	}

	channelOpen := bean.SendChannelOpen{
		FundingPubKey:      in.NodePubkeyString,
		FunderAddressIndex: nodePubKeyIndex,
		IsPrivate:          in.Private,
	}

	infoBytes, _ := json.Marshal(channelOpen)
	requestMessage := bean.RequestMessage{
		Type:                enum.MsgType_SendChannelOpen_32,
		SenderNodePeerId:    obcClient.User.P2PLocalPeerId,
		SenderUserPeerId:    obcClient.User.PeerId,
		RecipientNodePeerId: in.RecipientInfo.RecipientNodePeerId,
		RecipientUserPeerId: in.RecipientInfo.RecipientUserPeerId,
		Data:                string(infoBytes)}

	err = checkTargetUserIsOnline(requestMessage)
	if err != nil {
		return nil, err
	}

	if obcClient.GrpcChan == nil {
		obcClient.GrpcChan = make(chan []byte)
	}

	obcClient.ChannelModule(requestMessage)

	message := <-obcClient.GrpcChan

	close(obcClient.GrpcChan)
	obcClient.GrpcChan = nil

	replyMessage := bean.ReplyMessage{}
	_ = json.Unmarshal(message, &replyMessage)
	if replyMessage.Status == false {
		return nil, errors.New(replyMessage.Result.(string))
	}

	dataResult := replyMessage.Result.(map[string]interface{})
	resp := &pb.OpenChannelResponse{}
	resp.TemplateChannelId = dataResult["temporary_channel_id"].(string)

	return resp, nil
}

func (s *RpcServer) CloseChannel(ctx context.Context, in *pb.CloseChannelRequest) (*pb.CloseChannelResponse, error) {
	log.Println("CloseChannel")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}
	if tool.CheckIsString(&in.ChannelId) == false {
		return nil, errors.New("wrong channel_id")
	}
	marshal, _ := json.Marshal(in)
	requestMessage := bean.RequestMessage{
		Type:             enum.MsgType_SendChannelOpen_32,
		SenderNodePeerId: obcClient.User.P2PLocalPeerId,
		SenderUserPeerId: obcClient.User.PeerId,
		Data:             string(marshal)}

	channel, err := service.ChannelService.ForceCloseChannel(requestMessage, obcClient.User)
	if err != nil {
		return nil, err
	}

	rsmcTxInfo, err := service.CommitmentTxService.GetLatestCommitmentTxByChannelId(string(marshal), obcClient.User)
	if err != nil {
		return nil, err
	}
	channelInfo := channel.(*dao.ChannelInfo)
	resp := &pb.CloseChannelResponse{
		ChannelId:     channelInfo.ChannelId,
		TotalAmount:   channelInfo.Amount,
		LocalBalance:  rsmcTxInfo.AmountToRSMC,
		RemoteBalance: rsmcTxInfo.AmountToCounterparty,
		PropertyId:    channelInfo.PropertyId,
	}
	return resp, nil
}

func (s *RpcServer) GetChanInfo(ctx context.Context, in *pb.ChanInfoRequest) (*pb.ChannelEdge, error) {
	log.Println("CloseChannel")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}
	if tool.CheckIsString(&in.ChannelId) == false {
		return nil, errors.New("wrong channel_id")
	}

	channelInfo, err := service.ChannelService.GetChannelInfoByChannelId(in.ChannelId, *obcClient.User)
	if err != nil {
		return nil, err
	}

	resp := &pb.ChannelEdge{
		ChannelId:      channelInfo.ChannelId,
		ChannelAddress: channelInfo.ChannelAddress,
		Node1Pub:       channelInfo.PubKeyA,
		Node2Pub:       channelInfo.PubKeyB,
		TotalAmount:    channelInfo.Amount,
		PropertyId:     channelInfo.PropertyId,
		CurrState:      int64(channelInfo.CurrState),
	}
	return resp, nil
}

func (s *RpcServer) FundChannel(ctx context.Context, in *pb.FundChannelRequest) (*pb.FundChannelResponse, error) {
	log.Println("FundChannel")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}
	if tool.CheckIsString(&in.RecipientInfo.RecipientNodePeerId) == false {
		return nil, errors.New("wrong recipient_node_peer_id")
	}

	if tool.CheckIsString(&in.RecipientInfo.RecipientUserPeerId) == false {
		return nil, errors.New("wrong recipient_user_peer_id")
	}
	if tool.CheckIsString(&in.TemplateChannelId) == false {
		return nil, errors.New("wrong template_channel_id")
	}
	if in.BtcAmount < 0 {
		return nil, errors.New("wrong btc_amount")
	}
	if in.PropertyId < 0 {
		return nil, errors.New("wrong property_id")
	}
	if in.AssetAmount < 0 {
		return nil, errors.New("wrong asset_amount")
	}

	requestFunding := bean.SendRequestFunding{
		TemporaryChannelId: in.TemplateChannelId,
		BtcAmount:          in.BtcAmount,
		PropertyId:         in.PropertyId,
		AssetAmount:        in.AssetAmount,
	}

	infoBytes, _ := json.Marshal(requestFunding)
	requestMessage := bean.RequestMessage{
		Type:                enum.MsgType_Funding_134,
		SenderNodePeerId:    obcClient.User.P2PLocalPeerId,
		SenderUserPeerId:    obcClient.User.PeerId,
		RecipientNodePeerId: in.RecipientInfo.RecipientNodePeerId,
		RecipientUserPeerId: in.RecipientInfo.RecipientUserPeerId,
		Data:                string(infoBytes)}

	err = checkTargetUserIsOnline(requestMessage)
	if err != nil {
		return nil, err
	}

	_, dataBytes, status := obcClient.FundingTransactionModule(requestMessage)

	data := string(dataBytes)
	if status == false {
		return nil, errors.New(data)
	}
	dataMap := make(map[string]interface{})
	_ = json.Unmarshal(dataBytes, &dataMap)

	resp := &pb.FundChannelResponse{}
	resp.ChannelId = dataMap["channel_id"].(string)
	return resp, nil
}


<|start_filename|>omnicore/DecodeRawTransaction_test.go<|end_filename|>
package omnicore

import (
	"fmt"
	"testing"

	"github.com/btcsuite/btcd/chaincfg"
)

func TestDecodeRawTransaction(t *testing.T) {
	tx_hex := "0100000002de95b97cf4c67ec01485fd698ec154a325ff69dd3e58435d7024bae7f69534c20000000000ffffffffb3b60aaa69b860c9bf31e742e3b37e75a2a553fd0bebf8aaf7da0e9bb07316ee0200000000ffffffff036a5a0d00000000001976a914c6734676a08e3c6438bd95fa62c57939c988a17b88ac0000000000000000166a146f6d6e690000000000000002000000000098968022020000000000001976a914ee692ea81da1b12d3dd8f53fd504865c9d843f5288ac00000000"
	fmt.Println(DecodeRawTransaction(tx_hex, &chaincfg.MainNetParams))
}

func TestVerfyOpreturnPayload(t *testing.T) {
	property_id_expected := "2"
	amount_expected := "0.1"
	devisible_expected := true

	// This testing hex equals to "OP_RETURN 6f6d6e6900000000000000020000000000989680",
	// which is encoded from payload of property id 2 and amount 0.1
	opreturn_hex := "6a146f6d6e6900000000000000020000000000989680"
	if VerfyOpreturnPayload(opreturn_hex, property_id_expected, amount_expected, devisible_expected) {
		fmt.Println("Match!")
	} else {
		fmt.Println("Please check opreturn string and expected data, and try again.")
	}

}


<|start_filename|>service/msg_service.go<|end_filename|>
package service

import (
	"encoding/json"
	"github.com/asdine/storm"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/tool"
	"time"
)

type Message struct {
	Id        int             `storm:"id,increment" json:"id" `
	HashValue string          `json:"hash_value"`
	Sender    string          `json:"sender"`
	Receiver  string          `json:"receiver"`
	Data      string          `json:"data"`
	CurrState dao.NormalState `json:"curr_state"`
	CreateAt  time.Time       `json:"create_at"`
	ReadAt    time.Time       `json:"read_at"`
}

type messageManage struct {
}

var messageService messageManage

func (this *messageManage) saveMsgUseTx(tx storm.Node, sender, receiver, data string) string {
	tool.CheckIsString(&data)
	msg := &Message{
		Sender:    sender,
		Receiver:  receiver,
		Data:      data,
		CreateAt:  time.Now(),
		CurrState: dao.NS_Create,
	}
	bytes, err := json.Marshal(msg)
	if err == nil {
		msg.HashValue = tool.SignMsgWithSha256(bytes)
		err = tx.Save(msg)
		if err == nil {
			return msg.HashValue
		}
	}
	return ""
}
func (this *messageManage) getMsgUseTx(tx storm.Node, hashValue string) (*Message, error) {
	msg := &Message{}
	err := tx.Select(q.Eq("HashValue", hashValue), q.Eq("CurrState", dao.NS_Create)).First(msg)
	if err == nil {
		msg.ReadAt = time.Now()
		_ = tx.Update(msg)
		return msg, nil
	}
	return nil, err
}
func (this *messageManage) updateMsgStateUseTx(tx storm.Node, msg *Message) error {
	msg.CurrState = dao.NS_Finish
	return tx.Update(msg)
}


<|start_filename|>omnicore/local_script_tx.go<|end_filename|>
package omnicore

import (
	"encoding/json"
	"errors"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/config"
	"github.com/omnilaboratory/obd/conn"
	"github.com/omnilaboratory/obd/tool"
	"github.com/shopspring/decimal"
	"github.com/tidwall/gjson"
	"strconv"
	"strings"
)

//创建btc的raw交易：输入为未广播的预交易,输出为交易hex，支持单签和多签，如果是单签，就需要后续步骤再签名
func BtcCreateRawTransactionForUnsendInputTx(fromBitCoinAddress string, inputItems []bean.TransactionInputItem, outputItems []bean.TransactionOutputItem, minerFee float64, sequence int, redeemScript *string) (retMap map[string]interface{}, err error) {
	if tool.CheckIsAddress(fromBitCoinAddress) == false {
		return nil, errors.New("fromBitCoinAddress is empty")
	}
	if len(outputItems) < 1 {
		return nil, errors.New("toBitCoinAddress is empty")
	}

	if minerFee <= tool.GetOmniDustBtc() {
		minerFee = GetMinerFee(10)
	}

	outAmount := decimal.NewFromFloat(0)
	for _, item := range outputItems {
		outAmount = outAmount.Add(decimal.NewFromFloat(item.Amount))
	}

	if outAmount.LessThan(decimal.NewFromFloat(tool.GetOmniDustBtc())) {
		return nil, errors.New("wrong outAmount")
	}

	if minerFee < tool.GetOmniDustBtc() {
		return nil, errors.New("minerFee too small")
	}

	var outTotalCount = 0
	for _, item := range outputItems {
		if item.Amount > 0 {
			outTotalCount++
		}
	}

	subMinerFee := 0.0
	if outTotalCount > 0 {
		count, _ := decimal.NewFromString(strconv.Itoa(outTotalCount))
		subMinerFee, _ = decimal.NewFromFloat(minerFee).DivRound(count, 8).Float64()
	}
	minerFee = 0
	for i := 0; i < outTotalCount; i++ {
		minerFee, _ = decimal.NewFromFloat(minerFee).Add(decimal.NewFromFloat(subMinerFee)).Round(8).Float64()
	}

	balance := 0.0
	var inputs []map[string]interface{}
	for _, item := range inputItems {
		node := make(map[string]interface{})
		node["txid"] = item.Txid
		node["vout"] = item.Vout
		node["amount"] = item.Amount
		if sequence > 0 {
			node["sequence"] = sequence
		}
		if tool.CheckIsString(redeemScript) {
			node["redeemScript"] = *redeemScript
		}
		node["scriptPubKey"] = item.ScriptPubKey
		balance, _ = decimal.NewFromFloat(balance).Add(decimal.NewFromFloat(item.Amount)).Round(8).Float64()
		inputs = append(inputs, node)
	}
	//not enough money
	if outAmount.GreaterThan(decimal.NewFromFloat(balance)) {
		return nil, errors.New("not enough balance")
	}

	//not enough money for minerFee
	if outAmount.Equal(decimal.NewFromFloat(balance)) {
		outAmount = outAmount.Sub(decimal.NewFromFloat(minerFee))
	}

	out, _ := decimal.NewFromFloat(minerFee).Add(outAmount).Round(8).Float64()

	if len(inputs) == 0 || balance < out {
		return nil, errors.New("not enough balance")
	}
	drawback, _ := decimal.NewFromFloat(balance).Sub(decimal.NewFromFloat(out)).Round(8).Float64()

	output := make(map[string]interface{})
	totalOutAmount := 0.0
	for _, item := range outputItems {
		if item.Amount > 0 {
			tempAmount, _ := decimal.NewFromFloat(item.Amount).Sub(decimal.NewFromFloat(subMinerFee)).Round(8).Float64()
			output[item.ToBitCoinAddress] = tempAmount
			totalOutAmount += tempAmount
		}
	}
	if drawback > 0 {
		output[fromBitCoinAddress] = drawback
	}

	dataToTracker := make(map[string]interface{})
	dataToTracker["inputs"] = inputs
	dataToTracker["outputs"] = output
	bytes, err := json.Marshal(dataToTracker)
	hex := conn2tracker.CreateRawTransaction(string(bytes))
	if hex == "" {
		return nil, errors.New("error createRawTransaction")
	}

	retMap = make(map[string]interface{})
	retMap["hex"] = hex
	retMap["inputs"] = inputs
	retMap["total_in_amount"] = balance
	retMap["total_out_amount"] = totalOutAmount
	return retMap, nil
}

// create a raw transaction and no sign , not send to the network,get the hash of signature
func BtcCreateRawTransaction(fromBitCoinAddress string, outputItems []bean.TransactionOutputItem, minerFee float64, sequence int, redeemScript *string) (retMap map[string]interface{}, err error) {
	if tool.CheckIsAddress(fromBitCoinAddress) == false {
		return nil, errors.New("fromBitCoinAddress is empty")
	}
	if len(outputItems) < 1 {
		return nil, errors.New("toBitCoinAddress is empty")
	}

	if minerFee <= 0 {
		minerFee = GetMinerFee(10)
	}

	outTotalAmount := decimal.NewFromFloat(0)
	for _, item := range outputItems {
		outTotalAmount = outTotalAmount.Add(decimal.NewFromFloat(item.Amount))
	}

	if outTotalAmount.LessThan(decimal.NewFromFloat(tool.GetOmniDustBtc())) {
		return nil, errors.New("wrong outTotalAmount")
	}

	if minerFee < tool.GetOmniDustBtc() {
		return nil, errors.New("minerFee too small")
	}

	result := conn2tracker.ListUnspent(fromBitCoinAddress)
	array := gjson.Parse(result).Array()
	if len(array) == 0 {
		return nil, errors.New("empty balance")
	}

	minerFeeAndOut, _ := decimal.NewFromFloat(minerFee).Add(outTotalAmount).Round(8).Float64()

	balance := 0.0
	inputs := make([]map[string]interface{}, 0)
	for _, item := range array {
		node := make(map[string]interface{})
		node["txid"] = item.Get("txid").String()
		node["vout"] = item.Get("vout").Int()
		node["amount"] = item.Get("amount").Float()
		if redeemScript != nil {
			node["redeemScript"] = *redeemScript
		} else {
			if item.Get("redeemScript").Exists() {
				node["redeemScript"] = item.Get("redeemScript")
			}
		}
		if sequence > 0 {
			node["sequence"] = sequence
		}
		node["scriptPubKey"] = item.Get("scriptPubKey").String()
		inputs = append(inputs, node)
		balance, _ = decimal.NewFromFloat(balance).Add(decimal.NewFromFloat(item.Get("amount").Float())).Round(8).Float64()
		if balance >= minerFeeAndOut {
			break
		}
	}

	if len(inputs) == 0 || balance < minerFeeAndOut {
		return nil, errors.New("not enough balance")
	}

	subMinerFee := 0.0
	if balance <= minerFeeAndOut {
		needLessFee, _ := decimal.NewFromFloat(minerFeeAndOut).Sub(decimal.NewFromFloat(balance)).Round(8).Float64()
		if needLessFee > 0 {
			var outTotalCount = 0
			for _, item := range outputItems {
				if item.Amount > 0 {
					outTotalCount++
				}
			}
			if outTotalCount > 0 {
				count, _ := decimal.NewFromString(strconv.Itoa(outTotalCount))
				subMinerFee, _ = decimal.NewFromFloat(minerFee).DivRound(count, 8).Float64()
			}
		}
	}

	drawback, _ := decimal.NewFromFloat(balance).Sub(decimal.NewFromFloat(minerFeeAndOut)).Round(8).Float64()
	output := make(map[string]interface{})
	for _, item := range outputItems {
		if item.Amount > 0 {
			output[item.ToBitCoinAddress], _ = decimal.NewFromFloat(item.Amount).Sub(decimal.NewFromFloat(subMinerFee)).Round(8).Float64()
		}
	}
	if drawback > 0 {
		output[fromBitCoinAddress] = drawback
	}

	dataToTracker := make(map[string]interface{})
	dataToTracker["inputs"] = inputs
	dataToTracker["outputs"] = output
	bytes, err := json.Marshal(dataToTracker)
	hex := conn2tracker.CreateRawTransaction(string(bytes))
	if hex == "" {
		return nil, errors.New("error createRawTransaction")
	}

	retMap = make(map[string]interface{})
	retMap["hex"] = hex
	retMap["inputs"] = inputs
	retMap["total_in_amount"] = balance
	return retMap, nil
}

// From channelAddress to temp multi address, to Create CommitmentTx
func OmniCreateRawTransactionUseSingleInput(resultListUnspent string, fromBitCoinAddress string, toBitCoinAddress string, propertyId int64, amount float64, minerFee float64, sequence int, redeemScript *string, usedTxid string) (retMap map[string]interface{}, currUseTxid string, err error) {
	if tool.CheckIsAddress(fromBitCoinAddress) == false {
		return nil, "", errors.New("fromBitCoinAddress is empty")
	}
	if tool.CheckIsAddress(toBitCoinAddress) == false {
		return nil, "", errors.New("toBitCoinAddress is empty")
	}
	if amount < tool.GetOmniDustBtc() {
		return nil, "", errors.New("wrong amount")
	}

	pMoney := tool.GetOmniDustBtc()

	arrayListUnspent := gjson.Parse(resultListUnspent).Array()

	balance := 0.0
	inputs := make([]map[string]interface{}, 0, 0)
	currUseTxid = ""
	for _, item := range arrayListUnspent {
		currUseTxid = item.Get("txid").String()
		if usedTxid != "" && strings.Contains(usedTxid, currUseTxid) {
			continue
		}
		inputAmount := item.Get("amount").Float()
		if inputAmount > pMoney {
			node := make(map[string]interface{})
			node["txid"] = item.Get("txid").String()
			node["vout"] = item.Get("vout").Int()
			node["amount"] = inputAmount
			node["scriptPubKey"] = item.Get("scriptPubKey").String()
			if redeemScript != nil {
				node["redeemScript"] = *redeemScript
			}
			balance, _ = decimal.NewFromFloat(balance).Add(decimal.NewFromFloat(node["amount"].(float64))).Round(8).Float64()
			minerFee = tool.GetBtcMinerAmount(balance)
			inputs = append(inputs, node)
			break
		}
	}

	if currUseTxid == "" {
		return nil, "", errors.New("not found the miner fee input")
	}

	minMinerFee := config.GetMinMinerFee(len(inputs))
	if minerFee < minMinerFee {
		minerFee = minMinerFee
	}

	out, _ := decimal.NewFromFloat(pMoney).
		Add(decimal.NewFromFloat(minerFee)).
		Round(8).
		Float64()

	retMap, err = createOmniRawTransaction(balance, out, amount, minerFee, propertyId, inputs, toBitCoinAddress, toBitCoinAddress, redeemScript)
	if err != nil {
		return nil, "", err
	}
	return retMap, currUseTxid, nil
}

// 通道地址的剩余input全部花掉
func OmniCreateRawTransactionUseRestInput(txType int, resultListUnspent string, fromBitCoinAddress string, usedTxid string, toBitCoinAddress, changeToAddress string, propertyId int64, amount float64, minerFee float64, redeemScript *string) (retMap map[string]interface{}, err error) {
	if tool.CheckIsAddress(fromBitCoinAddress) == false {
		return nil, errors.New("fromBitCoinAddress is empty")
	}
	if tool.CheckIsAddress(toBitCoinAddress) == false {
		return nil, errors.New("toBitCoinAddress is empty")
	}
	if amount < tool.GetOmniDustBtc() {
		return nil, errors.New("wrong amount")
	}

	pMoney := tool.GetOmniDustBtc()

	arrayListUnspent := gjson.Parse(resultListUnspent).Array()
	inputs := make([]map[string]interface{}, 0, 0)
	for _, item := range arrayListUnspent {
		txid := item.Get("txid").String()
		if (usedTxid != "" && strings.Contains(usedTxid, txid) == false) || len(usedTxid) == 0 {
			node := make(map[string]interface{})
			node["txid"] = txid
			node["vout"] = item.Get("vout").Int()
			node["amount"] = item.Get("amount").Float()
			node["scriptPubKey"] = item.Get("scriptPubKey").String()
			if redeemScript != nil {
				node["redeemScript"] = *redeemScript
			}
			inputs = append(inputs, node)
		}
	}

	minMinerFee := config.GetMinMinerFee(len(inputs))
	if minerFee < minMinerFee {
		minerFee = minMinerFee
	}
	out, _ := decimal.NewFromFloat(minerFee).
		Add(decimal.NewFromFloat(pMoney)).
		Round(8).
		Float64()

	balance := 0.0
	for _, item := range inputs {
		balance, _ = decimal.NewFromFloat(balance).Add(decimal.NewFromFloat(item["amount"].(float64))).Round(8).Float64()
		if balance >= out {
			break
		}
	}
	return createOmniRawTransaction(balance, out, amount, minerFee, propertyId, inputs, toBitCoinAddress, changeToAddress, redeemScript)
}

func OmniCreateRawTransactionUseUnsendInput(fromBitCoinAddress string, inputItems []bean.TransactionInputItem, toBitCoinAddress, changeToAddress string, propertyId int64, amount float64, minerFee float64, sequence int, redeemScript *string) (retMap map[string]interface{}, err error) {
	if tool.CheckIsAddress(fromBitCoinAddress) == false {
		return nil, errors.New("fromBitCoinAddress is empty")
	}
	if tool.CheckIsAddress(toBitCoinAddress) == false {
		return nil, errors.New("toBitCoinAddress is empty")
	}
	if tool.CheckIsAddress(changeToAddress) == false {
		return nil, errors.New("changeToAddress is empty")
	}

	if len(inputItems) == 0 {
		return nil, errors.New("inputItems is empty")
	}

	if amount < tool.GetOmniDustBtc() {
		return nil, errors.New("wrong amount")
	}
	pMoney := tool.GetOmniDustBtc()

	inputs := make([]map[string]interface{}, 0, 0)
	for _, item := range inputItems {
		node := make(map[string]interface{})
		node["txid"] = item.Txid
		node["vout"] = item.Vout
		node["amount"] = item.Amount
		node["scriptPubKey"] = item.ScriptPubKey
		if sequence > 0 {
			node["sequence"] = sequence
		}
		if redeemScript != nil {
			node["redeemScript"] = *redeemScript
		}

		inputs = append(inputs, node)
	}
	out, _ := decimal.NewFromFloat(minerFee).Add(decimal.NewFromFloat(pMoney)).Round(8).Float64()
	balance := 0.0
	for _, item := range inputs {
		balance, _ = decimal.NewFromFloat(balance).Add(decimal.NewFromFloat(item["amount"].(float64))).Round(8).Float64()
		if balance >= out {
			break
		}
	}

	return createOmniRawTransaction(balance, out, amount, minerFee, propertyId, inputs, toBitCoinAddress, changeToAddress, redeemScript)
}

// From channelAddress to temp multi address, to Create CommitmentTx
func GetInputInfo(fromBitCoinAddress string, txid, redeemScript string) (info map[string]interface{}, err error) {
	if tool.CheckIsAddress(fromBitCoinAddress) == false {
		return nil, errors.New("fromBitCoinAddress is empty")
	}

	resultListUnspent := conn2tracker.ListUnspent(fromBitCoinAddress)
	if resultListUnspent == "" {
		return nil, err
	}

	arrayListUnspent := gjson.Parse(resultListUnspent).Array()
	for _, item := range arrayListUnspent {
		currUseTxid := item.Get("txid").String()
		if currUseTxid == txid {
			node := make(map[string]interface{})
			node["txid"] = currUseTxid
			node["vout"] = item.Get("vout").Int()
			node["amount"] = item.Get("amount").Float()
			node["scriptPubKey"] = item.Get("scriptPubKey").String()
			if &redeemScript != nil {
				node["redeemScript"] = redeemScript
			}
			return node, nil
		}
	}

	return nil, errors.New("not found input info")
}

func OmniCreateRawTransaction(fromBitCoinAddress string, toBitCoinAddress string, propertyId int64, amount float64, minerFee float64) (retMap map[string]interface{}, err error) {
	if tool.CheckIsAddress(fromBitCoinAddress) == false {
		return nil, errors.New("fromBitCoinAddress is empty")
	}
	if tool.CheckIsAddress(toBitCoinAddress) == false {
		return nil, errors.New("toBitCoinAddress is empty")
	}
	if amount < tool.GetOmniDustBtc() {
		return nil, errors.New("wrong amount")
	}

	_, err = ParsePropertyId(strconv.Itoa(int(propertyId)))
	if err != nil {
		return nil, err
	}

	pMoney := tool.GetOmniDustBtc()
	if minerFee < tool.GetOmniDustBtc() {
		minerFee = 0.00003
	}

	balanceResult := conn2tracker.OmniGetBalancesForAddress(fromBitCoinAddress, int(propertyId))
	if balanceResult == "" {
		return nil, errors.New("empty omni balance")
	}

	omniBalance := gjson.Get(balanceResult, "balance").Float()
	if omniBalance < amount {
		return nil, errors.New("not enough omni balance")
	}

	resultListUnspent := conn2tracker.ListUnspent(fromBitCoinAddress)
	if resultListUnspent == "" {
		return nil, errors.New("enmpty ListUnspent")
	}

	arrayListUnspent := gjson.Parse(resultListUnspent).Array()
	if len(arrayListUnspent) == 0 {
		return nil, errors.New("empty balance")
	}

	out, _ := decimal.NewFromFloat(minerFee).Add(decimal.NewFromFloat(pMoney)).Round(8).Float64()

	balance := 0.0
	inputs := make([]map[string]interface{}, 0, len(arrayListUnspent))
	for _, item := range arrayListUnspent {
		node := make(map[string]interface{})
		node["txid"] = item.Get("txid").String()
		node["vout"] = item.Get("vout").Int()
		node["scriptPubKey"] = item.Get("scriptPubKey").String()
		node["amount"] = item.Get("amount").Float()
		inputs = append(inputs, node)
		balance, _ = decimal.NewFromFloat(balance).Add(decimal.NewFromFloat(item.Get("amount").Float())).Round(8).Float64()
		if balance >= out {
			break
		}
	}

	retMap, err = createOmniRawTransaction(balance, out, amount, minerFee, propertyId, inputs, toBitCoinAddress, fromBitCoinAddress, nil)
	if err != nil {
		return nil, err
	}
	return retMap, nil
}

func createOmniRawTransaction(balance, out, amount, minerFee float64, propertyId int64, inputs []map[string]interface{}, toBitCoinAddress, changeToAddress string, redeemScript *string) (retMap map[string]interface{}, err error) {
	if balance < out {
		return nil, errors.New("not enough balance")
	}

	payloadBytes, payloadHex := Omni_createpayload_simplesend(strconv.Itoa(int(propertyId)), tool.FloatToString(amount, 8), true)

	inputsBytes, _ := json.Marshal(inputs)
	inputsStr := string(inputsBytes)
	inputsStr = strings.TrimLeft(inputsStr, "[")
	inputsStr = strings.TrimRight(inputsStr, "]")
	inputsStr = strings.ReplaceAll(inputsStr, "},", "}")
	rawTx, _, _ := CreateRawTransaction(inputsStr, 2)

	opreturnTxMsg, err := Omni_createrawtx_opreturn(rawTx, payloadBytes, payloadHex)

	referenceTxMsg, err := Omni_createrawtx_reference(opreturnTxMsg, toBitCoinAddress, tool.GetCoreNet())

	//6.Omni_createrawtx_change
	prevtxs := make([]map[string]interface{}, 0, 0)
	for _, item := range inputs {
		node := make(map[string]interface{})
		node["txid"] = item["txid"]
		node["vout"] = item["vout"]
		node["scriptPubKey"] = item["scriptPubKey"]
		value := decimal.NewFromFloat(item["amount"].(float64))
		node["value"] = value.String()
		if redeemScript != nil {
			node["redeemScript"] = *redeemScript
		}
		prevtxs = append(prevtxs, node)
	}

	prevtxsBytes, _ := json.Marshal(prevtxs)
	prevtxsStr := string(prevtxsBytes)
	prevtxsStr = strings.TrimLeft(prevtxsStr, "[")
	prevtxsStr = strings.TrimRight(prevtxsStr, "]")
	prevtxsStr = strings.ReplaceAll(prevtxsStr, "},", "}")
	change, err := Omni_createrawtx_change(referenceTxMsg, prevtxsStr, changeToAddress, tool.FloatToString(minerFee, 8), tool.GetCoreNet())

	retMap = make(map[string]interface{})
	retMap["hex"] = TxToHex(change)
	retMap["inputs"] = inputs
	return retMap, nil
}

func OmniSignRawTransactionForUnsend(hex string, inputItems []bean.TransactionInputItem, privKey string) (string, string, error) {
	if len(hex) == 0 {
		return "", "", nil
	}
	var items []bean.RawTxInputItem
	for _, item := range inputItems {
		items = append(items, bean.RawTxInputItem{ScriptPubKey: item.ScriptPubKey, RedeemScript: item.RedeemScript})
	}

	hex, err := SignRawHex(items, hex, privKey, 2)
	if err != nil {
		return "", hex, err
	}
	//transaction, _ := DecodeBtcRawTransaction(hex)
	//log.Println(transaction)

	return GetTxId(hex), hex, nil
}


<|start_filename|>proxy/tests/rpcclient_rsmc_test.go<|end_filename|>
package main

import (
	"context"
	"encoding/json"
	proxy "github.com/omnilaboratory/obd/proxy/pb"
	"google.golang.org/grpc"
	"log"
	"testing"
)

func getRsmcClient() (proxy.RsmcClient, *grpc.ClientConn) {

	opts := grpc.WithInsecure()
	conn, err := grpc.Dial("localhost:50051", opts)
	if err != nil {
		log.Println(err)
		return nil, nil
	}
	return proxy.NewRsmcClient(conn), conn
}

func TestRsmcPayment(t *testing.T) {

	client, conn := getRsmcClient()
	defer conn.Close()

	payment, err := client.RsmcPayment(context.Background(), &proxy.RsmcPaymentRequest{
		RecipientInfo: &proxy.RecipientNodeInfo{
			RecipientNodePeerId: "<KEY>",
			RecipientUserPeerId: "<KEY>"},
		ChannelId: "04281cba5a1179cf47501ae3cc687bd58aeeae848fc4daa3690351292ad2eb7a",
		Amount:    0.01,
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(payment)
	log.Println(string(marshal))
}


<|start_filename|>dao/pojo.go<|end_filename|>
package dao

import (
	"github.com/omnilaboratory/obd/bean"
	"time"
)

type User struct {
	Id              int            `storm:"id,increment" json:"id" `
	PeerId          string         `json:"peer_id"`
	P2PLocalAddress string         `json:"p2p_local_address"`
	P2PLocalPeerId  string         `json:"p2p_local_peer_id"`
	CurrAddrIndex   int            `json:"curr_addr_index"`
	CurrState       bean.UserState `json:"curr_state"`
	CreateAt        time.Time      `json:"create_at"`
	LatestLoginTime time.Time      `json:"latest_login_time"`
}
type UserLoginLog struct {
	Id       int       `storm:"id,increment" json:"id" `
	PeerId   string    `json:"peer_id"`
	LoginAt  time.Time `json:"login_at"`
	LogoutAt time.Time `json:"logout_at"`
}

type ChannelInfo struct {
	bean.RequestOpenChannel
	Id                         int               `storm:"id,increment" json:"id"`
	ChannelId                  string            `json:"channel_id"`
	PeerIdA                    string            `storm:"index" json:"peer_id_a"`
	PubKeyA                    string            `json:"pub_key_a"`
	AddressA                   string            `json:"address_a"`
	PeerIdB                    string            `storm:"index" json:"peer_id_b"`
	PubKeyB                    string            `json:"pub_key_b"`
	FundeeAddressIndex         int               `json:"fundee_address_index"`
	AddressB                   string            `json:"address_b"`
	ChannelAddress             string            `json:"channel_address"`
	ChannelAddressRedeemScript string            `json:"channel_address_redeem_script"`
	ChannelAddressScriptPubKey string            `json:"channel_address_script_pub_key"`
	PropertyId                 int64             `json:"property_id"`
	Amount                     float64           `json:"amount"`
	BtcAmount                  float64           `json:"btc_amount"`
	CurrState                  bean.ChannelState `json:"curr_state"`
	RefuseReason               string            `json:"refuse_reason"`
	CreateBy                   string            `json:"create_by"`
	CreateAt                   time.Time         `json:"create_at"`
	AcceptAt                   time.Time         `json:"accept_at"`
	CloseAt                    time.Time         `json:"close_at"`
}

type ChannelBtcListUnspent struct {
	Id          int    `storm:"id,increment" json:"id"`
	ChannelId   string `json:"channel_id"`
	ListUnspent string `json:"list_unspent"`
}

type ChannelAddressListUnspent struct {
	Id           int     `storm:"id,increment" json:"id"`
	ChannelId    string  `json:"channel_id"`
	Txid         string  `json:"txid"`
	Vout         uint32  `json:"vout"`
	ScriptPubKey string  `json:"scriptPubKey"`
	Amount       float64 `json:"amount"`
}

type CloseChannel struct {
	bean.CloseChannel
	Id             int       `storm:"id,increment" json:"id"`
	CommitmentTxId int       `json:"commitment_tx_id"`
	RequestHex     string    `json:"request_hex"`
	Owner          string    `json:"owner"`
	Approval       bool      `json:"approval"`
	CurrState      int       `json:"curr_state"` // 0: create 1 finish
	CreateAt       time.Time `json:"create_at"`
}

type FundingTransactionState int

const (
	FundingTransactionState_Create FundingTransactionState = 10
	FundingTransactionState_Accept FundingTransactionState = 20
)

type FundingTransaction struct {
	Id                         int                     `storm:"id,increment" json:"id"`
	TemporaryChannelId         string                  `json:"temporary_channel_id"`
	ChannelInfoId              int                     `json:"channel_info_id"`
	CurrState                  FundingTransactionState `json:"curr_state"`
	PeerIdA                    string                  `json:"peer_id_a"`
	PeerIdB                    string                  `json:"peer_id_b"`
	ChannelId                  string                  `json:"channel_id"`
	PropertyId                 int64                   `json:"property_id"`
	AmountA                    float64                 `json:"amount_a"`
	FunderPubKey2ForCommitment string                  `json:"funder_pub_key_2_for_commitment"`
	FundingTxHex               string                  `json:"funding_tx_hex"`
	FundingTxid                string                  `json:"funding_txid"`
	FundingOutputIndex         uint32                  `json:"funding_output_index"`
	AmountB                    float64                 `json:"amount_b"`
	RsmcTempAddressPubKey      string                  `json:"rsmc_temp_address_pub_key"` //为bob准备的
	FunderRsmcHex              string                  `json:"funder_rsmc_hex"`
	CreateBy                   string                  `json:"create_by"`
	Owner                      string                  `json:"owner"`
	FunderAddress              string                  `json:"funder_address"`
	CreateAt                   time.Time               `json:"create_at"`
	FundeeSignAt               time.Time               `json:"fundee_sign_at"`
}

type TxInfoState int

const (
	TxInfoState_Init                TxInfoState = 1
	TxInfoState_Create              TxInfoState = 5
	TxInfoState_Htlc_WaitHTRD1aSign TxInfoState = 6 //等待bob创建htrd1a
	TxInfoState_CreateAndSign       TxInfoState = 10
	TxInfoState_Htlc_GetH           TxInfoState = 11 // 创建Htlc交易的时候的状态
	TxInfoState_Htlc_GetR           TxInfoState = 12 // 获取到R后的状态
	TxInfoState_SendHex             TxInfoState = 20
	TxInfoState_Abord               TxInfoState = 30
)

type FundingBtcRequest struct {
	Id                 int       `storm:"id,increment" json:"id" `
	Owner              string    `json:"owner"`
	TemporaryChannelId string    `json:"temporary_channel_id"`
	TxHash             string    `json:"tx_hash"`
	RedeemHex          string    `json:"redeem_hex"`
	TxId               string    `json:"tx_id"`
	Amount             float64   `json:"amount"`
	CreateAt           time.Time `json:"create_at"`
	SignAt             time.Time `json:"sign_at"`
	SignApproval       bool      `json:"sign_approval"`
	FinishAt           time.Time `json:"finish_at"`
	IsFinish           bool      `json:"is_finish"`
}

//redeem the btc fee
type MinerFeeRedeemTransaction struct {
	Id                 int       `storm:"id,increment" json:"id" `
	Owner              string    `json:"owner"`
	TemporaryChannelId string    `json:"temporary_channel_id"`
	FundingTxId        string    `json:"funding_tx_id"`
	Amount             float64   `json:"amount"`
	Hex                string    `json:"hex"`
	Txid               string    `json:"txid"`
	IsFinish           bool      `json:"is_finish"`
	CreateAt           time.Time `json:"create_at"`
}

type CommitmentTransactionType int

const (
	CommitmentTransactionType_Rsmc = 0
	CommitmentTransactionType_Htlc = 1
)

//CommitmentTransaction
type CommitmentTransaction struct {
	Id                 int     `storm:"id,increment" json:"id" `
	LastCommitmentTxId int     `json:"last_commitment_tx_id"`
	LastHash           string  `json:"last_hash"`
	CurrHash           string  `json:"curr_hash"`
	PeerIdA            string  `json:"peer_id_a"`
	PeerIdB            string  `json:"peer_id_b"`
	ChannelId          string  `json:"channel_id"`
	PropertyId         int64   `json:"property_id"`
	InputTxid          string  `json:"input_txid"`   //input txid  from channelAddr: alice&bob multiAddr, so need  sign of alice and bob
	InputVout          uint32  `json:"input_vout"`   // input vout
	InputAmount        float64 `json:"input_amount"` //input amount

	TxType CommitmentTransactionType `json:"tx_type"` // 0 rsmc 1 htlc

	//RSMC
	// 用于记录助记词导出地址的index
	RSMCTempAddressIndex         int     `json:"rsmc_temp_address_index"`   //aliceTempRemc or bobTempRsmc
	RSMCTempAddressPubKey        string  `json:"rsmc_temp_address_pub_key"` //aliceTempRemc or bobTempRsmc
	RSMCMultiAddress             string  `json:"rsmc_multi_address"`        //output aliceTempRsmc&bob  or alice&bobTempRsmc  multiAddr
	RSMCRedeemScript             string  `json:"rsmc_redeem_script"`
	RSMCMultiAddressScriptPubKey string  `json:"rsmc_multi_address_script_pub_key"`
	AmountToRSMC                 float64 `json:"amount_to_rsmc"` // amount to multiAddr
	RsmcInputTxid                string  `json:"rsmc_input_txid"`
	RSMCTxHex                    string  `json:"rsmc_tx_hex"`
	RSMCTxid                     string  `json:"rsmc_txid"`
	//To CounterParty
	ToCounterpartyTxHex            string  `json:"to_counterparty_tx_hex,omitempty"`
	ToCounterpartyTxid             string  `json:"to_counterparty_txid,omitempty"`
	AmountToCounterparty           float64 `json:"amount_to_counterparty,omitempty"`               //amount to bob(if Cna) or alice(if Cnb)
	FromCounterpartySideForMeTxHex string  `json:"from_counterparty_side_for_me_tx_hex,omitempty"` //对方给自己的转账部分，防止对方不广播此交易
	//htlc
	HtlcRoutingPacket            string  `json:"htlc_routing_packet,omitempty"`        //借道Path
	HtlcCltvExpiry               int     `json:"htlc_cltv_expiry,omitempty,omitempty"` //借道的最大超时 分钟为单位
	BeginBlockHeight             int     `json:"begin_block_height,omitempty"`         //借道时的区块高度
	HTLCTempAddressIndex         int     `json:"htlc_temp_address_index,omitempty"`
	HTLCTempAddressPubKey        string  `json:"htlc_temp_address_pub_key,omitempty"` //alice for htlc or bob for htlc
	HTLCMultiAddress             string  `json:"htlc_multi_address,omitempty"`        //output aliceTempHtlc&bob  or alice&bobTempHtlc  multiAddr
	HTLCRedeemScript             string  `json:"htlc_redeem_script,omitempty"`
	HTLCMultiAddressScriptPubKey string  `json:"htlc_multi_address_script_pub_key,omitempty"`
	AmountToHtlc                 float64 `json:"amount_to_htlc,omitempty"`
	HtlcAmountToPayee            float64 `json:"htlc_amount_to_payee"`
	HtlcTxHex                    string  `json:"htlc_tx_hex,omitempty"`
	HTLCTxid                     string  `json:"htlc_txid,omitempty"`
	HtlcMemo                     string  `json:"htlc_memo,omitempty"`
	HtlcH                        string  `json:"htlc_h,omitempty"`
	HtlcR                        string  `json:"htlc_r,omitempty"`
	HtlcSender                   string  `json:"htlc_sender,omitempty"`

	CurrState    TxInfoState `json:"curr_state"`
	CreateBy     string      `json:"create_by"`
	CreateAt     time.Time   `json:"create_at"`
	SignAt       time.Time   `json:"sign_at"`
	SendAt       time.Time   `json:"send_at"`
	LastEditTime time.Time   `json:"last_edit_time"`
	Owner        string      `json:"owner"`
}

type CommitmentTxRawTx struct {
	Id                      int                       `storm:"id,increment" json:"id" `
	CommitmentTxId          int                       `json:"commitment_tx_id"`
	ToCounterpartyRawTxData bean.NeedClientSignTxData `json:"to_counterparty_raw_tx_data"`
	RsmcRawTxData           bean.NeedClientSignTxData `json:"rsmc_raw_tx_data"`
	HtlcRawTxData           bean.NeedClientSignTxData `json:"htlc_raw_tx_data"`
}

type PayeeRevokeAndAcknowledgeCommitment struct {
	Id               int    `storm:"id,increment" json:"id" `
	ChannelId        string `json:"channel_id"`
	CommitmentTxHash string `json:"commitment_tx_hash"`
	Approval         bool   `json:"approval"`
}

// close channel , alice or bob wait 1000 sequence to drawback the balance
type RevocableDeliveryTransaction struct {
	Id             int         `storm:"id,increment" json:"id" `
	CommitmentTxId int         `json:"commitment_tx_id"`
	PeerIdA        string      `json:"peer_id_a"`
	PeerIdB        string      `json:"peer_id_b"`
	ChannelId      string      `json:"channel_id"`
	PropertyId     int64       `json:"property_id"`
	InputTxHex     string      `json:"input_tx_hex"`
	InputTxid      string      `json:"input_txid"`     //input txid  from commitTx alice2&bob multtaddr, so need  sign of alice2 and bob
	InputVout      uint32      `json:"input_vout"`     // input vout
	InputAmount    float64     `json:"input_amount"`   //input amount
	OutputAddress  string      `json:"output_address"` //output alice
	Sequence       int         `json:"sequence"`
	RDType         int         `json:"rd_type"` // default 0 for rsmc Rd,1 for htrd
	Amount         float64     `json:"amount"`  // output alice amount
	TxHex          string      `json:"tx_hex"`
	Txid           string      `json:"txid"`
	CurrState      TxInfoState `json:"curr_state"`
	CreateBy       string      `json:"create_by"`
	CreateAt       time.Time   `json:"create_at"`
	SignAt         time.Time   `json:"sign_at"`
	SendAt         time.Time   `json:"send_at"`
	LastEditTime   time.Time   `json:"last_edit_time"`
	Owner          string      `json:"owner"`
}

// rd tx of waiting 1000 sequence
type BRType int

const (
	BRType_Rmsc BRType = 0 //来源RSMC
	BRType_Htlc BRType = 1 //来源Htlc
	BRType_Ht1a BRType = 2 //来源Ht1a
	BRType_HE1b BRType = 3 //来源HE1b
)

// to punish alice do not admit the latest commitment tx
type BreachRemedyTransaction struct {
	Id                       int         `storm:"id,increment" json:"id" `
	CommitmentTxId           int         `json:"commitment_tx_id"` // parent commitmentTx id
	PeerIdA                  string      `json:"peer_id_a"`
	PeerIdB                  string      `json:"peer_id_b"`
	ChannelId                string      `json:"channel_id"`
	PropertyId               int64       `json:"property_id"`
	TempPubKey               string      `json:"temp_pub_key"`
	InputAddress             string      `json:"input_address"`
	InputAddressScriptPubKey string      `json:"input_address_script_pub_key"`
	InputRedeemScript        string      `json:"input_redeem_script"`
	InputTxHex               string      `json:"input_tx_hex"`
	InputTxid                string      `json:"input_txid"`   //input txid  from commitTx alice2&bob multtAddr, so need  sign of alice2 and bob
	InputVout                uint32      `json:"input_vout"`   // input vout
	InputAmount              float64     `json:"input_amount"` //input amount
	OutAddress               string      `json:"out_address"`
	Amount                   float64     `json:"amount"`    // output bob amount
	BrTxHex                  string      `json:"br_tx_hex"` // first alice2 sign
	Txid                     string      `json:"txid"`
	Type                     BRType      `json:"type"` //:0:rmsc ,1:htlc,2:ht1a 3:hebr1b
	CurrState                TxInfoState `json:"curr_state"`
	CreateBy                 string      `json:"create_by"`
	CreateAt                 time.Time   `json:"create_at"`
	SignAt                   time.Time   `json:"sign_at"`
	SendAt                   time.Time   `json:"send_at"`
	LastEditTime             time.Time   `json:"last_edit_time"`
	Owner                    string      `json:"owner"`
}

type AtomicSwapInfo struct {
	bean.AtomicSwapRequest
	Id           int       `storm:"id,increment" json:"id" `
	CreateBy     string    `json:"create_by"`
	CreateAt     time.Time `json:"create_at"`
	LatestEditAt time.Time `json:"latest_edit_at"`
}
type AtomicSwapAcceptedInfo struct {
	bean.AtomicSwapAccepted
	Id           int       `storm:"id,increment" json:"id" `
	CreateBy     string    `json:"create_by"`
	CreateAt     time.Time `json:"create_at"`
	LatestEditAt time.Time `json:"latest_edit_at"`
}

type CacheDataForTx struct {
	Id       int       `storm:"id,increment" json:"id" `
	KeyName  string    `json:"key_name"`
	Data     []byte    `json:"data"`
	IsFinish bool      `json:"is_finish"`
	CreateAt time.Time `json:"create_at"`
}


<|start_filename|>service/communicate_with_tracker.go<|end_filename|>
package service

import (
	"encoding/json"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/dao"
	trackerBean "github.com/omnilaboratory/obd/tracker/bean"
	"github.com/tidwall/gjson"
	"strings"
)

var TrackerChan chan []byte

// sendChannelStateToTracker
func sendChannelStateToTracker(channelInfo dao.ChannelInfo, commitmentTx dao.CommitmentTransaction) {
	if channelInfo.IsPrivate {
		return
	}
	infoRequest := bean.ChannelInfoRequest{}
	infoRequest.ChannelId = channelInfo.ChannelId
	infoRequest.PropertyId = channelInfo.PropertyId
	infoRequest.CurrState = channelInfo.CurrState
	infoRequest.PeerIdA = channelInfo.PeerIdA
	infoRequest.PeerIdB = channelInfo.PeerIdB

	infoRequest.IsAlice = false
	if commitmentTx.Id > 0 {
		if commitmentTx.Owner == channelInfo.PeerIdA {
			infoRequest.IsAlice = true
			infoRequest.AmountA = commitmentTx.AmountToRSMC
			infoRequest.AmountB = commitmentTx.AmountToCounterparty
		} else {
			infoRequest.AmountB = commitmentTx.AmountToRSMC
			infoRequest.AmountA = commitmentTx.AmountToCounterparty
		}
	}
	nodes := make([]bean.ChannelInfoRequest, 0)
	nodes = append(nodes, infoRequest)
	go sendMsgToTracker(enum.MsgType_Tracker_UpdateChannelInfo_350, nodes)
}

func noticeTrackerUserLogin(user dao.User) {
	loginRequest := bean.ObdNodeUserLoginRequest{UserId: user.PeerId}
	sendMsgToTracker(enum.MsgType_Tracker_UserLogin_304, loginRequest)
}

func noticeTrackerUserLogout(user dao.User) {
	loginRequest := bean.ObdNodeUserLoginRequest{UserId: user.PeerId}
	sendMsgToTracker(enum.MsgType_Tracker_UserLogout_305, loginRequest)
}

func sendMsgToTracker(msgType enum.MsgType, data interface{}) {

	message := trackerBean.RequestMessage{Type: msgType}

	dataBytes, _ := json.Marshal(data)
	dataStr := string(dataBytes)

	parse := gjson.Parse(dataStr)
	result := parse.Value()
	if strings.HasPrefix(dataStr, "{") == false && strings.HasPrefix(dataStr, "[") == false {
		result = dataStr
	}

	message.Data = result
	//log.Println(message.Data)
	bytes, _ := json.Marshal(message)
	if TrackerChan != nil {
		TrackerChan <- bytes
	}
}


<|start_filename|>tracker/rpc/rpcclient.go<|end_filename|>
package rpc

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/omnilaboratory/obd/tracker/config"
	"github.com/tidwall/gjson"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
	"sync/atomic"
)

var connConfig *ConnConfig

func init() {
	connConfig = &ConnConfig{
		Host: cfg.ChainNode_Host,
		User: cfg.ChainNode_User,
		Pass: cfg.ChainNode_Pass,
	}
}

type ConnConfig struct {
	// Host is the IP address and port of the remote omnicore server you want to connect to.
	Host string
	// User is the username used in authentification by the remote RPC server.
	User string
	// Pass is the passphrase used in authentification.
	Pass string
}

type Client struct {
	id uint64 // atomic, so must stay 64-bit aligned
	// config holds the connection configuration assoiated with this client.
	config *ConnConfig
	// httpClient is the underlying HTTP client to use when running in HTTP POST mode.
	httpClient http.Client
}

type Request struct {
	Jsonrpc string            `json:"jsonrpc"`
	ID      interface{}       `json:"id"`
	Method  string            `json:"method"`
	Params  []json.RawMessage `json:"params"`
}

type rawResponse struct {
	Result json.RawMessage `json:"result"`
	Error  *RPCError       `json:"error"`
}

func (r rawResponse) result() (result []byte, err error) {
	if r.Error != nil {
		return nil, r.Error
	}
	return r.Result, nil
}

func (r *RPCError) Error() string {
	return fmt.Sprintf("Code: %d,Msg: %s", r.Code, r.Message)
}

type RPCError struct {
	Code    int    `json:"code,omitempty"`
	Message string `json:"message,omitempty"`
}

var client *Client

func NewClient() *Client {
	if client == nil {
		httpClient := http.Client{
			Transport: &http.Transport{
				Proxy:           nil,
				TLSClientConfig: nil,
			},
		}
		connConfig.Host = "http://" + connConfig.Host
		client = &Client{
			config:     connConfig,
			httpClient: httpClient,
		}
	}
	return client
}

func (client *Client) NextID() uint64 {
	return atomic.AddUint64(&client.id, 1)
}

func (client *Client) CheckVersion() error {

	result, err := client.GetBlockChainInfo()
	if err != nil {
		return err
	}
	cfg.ChainNode_Type = gjson.Get(result, "chain").Str

	result, err = client.OmniGetInfo()
	if err != nil {
		return err
	}

	omniCoreVersion := gjson.Get(result, "omnicoreversion").String()
	btcCoreVersion := gjson.Get(result, "bitcoincoreversion").String()
	log.Println("omniCoreVersion: "+omniCoreVersion+",", "bitcoinCoreVersion: "+btcCoreVersion)

	infoes := strings.Split(btcCoreVersion, ".")
	tempInt, _ := strconv.Atoi(infoes[0])
	if tempInt >= 0 {
		return nil
	}
	tempInt, _ = strconv.Atoi(infoes[1])
	if tempInt >= 18 {
		return nil
	}

	return errors.New("error bitcoinCore version " + btcCoreVersion)
}

func (client *Client) send(method string, params []interface{}) (result string, err error) {
	rawParams := make([]json.RawMessage, 0, len(params))
	for _, item := range params {
		marshaledParam, err := json.Marshal(item)
		if err == nil {
			rawParams = append(rawParams, marshaledParam)
		}
	}
	//method = "./omnicore-cli -conf=/root/.bitcoin/omnicore18data/bitcoin.conf "+method
	//log.Println("request to Rpc server:", method, params)
	req := &Request{
		Jsonrpc: "2.0",
		ID:      client.NextID(),
		Method:  strings.Trim(method, " "),
		Params:  rawParams,
	}

	marshaledJSON, e := json.Marshal(req)
	if e != nil {
		return "", e
	}

	bodyReader := bytes.NewReader(marshaledJSON)

	httpReq, err := http.NewRequest("POST", client.config.Host, bodyReader)
	httpReq.Header.Set("Content-Type", "application/json")
	httpReq.SetBasicAuth(client.config.User, client.config.Pass)
	httpResponse, err := client.httpClient.Do(httpReq)
	if err != nil {
		return "", err
	}
	defer httpResponse.Body.Close()

	if httpResponse.StatusCode == 403 {
		err = fmt.Errorf("status code: %d, response: %q , your ip is not allowed", httpResponse.StatusCode, httpResponse.Status)
		return "", err
	}

	// Read the raw bytes and close the response.
	respBytes, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		return "", err
	}

	var resp rawResponse
	err = json.Unmarshal(respBytes, &resp)

	if err != nil {
		err = fmt.Errorf("error reading json reply: %v", err)
		return "", err
	}

	if err != nil {
		err = fmt.Errorf("status code: %d, response: %q", httpResponse.StatusCode, err.Error())
		return "", err
	}

	res, err := resp.result()
	if httpResponse.StatusCode != 200 || err != nil {
		if err == nil {
			err = fmt.Errorf("status code: %d, response: %q", httpResponse.StatusCode, httpResponse.Status)
		}
		return "", err
	}
	return gjson.Parse(string(res)).String(), nil
}


<|start_filename|>proxy/tests/rpcclient_channel_test.go<|end_filename|>
package main

import (
	"context"
	"encoding/json"
	proxy "github.com/omnilaboratory/obd/proxy/pb"
	"log"
	"testing"
)

func TestOpenChannel(t *testing.T) {

	client, conn := getClient()
	defer conn.Close()

	channelResponse, err := client.OpenChannel(context.Background(), &proxy.OpenChannelRequest{
		RecipientInfo: &proxy.RecipientNodeInfo{
			RecipientNodePeerId: "<KEY>",
			RecipientUserPeerId: "<KEY>"},
		NodePubkeyString: "<KEY>",
		Private:          false,
	})
	if err != nil {
		log.Println(err)
		return
	}
	log.Println(channelResponse.TemplateChannelId)
}

func TestCloseChannel(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	resp, err := client.CloseChannel(context.Background(), &proxy.CloseChannelRequest{
		ChannelId: "e936e067a885ebf6fe94b4c75f7356aacb438ecdbc182172f55febe7d1e860fa",
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestGetChanInfo(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	resp, err := client.GetChanInfo(context.Background(), &proxy.ChanInfoRequest{
		ChannelId: "e936e067a885ebf6fe94b4c75f7356aacb438ecdbc182172f55febe7d1e860fa",
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestListChannels(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	resp, err := client.ListChannels(context.Background(), &proxy.ListChannelsRequest{
		ActiveOnly: true,
		PageIndex:  1,
		PageSize:   10,
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestPendingChannels(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	resp, err := client.PendingChannels(context.Background(), &proxy.PendingChannelsRequest{
		PageIndex: 1,
		PageSize:  10,
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestClosedChannels(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	resp, err := client.ClosedChannels(context.Background(), &proxy.ClosedChannelsRequest{
		PageIndex: 1,
		PageSize:  10,
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestLatestTransaction(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	resp, err := client.LatestTransaction(context.Background(), &proxy.LatestTransactionRequest{
		ChannelId: "<KEY>",
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestGetTransactionsByChannelId(t *testing.T) {

	client, conn := getClient()
	defer conn.Close()

	resp, err := client.GetTransactions(context.Background(), &proxy.GetTransactionsRequest{
		ChannelId: "343a94dd76703596b6b001a7751abfaa6afe27af196259b5e419ae17928aefdb",
		PageSize:  20,
		PageIndex: 1,
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestChannelBalance(t *testing.T) {

	client, conn := getClient()
	defer conn.Close()

	resp, err := client.ChannelBalance(context.Background(), &proxy.ChannelBalanceRequest{})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}


<|start_filename|>proxy/pb/rpc.pb.go<|end_filename|>
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: rpc.proto

package pb

import (
	context "context"
	fmt "fmt"
	proto "github.com/golang/protobuf/proto"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
	math "math"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

type RecipientNodeInfo struct {
	RecipientNodePeerId  string   `protobuf:"bytes,1,opt,name=recipient_node_peer_id,json=recipientNodePeerId,proto3" json:"recipient_node_peer_id,omitempty"`
	RecipientUserPeerId  string   `protobuf:"bytes,2,opt,name=recipient_user_peer_id,json=recipientUserPeerId,proto3" json:"recipient_user_peer_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *RecipientNodeInfo) Reset()         { *m = RecipientNodeInfo{} }
func (m *RecipientNodeInfo) String() string { return proto.CompactTextString(m) }
func (*RecipientNodeInfo) ProtoMessage()    {}
func (*RecipientNodeInfo) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{0}
}

func (m *RecipientNodeInfo) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_RecipientNodeInfo.Unmarshal(m, b)
}
func (m *RecipientNodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_RecipientNodeInfo.Marshal(b, m, deterministic)
}
func (m *RecipientNodeInfo) XXX_Merge(src proto.Message) {
	xxx_messageInfo_RecipientNodeInfo.Merge(m, src)
}
func (m *RecipientNodeInfo) XXX_Size() int {
	return xxx_messageInfo_RecipientNodeInfo.Size(m)
}
func (m *RecipientNodeInfo) XXX_DiscardUnknown() {
	xxx_messageInfo_RecipientNodeInfo.DiscardUnknown(m)
}

var xxx_messageInfo_RecipientNodeInfo proto.InternalMessageInfo

func (m *RecipientNodeInfo) GetRecipientNodePeerId() string {
	if m != nil {
		return m.RecipientNodePeerId
	}
	return ""
}

func (m *RecipientNodeInfo) GetRecipientUserPeerId() string {
	if m != nil {
		return m.RecipientUserPeerId
	}
	return ""
}

type ConnectPeerRequest struct {
	Addr                 string   `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ConnectPeerRequest) Reset()         { *m = ConnectPeerRequest{} }
func (m *ConnectPeerRequest) String() string { return proto.CompactTextString(m) }
func (*ConnectPeerRequest) ProtoMessage()    {}
func (*ConnectPeerRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{1}
}

func (m *ConnectPeerRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ConnectPeerRequest.Unmarshal(m, b)
}
func (m *ConnectPeerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ConnectPeerRequest.Marshal(b, m, deterministic)
}
func (m *ConnectPeerRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ConnectPeerRequest.Merge(m, src)
}
func (m *ConnectPeerRequest) XXX_Size() int {
	return xxx_messageInfo_ConnectPeerRequest.Size(m)
}
func (m *ConnectPeerRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ConnectPeerRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ConnectPeerRequest proto.InternalMessageInfo

func (m *ConnectPeerRequest) GetAddr() string {
	if m != nil {
		return m.Addr
	}
	return ""
}

type ConnectPeerResponse struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ConnectPeerResponse) Reset()         { *m = ConnectPeerResponse{} }
func (m *ConnectPeerResponse) String() string { return proto.CompactTextString(m) }
func (*ConnectPeerResponse) ProtoMessage()    {}
func (*ConnectPeerResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{2}
}

func (m *ConnectPeerResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ConnectPeerResponse.Unmarshal(m, b)
}
func (m *ConnectPeerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ConnectPeerResponse.Marshal(b, m, deterministic)
}
func (m *ConnectPeerResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ConnectPeerResponse.Merge(m, src)
}
func (m *ConnectPeerResponse) XXX_Size() int {
	return xxx_messageInfo_ConnectPeerResponse.Size(m)
}
func (m *ConnectPeerResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_ConnectPeerResponse.DiscardUnknown(m)
}

var xxx_messageInfo_ConnectPeerResponse proto.InternalMessageInfo

type DisconnectPeerRequest struct {
	Addr                 string   `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *DisconnectPeerRequest) Reset()         { *m = DisconnectPeerRequest{} }
func (m *DisconnectPeerRequest) String() string { return proto.CompactTextString(m) }
func (*DisconnectPeerRequest) ProtoMessage()    {}
func (*DisconnectPeerRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{3}
}

func (m *DisconnectPeerRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_DisconnectPeerRequest.Unmarshal(m, b)
}
func (m *DisconnectPeerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_DisconnectPeerRequest.Marshal(b, m, deterministic)
}
func (m *DisconnectPeerRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_DisconnectPeerRequest.Merge(m, src)
}
func (m *DisconnectPeerRequest) XXX_Size() int {
	return xxx_messageInfo_DisconnectPeerRequest.Size(m)
}
func (m *DisconnectPeerRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_DisconnectPeerRequest.DiscardUnknown(m)
}

var xxx_messageInfo_DisconnectPeerRequest proto.InternalMessageInfo

func (m *DisconnectPeerRequest) GetAddr() string {
	if m != nil {
		return m.Addr
	}
	return ""
}

type DisconnectPeerResponse struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *DisconnectPeerResponse) Reset()         { *m = DisconnectPeerResponse{} }
func (m *DisconnectPeerResponse) String() string { return proto.CompactTextString(m) }
func (*DisconnectPeerResponse) ProtoMessage()    {}
func (*DisconnectPeerResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{4}
}

func (m *DisconnectPeerResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_DisconnectPeerResponse.Unmarshal(m, b)
}
func (m *DisconnectPeerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_DisconnectPeerResponse.Marshal(b, m, deterministic)
}
func (m *DisconnectPeerResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_DisconnectPeerResponse.Merge(m, src)
}
func (m *DisconnectPeerResponse) XXX_Size() int {
	return xxx_messageInfo_DisconnectPeerResponse.Size(m)
}
func (m *DisconnectPeerResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_DisconnectPeerResponse.DiscardUnknown(m)
}

var xxx_messageInfo_DisconnectPeerResponse proto.InternalMessageInfo

type OpenChannelRequest struct {
	NodePubkeyString     string             `protobuf:"bytes,1,opt,name=node_pubkey_string,json=nodePubkeyString,proto3" json:"node_pubkey_string,omitempty"`
	Private              bool               `protobuf:"varint,2,opt,name=private,proto3" json:"private,omitempty"`
	RecipientInfo        *RecipientNodeInfo `protobuf:"bytes,3,opt,name=recipientInfo,proto3" json:"recipientInfo,omitempty"`
	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
	XXX_unrecognized     []byte             `json:"-"`
	XXX_sizecache        int32              `json:"-"`
}

func (m *OpenChannelRequest) Reset()         { *m = OpenChannelRequest{} }
func (m *OpenChannelRequest) String() string { return proto.CompactTextString(m) }
func (*OpenChannelRequest) ProtoMessage()    {}
func (*OpenChannelRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{5}
}

func (m *OpenChannelRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_OpenChannelRequest.Unmarshal(m, b)
}
func (m *OpenChannelRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_OpenChannelRequest.Marshal(b, m, deterministic)
}
func (m *OpenChannelRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_OpenChannelRequest.Merge(m, src)
}
func (m *OpenChannelRequest) XXX_Size() int {
	return xxx_messageInfo_OpenChannelRequest.Size(m)
}
func (m *OpenChannelRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_OpenChannelRequest.DiscardUnknown(m)
}

var xxx_messageInfo_OpenChannelRequest proto.InternalMessageInfo

func (m *OpenChannelRequest) GetNodePubkeyString() string {
	if m != nil {
		return m.NodePubkeyString
	}
	return ""
}

func (m *OpenChannelRequest) GetPrivate() bool {
	if m != nil {
		return m.Private
	}
	return false
}

func (m *OpenChannelRequest) GetRecipientInfo() *RecipientNodeInfo {
	if m != nil {
		return m.RecipientInfo
	}
	return nil
}

type OpenChannelResponse struct {
	TemplateChannelId    string   `protobuf:"bytes,1,opt,name=template_channel_id,json=templateChannelId,proto3" json:"template_channel_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *OpenChannelResponse) Reset()         { *m = OpenChannelResponse{} }
func (m *OpenChannelResponse) String() string { return proto.CompactTextString(m) }
func (*OpenChannelResponse) ProtoMessage()    {}
func (*OpenChannelResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{6}
}

func (m *OpenChannelResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_OpenChannelResponse.Unmarshal(m, b)
}
func (m *OpenChannelResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_OpenChannelResponse.Marshal(b, m, deterministic)
}
func (m *OpenChannelResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_OpenChannelResponse.Merge(m, src)
}
func (m *OpenChannelResponse) XXX_Size() int {
	return xxx_messageInfo_OpenChannelResponse.Size(m)
}
func (m *OpenChannelResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_OpenChannelResponse.DiscardUnknown(m)
}

var xxx_messageInfo_OpenChannelResponse proto.InternalMessageInfo

func (m *OpenChannelResponse) GetTemplateChannelId() string {
	if m != nil {
		return m.TemplateChannelId
	}
	return ""
}

type FundChannelRequest struct {
	TemplateChannelId    string             `protobuf:"bytes,1,opt,name=template_channel_id,json=templateChannelId,proto3" json:"template_channel_id,omitempty"`
	BtcAmount            float64            `protobuf:"fixed64,2,opt,name=btc_amount,json=btcAmount,proto3" json:"btc_amount,omitempty"`
	PropertyId           int64              `protobuf:"varint,3,opt,name=property_id,json=propertyId,proto3" json:"property_id,omitempty"`
	AssetAmount          float64            `protobuf:"fixed64,4,opt,name=asset_amount,json=assetAmount,proto3" json:"asset_amount,omitempty"`
	RecipientInfo        *RecipientNodeInfo `protobuf:"bytes,5,opt,name=recipientInfo,proto3" json:"recipientInfo,omitempty"`
	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
	XXX_unrecognized     []byte             `json:"-"`
	XXX_sizecache        int32              `json:"-"`
}

func (m *FundChannelRequest) Reset()         { *m = FundChannelRequest{} }
func (m *FundChannelRequest) String() string { return proto.CompactTextString(m) }
func (*FundChannelRequest) ProtoMessage()    {}
func (*FundChannelRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{7}
}

func (m *FundChannelRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_FundChannelRequest.Unmarshal(m, b)
}
func (m *FundChannelRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_FundChannelRequest.Marshal(b, m, deterministic)
}
func (m *FundChannelRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_FundChannelRequest.Merge(m, src)
}
func (m *FundChannelRequest) XXX_Size() int {
	return xxx_messageInfo_FundChannelRequest.Size(m)
}
func (m *FundChannelRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_FundChannelRequest.DiscardUnknown(m)
}

var xxx_messageInfo_FundChannelRequest proto.InternalMessageInfo

func (m *FundChannelRequest) GetTemplateChannelId() string {
	if m != nil {
		return m.TemplateChannelId
	}
	return ""
}

func (m *FundChannelRequest) GetBtcAmount() float64 {
	if m != nil {
		return m.BtcAmount
	}
	return 0
}

func (m *FundChannelRequest) GetPropertyId() int64 {
	if m != nil {
		return m.PropertyId
	}
	return 0
}

func (m *FundChannelRequest) GetAssetAmount() float64 {
	if m != nil {
		return m.AssetAmount
	}
	return 0
}

func (m *FundChannelRequest) GetRecipientInfo() *RecipientNodeInfo {
	if m != nil {
		return m.RecipientInfo
	}
	return nil
}

type FundChannelResponse struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *FundChannelResponse) Reset()         { *m = FundChannelResponse{} }
func (m *FundChannelResponse) String() string { return proto.CompactTextString(m) }
func (*FundChannelResponse) ProtoMessage()    {}
func (*FundChannelResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{8}
}

func (m *FundChannelResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_FundChannelResponse.Unmarshal(m, b)
}
func (m *FundChannelResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_FundChannelResponse.Marshal(b, m, deterministic)
}
func (m *FundChannelResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_FundChannelResponse.Merge(m, src)
}
func (m *FundChannelResponse) XXX_Size() int {
	return xxx_messageInfo_FundChannelResponse.Size(m)
}
func (m *FundChannelResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_FundChannelResponse.DiscardUnknown(m)
}

var xxx_messageInfo_FundChannelResponse proto.InternalMessageInfo

func (m *FundChannelResponse) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

type HelloRequest struct {
	Sayhi                string   `protobuf:"bytes,1,opt,name=sayhi,proto3" json:"sayhi,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *HelloRequest) Reset()         { *m = HelloRequest{} }
func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
func (*HelloRequest) ProtoMessage()    {}
func (*HelloRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{9}
}

func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_HelloRequest.Unmarshal(m, b)
}
func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
}
func (m *HelloRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_HelloRequest.Merge(m, src)
}
func (m *HelloRequest) XXX_Size() int {
	return xxx_messageInfo_HelloRequest.Size(m)
}
func (m *HelloRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_HelloRequest.DiscardUnknown(m)
}

var xxx_messageInfo_HelloRequest proto.InternalMessageInfo

func (m *HelloRequest) GetSayhi() string {
	if m != nil {
		return m.Sayhi
	}
	return ""
}

type HelloResponse struct {
	Resp                 string   `protobuf:"bytes,1,opt,name=resp,proto3" json:"resp,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *HelloResponse) Reset()         { *m = HelloResponse{} }
func (m *HelloResponse) String() string { return proto.CompactTextString(m) }
func (*HelloResponse) ProtoMessage()    {}
func (*HelloResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{10}
}

func (m *HelloResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_HelloResponse.Unmarshal(m, b)
}
func (m *HelloResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_HelloResponse.Marshal(b, m, deterministic)
}
func (m *HelloResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_HelloResponse.Merge(m, src)
}
func (m *HelloResponse) XXX_Size() int {
	return xxx_messageInfo_HelloResponse.Size(m)
}
func (m *HelloResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_HelloResponse.DiscardUnknown(m)
}

var xxx_messageInfo_HelloResponse proto.InternalMessageInfo

func (m *HelloResponse) GetResp() string {
	if m != nil {
		return m.Resp
	}
	return ""
}

type ListChannelsRequest struct {
	ActiveOnly   bool `protobuf:"varint,1,opt,name=active_only,json=activeOnly,proto3" json:"active_only,omitempty"`
	InactiveOnly bool `protobuf:"varint,2,opt,name=inactive_only,json=inactiveOnly,proto3" json:"inactive_only,omitempty"`
	PublicOnly   bool `protobuf:"varint,3,opt,name=public_only,json=publicOnly,proto3" json:"public_only,omitempty"`
	PrivateOnly  bool `protobuf:"varint,4,opt,name=private_only,json=privateOnly,proto3" json:"private_only,omitempty"`
	//
	//Filters the response for channels with a target peer's pubkey. If peer is
	//empty, all channels will be returned.
	Peer                 []byte   `protobuf:"bytes,5,opt,name=peer,proto3" json:"peer,omitempty"`
	PageSize             int32    `protobuf:"varint,6,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	PageIndex            int32    `protobuf:"varint,7,opt,name=page_index,json=pageIndex,proto3" json:"page_index,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ListChannelsRequest) Reset()         { *m = ListChannelsRequest{} }
func (m *ListChannelsRequest) String() string { return proto.CompactTextString(m) }
func (*ListChannelsRequest) ProtoMessage()    {}
func (*ListChannelsRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{11}
}

func (m *ListChannelsRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ListChannelsRequest.Unmarshal(m, b)
}
func (m *ListChannelsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ListChannelsRequest.Marshal(b, m, deterministic)
}
func (m *ListChannelsRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ListChannelsRequest.Merge(m, src)
}
func (m *ListChannelsRequest) XXX_Size() int {
	return xxx_messageInfo_ListChannelsRequest.Size(m)
}
func (m *ListChannelsRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ListChannelsRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ListChannelsRequest proto.InternalMessageInfo

func (m *ListChannelsRequest) GetActiveOnly() bool {
	if m != nil {
		return m.ActiveOnly
	}
	return false
}

func (m *ListChannelsRequest) GetInactiveOnly() bool {
	if m != nil {
		return m.InactiveOnly
	}
	return false
}

func (m *ListChannelsRequest) GetPublicOnly() bool {
	if m != nil {
		return m.PublicOnly
	}
	return false
}

func (m *ListChannelsRequest) GetPrivateOnly() bool {
	if m != nil {
		return m.PrivateOnly
	}
	return false
}

func (m *ListChannelsRequest) GetPeer() []byte {
	if m != nil {
		return m.Peer
	}
	return nil
}

func (m *ListChannelsRequest) GetPageSize() int32 {
	if m != nil {
		return m.PageSize
	}
	return 0
}

func (m *ListChannelsRequest) GetPageIndex() int32 {
	if m != nil {
		return m.PageIndex
	}
	return 0
}

type Channel struct {
	// Whether this channel is active or not
	Active bool `protobuf:"varint,1,opt,name=active,proto3" json:"active,omitempty"`
	// The identity pubkey of the remote node
	RemotePubkey string `protobuf:"bytes,2,opt,name=remote_pubkey,json=remotePubkey,proto3" json:"remote_pubkey,omitempty"`
	//
	//The outpoint (txid:index) of the funding transaction. With this value, Bob
	//will be able to generate a signature for Alice's version of the commitment
	//transaction.
	ChannelPoint string `protobuf:"bytes,3,opt,name=channel_point,json=channelPoint,proto3" json:"channel_point,omitempty"`
	ChanId       string `protobuf:"bytes,4,opt,name=chan_id,json=chanId,proto3" json:"chan_id,omitempty"`
	// The total amount of funds held in this channel
	Capacity int64 `protobuf:"varint,5,opt,name=capacity,proto3" json:"capacity,omitempty"`
	// This node's current balance in this channel
	LocalBalance int64 `protobuf:"varint,6,opt,name=local_balance,json=localBalance,proto3" json:"local_balance,omitempty"`
	// The counterparty's current balance in this channel
	RemoteBalance int64 `protobuf:"varint,7,opt,name=remote_balance,json=remoteBalance,proto3" json:"remote_balance,omitempty"`
	//
	//The amount calculated to be paid in fees for the current set of commitment
	//transactions. The fee amount is persisted with the channel in order to
	//allow the fee amount to be removed and recalculated with each channel state
	//update, including updates that happen after a system restart.
	CommitFee int64 `protobuf:"varint,8,opt,name=commit_fee,json=commitFee,proto3" json:"commit_fee,omitempty"`
	// The weight of the commitment transaction
	CommitWeight int64 `protobuf:"varint,9,opt,name=commit_weight,json=commitWeight,proto3" json:"commit_weight,omitempty"`
	//
	//The required number of satoshis per kilo-weight that the requester will pay
	//at all times, for both the funding transaction and commitment transaction.
	//This value can later be updated once the channel is open.
	FeePerKw int64 `protobuf:"varint,10,opt,name=fee_per_kw,json=feePerKw,proto3" json:"fee_per_kw,omitempty"`
	// The unsettled balance in this channel
	UnsettledBalance int64 `protobuf:"varint,11,opt,name=unsettled_balance,json=unsettledBalance,proto3" json:"unsettled_balance,omitempty"`
	//
	//The total number of satoshis we've sent within this channel.
	TotalSatoshisSent int64 `protobuf:"varint,12,opt,name=total_satoshis_sent,json=totalSatoshisSent,proto3" json:"total_satoshis_sent,omitempty"`
	//
	//The total number of satoshis we've received within this channel.
	TotalSatoshisReceived int64 `protobuf:"varint,13,opt,name=total_satoshis_received,json=totalSatoshisReceived,proto3" json:"total_satoshis_received,omitempty"`
	//
	//The total number of updates conducted within this channel.
	NumUpdates uint64 `protobuf:"varint,14,opt,name=num_updates,json=numUpdates,proto3" json:"num_updates,omitempty"`
	// Whether this channel is advertised to the network or not.
	Private bool `protobuf:"varint,17,opt,name=private,proto3" json:"private,omitempty"`
	// True if we were the ones that created the channel.
	Initiator bool `protobuf:"varint,18,opt,name=initiator,proto3" json:"initiator,omitempty"`
	// A set of flags showing the current state of the channel.
	ChanStatusFlags string `protobuf:"bytes,19,opt,name=chan_status_flags,json=chanStatusFlags,proto3" json:"chan_status_flags,omitempty"`
	//
	//The number of seconds that the channel has been monitored by the channel
	//scoring system. Scores are currently not persisted, so this value may be
	//less than the lifetime of the channel [EXPERIMENTAL].
	Lifetime int64 `protobuf:"varint,23,opt,name=lifetime,proto3" json:"lifetime,omitempty"`
	//
	//The number of seconds that the remote peer has been observed as being online
	//by the channel scoring system over the lifetime of the channel
	//[EXPERIMENTAL].
	Uptime int64 `protobuf:"varint,24,opt,name=uptime,proto3" json:"uptime,omitempty"`
	//
	//Close address is the address that we will enforce payout to on cooperative
	//close if the channel was opened utilizing option upfront shutdown. This
	//value can be set on channel open by setting close_address in an open channel
	//request. If this value is not set, you can still choose a payout address by
	//cooperatively closing with the delivery_address field set.
	CloseAddress string `protobuf:"bytes,25,opt,name=close_address,json=closeAddress,proto3" json:"close_address,omitempty"`
	//
	//The amount that the initiator of the channel optionally pushed to the remote
	//party on channel open. This amount will be zero if the channel initiator did
	//not push any funds to the remote peer. If the initiator field is true, we
	//pushed this amount to our peer, if it is false, the remote peer pushed this
	//amount to us.
	PushAmountSat        uint64   `protobuf:"varint,27,opt,name=push_amount_sat,json=pushAmountSat,proto3" json:"push_amount_sat,omitempty"`
	PropertyId           int64    `protobuf:"varint,28,opt,name=property_id,json=propertyId,proto3" json:"property_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *Channel) Reset()         { *m = Channel{} }
func (m *Channel) String() string { return proto.CompactTextString(m) }
func (*Channel) ProtoMessage()    {}
func (*Channel) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{12}
}

func (m *Channel) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Channel.Unmarshal(m, b)
}
func (m *Channel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Channel.Marshal(b, m, deterministic)
}
func (m *Channel) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Channel.Merge(m, src)
}
func (m *Channel) XXX_Size() int {
	return xxx_messageInfo_Channel.Size(m)
}
func (m *Channel) XXX_DiscardUnknown() {
	xxx_messageInfo_Channel.DiscardUnknown(m)
}

var xxx_messageInfo_Channel proto.InternalMessageInfo

func (m *Channel) GetActive() bool {
	if m != nil {
		return m.Active
	}
	return false
}

func (m *Channel) GetRemotePubkey() string {
	if m != nil {
		return m.RemotePubkey
	}
	return ""
}

func (m *Channel) GetChannelPoint() string {
	if m != nil {
		return m.ChannelPoint
	}
	return ""
}

func (m *Channel) GetChanId() string {
	if m != nil {
		return m.ChanId
	}
	return ""
}

func (m *Channel) GetCapacity() int64 {
	if m != nil {
		return m.Capacity
	}
	return 0
}

func (m *Channel) GetLocalBalance() int64 {
	if m != nil {
		return m.LocalBalance
	}
	return 0
}

func (m *Channel) GetRemoteBalance() int64 {
	if m != nil {
		return m.RemoteBalance
	}
	return 0
}

func (m *Channel) GetCommitFee() int64 {
	if m != nil {
		return m.CommitFee
	}
	return 0
}

func (m *Channel) GetCommitWeight() int64 {
	if m != nil {
		return m.CommitWeight
	}
	return 0
}

func (m *Channel) GetFeePerKw() int64 {
	if m != nil {
		return m.FeePerKw
	}
	return 0
}

func (m *Channel) GetUnsettledBalance() int64 {
	if m != nil {
		return m.UnsettledBalance
	}
	return 0
}

func (m *Channel) GetTotalSatoshisSent() int64 {
	if m != nil {
		return m.TotalSatoshisSent
	}
	return 0
}

func (m *Channel) GetTotalSatoshisReceived() int64 {
	if m != nil {
		return m.TotalSatoshisReceived
	}
	return 0
}

func (m *Channel) GetNumUpdates() uint64 {
	if m != nil {
		return m.NumUpdates
	}
	return 0
}

func (m *Channel) GetPrivate() bool {
	if m != nil {
		return m.Private
	}
	return false
}

func (m *Channel) GetInitiator() bool {
	if m != nil {
		return m.Initiator
	}
	return false
}

func (m *Channel) GetChanStatusFlags() string {
	if m != nil {
		return m.ChanStatusFlags
	}
	return ""
}

func (m *Channel) GetLifetime() int64 {
	if m != nil {
		return m.Lifetime
	}
	return 0
}

func (m *Channel) GetUptime() int64 {
	if m != nil {
		return m.Uptime
	}
	return 0
}

func (m *Channel) GetCloseAddress() string {
	if m != nil {
		return m.CloseAddress
	}
	return ""
}

func (m *Channel) GetPushAmountSat() uint64 {
	if m != nil {
		return m.PushAmountSat
	}
	return 0
}

func (m *Channel) GetPropertyId() int64 {
	if m != nil {
		return m.PropertyId
	}
	return 0
}

type PendingChannelsRequest struct {
	PageSize             int32    `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	PageIndex            int32    `protobuf:"varint,2,opt,name=page_index,json=pageIndex,proto3" json:"page_index,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *PendingChannelsRequest) Reset()         { *m = PendingChannelsRequest{} }
func (m *PendingChannelsRequest) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsRequest) ProtoMessage()    {}
func (*PendingChannelsRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{13}
}

func (m *PendingChannelsRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_PendingChannelsRequest.Unmarshal(m, b)
}
func (m *PendingChannelsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_PendingChannelsRequest.Marshal(b, m, deterministic)
}
func (m *PendingChannelsRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_PendingChannelsRequest.Merge(m, src)
}
func (m *PendingChannelsRequest) XXX_Size() int {
	return xxx_messageInfo_PendingChannelsRequest.Size(m)
}
func (m *PendingChannelsRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_PendingChannelsRequest.DiscardUnknown(m)
}

var xxx_messageInfo_PendingChannelsRequest proto.InternalMessageInfo

func (m *PendingChannelsRequest) GetPageSize() int32 {
	if m != nil {
		return m.PageSize
	}
	return 0
}

func (m *PendingChannelsRequest) GetPageIndex() int32 {
	if m != nil {
		return m.PageIndex
	}
	return 0
}

type ListChannelsResponse struct {
	// The list of active channels
	Channels             []*Channel `protobuf:"bytes,1,rep,name=channels,proto3" json:"channels,omitempty"`
	XXX_NoUnkeyedLiteral struct{}   `json:"-"`
	XXX_unrecognized     []byte     `json:"-"`
	XXX_sizecache        int32      `json:"-"`
}

func (m *ListChannelsResponse) Reset()         { *m = ListChannelsResponse{} }
func (m *ListChannelsResponse) String() string { return proto.CompactTextString(m) }
func (*ListChannelsResponse) ProtoMessage()    {}
func (*ListChannelsResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{14}
}

func (m *ListChannelsResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ListChannelsResponse.Unmarshal(m, b)
}
func (m *ListChannelsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ListChannelsResponse.Marshal(b, m, deterministic)
}
func (m *ListChannelsResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ListChannelsResponse.Merge(m, src)
}
func (m *ListChannelsResponse) XXX_Size() int {
	return xxx_messageInfo_ListChannelsResponse.Size(m)
}
func (m *ListChannelsResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_ListChannelsResponse.DiscardUnknown(m)
}

var xxx_messageInfo_ListChannelsResponse proto.InternalMessageInfo

func (m *ListChannelsResponse) GetChannels() []*Channel {
	if m != nil {
		return m.Channels
	}
	return nil
}

type LatestTransactionRequest struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *LatestTransactionRequest) Reset()         { *m = LatestTransactionRequest{} }
func (m *LatestTransactionRequest) String() string { return proto.CompactTextString(m) }
func (*LatestTransactionRequest) ProtoMessage()    {}
func (*LatestTransactionRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{15}
}

func (m *LatestTransactionRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_LatestTransactionRequest.Unmarshal(m, b)
}
func (m *LatestTransactionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_LatestTransactionRequest.Marshal(b, m, deterministic)
}
func (m *LatestTransactionRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_LatestTransactionRequest.Merge(m, src)
}
func (m *LatestTransactionRequest) XXX_Size() int {
	return xxx_messageInfo_LatestTransactionRequest.Size(m)
}
func (m *LatestTransactionRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_LatestTransactionRequest.DiscardUnknown(m)
}

var xxx_messageInfo_LatestTransactionRequest proto.InternalMessageInfo

func (m *LatestTransactionRequest) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

type Transaction struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	AmountA              float64  `protobuf:"fixed64,2,opt,name=amount_a,json=amountA,proto3" json:"amount_a,omitempty"`
	AmountB              float64  `protobuf:"fixed64,3,opt,name=amount_b,json=amountB,proto3" json:"amount_b,omitempty"`
	PeerA                string   `protobuf:"bytes,4,opt,name=peer_a,json=peerA,proto3" json:"peer_a,omitempty"`
	PeerB                string   `protobuf:"bytes,5,opt,name=peer_b,json=peerB,proto3" json:"peer_b,omitempty"`
	CurrState            int32    `protobuf:"varint,6,opt,name=curr_state,json=currState,proto3" json:"curr_state,omitempty"`
	TxHash               string   `protobuf:"bytes,7,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"`
	TxType               int32    `protobuf:"varint,8,opt,name=tx_type,json=txType,proto3" json:"tx_type,omitempty"`
	H                    string   `protobuf:"bytes,9,opt,name=h,proto3" json:"h,omitempty"`
	R                    string   `protobuf:"bytes,10,opt,name=r,proto3" json:"r,omitempty"`
	AmountHtlc           float64  `protobuf:"fixed64,11,opt,name=amount_htlc,json=amountHtlc,proto3" json:"amount_htlc,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *Transaction) Reset()         { *m = Transaction{} }
func (m *Transaction) String() string { return proto.CompactTextString(m) }
func (*Transaction) ProtoMessage()    {}
func (*Transaction) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{16}
}

func (m *Transaction) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Transaction.Unmarshal(m, b)
}
func (m *Transaction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Transaction.Marshal(b, m, deterministic)
}
func (m *Transaction) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Transaction.Merge(m, src)
}
func (m *Transaction) XXX_Size() int {
	return xxx_messageInfo_Transaction.Size(m)
}
func (m *Transaction) XXX_DiscardUnknown() {
	xxx_messageInfo_Transaction.DiscardUnknown(m)
}

var xxx_messageInfo_Transaction proto.InternalMessageInfo

func (m *Transaction) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

func (m *Transaction) GetAmountA() float64 {
	if m != nil {
		return m.AmountA
	}
	return 0
}

func (m *Transaction) GetAmountB() float64 {
	if m != nil {
		return m.AmountB
	}
	return 0
}

func (m *Transaction) GetPeerA() string {
	if m != nil {
		return m.PeerA
	}
	return ""
}

func (m *Transaction) GetPeerB() string {
	if m != nil {
		return m.PeerB
	}
	return ""
}

func (m *Transaction) GetCurrState() int32 {
	if m != nil {
		return m.CurrState
	}
	return 0
}

func (m *Transaction) GetTxHash() string {
	if m != nil {
		return m.TxHash
	}
	return ""
}

func (m *Transaction) GetTxType() int32 {
	if m != nil {
		return m.TxType
	}
	return 0
}

func (m *Transaction) GetH() string {
	if m != nil {
		return m.H
	}
	return ""
}

func (m *Transaction) GetR() string {
	if m != nil {
		return m.R
	}
	return ""
}

func (m *Transaction) GetAmountHtlc() float64 {
	if m != nil {
		return m.AmountHtlc
	}
	return 0
}

type GetTransactionsRequest struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	PageSize             int32    `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	PageIndex            int32    `protobuf:"varint,3,opt,name=page_index,json=pageIndex,proto3" json:"page_index,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *GetTransactionsRequest) Reset()         { *m = GetTransactionsRequest{} }
func (m *GetTransactionsRequest) String() string { return proto.CompactTextString(m) }
func (*GetTransactionsRequest) ProtoMessage()    {}
func (*GetTransactionsRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{17}
}

func (m *GetTransactionsRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_GetTransactionsRequest.Unmarshal(m, b)
}
func (m *GetTransactionsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_GetTransactionsRequest.Marshal(b, m, deterministic)
}
func (m *GetTransactionsRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_GetTransactionsRequest.Merge(m, src)
}
func (m *GetTransactionsRequest) XXX_Size() int {
	return xxx_messageInfo_GetTransactionsRequest.Size(m)
}
func (m *GetTransactionsRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_GetTransactionsRequest.DiscardUnknown(m)
}

var xxx_messageInfo_GetTransactionsRequest proto.InternalMessageInfo

func (m *GetTransactionsRequest) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

func (m *GetTransactionsRequest) GetPageSize() int32 {
	if m != nil {
		return m.PageSize
	}
	return 0
}

func (m *GetTransactionsRequest) GetPageIndex() int32 {
	if m != nil {
		return m.PageIndex
	}
	return 0
}

type TransactionDetails struct {
	Transactions         []*Transaction `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"`
	TotalCount           int32          `protobuf:"varint,2,opt,name=total_count,json=totalCount,proto3" json:"total_count,omitempty"`
	PageSize             int32          `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	PageIndex            int32          `protobuf:"varint,4,opt,name=page_index,json=pageIndex,proto3" json:"page_index,omitempty"`
	XXX_NoUnkeyedLiteral struct{}       `json:"-"`
	XXX_unrecognized     []byte         `json:"-"`
	XXX_sizecache        int32          `json:"-"`
}

func (m *TransactionDetails) Reset()         { *m = TransactionDetails{} }
func (m *TransactionDetails) String() string { return proto.CompactTextString(m) }
func (*TransactionDetails) ProtoMessage()    {}
func (*TransactionDetails) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{18}
}

func (m *TransactionDetails) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_TransactionDetails.Unmarshal(m, b)
}
func (m *TransactionDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_TransactionDetails.Marshal(b, m, deterministic)
}
func (m *TransactionDetails) XXX_Merge(src proto.Message) {
	xxx_messageInfo_TransactionDetails.Merge(m, src)
}
func (m *TransactionDetails) XXX_Size() int {
	return xxx_messageInfo_TransactionDetails.Size(m)
}
func (m *TransactionDetails) XXX_DiscardUnknown() {
	xxx_messageInfo_TransactionDetails.DiscardUnknown(m)
}

var xxx_messageInfo_TransactionDetails proto.InternalMessageInfo

func (m *TransactionDetails) GetTransactions() []*Transaction {
	if m != nil {
		return m.Transactions
	}
	return nil
}

func (m *TransactionDetails) GetTotalCount() int32 {
	if m != nil {
		return m.TotalCount
	}
	return 0
}

func (m *TransactionDetails) GetPageSize() int32 {
	if m != nil {
		return m.PageSize
	}
	return 0
}

func (m *TransactionDetails) GetPageIndex() int32 {
	if m != nil {
		return m.PageIndex
	}
	return 0
}

type ChannelBalanceRequest struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ChannelBalanceRequest) Reset()         { *m = ChannelBalanceRequest{} }
func (m *ChannelBalanceRequest) String() string { return proto.CompactTextString(m) }
func (*ChannelBalanceRequest) ProtoMessage()    {}
func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{19}
}

func (m *ChannelBalanceRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ChannelBalanceRequest.Unmarshal(m, b)
}
func (m *ChannelBalanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ChannelBalanceRequest.Marshal(b, m, deterministic)
}
func (m *ChannelBalanceRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ChannelBalanceRequest.Merge(m, src)
}
func (m *ChannelBalanceRequest) XXX_Size() int {
	return xxx_messageInfo_ChannelBalanceRequest.Size(m)
}
func (m *ChannelBalanceRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ChannelBalanceRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ChannelBalanceRequest proto.InternalMessageInfo

type ChannelBalanceResponse struct {
	LocalBalance             float64  `protobuf:"fixed64,1,opt,name=local_balance,json=localBalance,proto3" json:"local_balance,omitempty"`
	RemoteBalance            float64  `protobuf:"fixed64,2,opt,name=remote_balance,json=remoteBalance,proto3" json:"remote_balance,omitempty"`
	UnsettledLocalBalance    float64  `protobuf:"fixed64,3,opt,name=unsettled_local_balance,json=unsettledLocalBalance,proto3" json:"unsettled_local_balance,omitempty"`
	UnsettledRemoteBalance   float64  `protobuf:"fixed64,4,opt,name=unsettled_remote_balance,json=unsettledRemoteBalance,proto3" json:"unsettled_remote_balance,omitempty"`
	PendingOpenLocalBalance  float64  `protobuf:"fixed64,5,opt,name=pending_open_local_balance,json=pendingOpenLocalBalance,proto3" json:"pending_open_local_balance,omitempty"`
	PendingOpenRemoteBalance float64  `protobuf:"fixed64,6,opt,name=pending_open_remote_balance,json=pendingOpenRemoteBalance,proto3" json:"pending_open_remote_balance,omitempty"`
	XXX_NoUnkeyedLiteral     struct{} `json:"-"`
	XXX_unrecognized         []byte   `json:"-"`
	XXX_sizecache            int32    `json:"-"`
}

func (m *ChannelBalanceResponse) Reset()         { *m = ChannelBalanceResponse{} }
func (m *ChannelBalanceResponse) String() string { return proto.CompactTextString(m) }
func (*ChannelBalanceResponse) ProtoMessage()    {}
func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{20}
}

func (m *ChannelBalanceResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ChannelBalanceResponse.Unmarshal(m, b)
}
func (m *ChannelBalanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ChannelBalanceResponse.Marshal(b, m, deterministic)
}
func (m *ChannelBalanceResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ChannelBalanceResponse.Merge(m, src)
}
func (m *ChannelBalanceResponse) XXX_Size() int {
	return xxx_messageInfo_ChannelBalanceResponse.Size(m)
}
func (m *ChannelBalanceResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_ChannelBalanceResponse.DiscardUnknown(m)
}

var xxx_messageInfo_ChannelBalanceResponse proto.InternalMessageInfo

func (m *ChannelBalanceResponse) GetLocalBalance() float64 {
	if m != nil {
		return m.LocalBalance
	}
	return 0
}

func (m *ChannelBalanceResponse) GetRemoteBalance() float64 {
	if m != nil {
		return m.RemoteBalance
	}
	return 0
}

func (m *ChannelBalanceResponse) GetUnsettledLocalBalance() float64 {
	if m != nil {
		return m.UnsettledLocalBalance
	}
	return 0
}

func (m *ChannelBalanceResponse) GetUnsettledRemoteBalance() float64 {
	if m != nil {
		return m.UnsettledRemoteBalance
	}
	return 0
}

func (m *ChannelBalanceResponse) GetPendingOpenLocalBalance() float64 {
	if m != nil {
		return m.PendingOpenLocalBalance
	}
	return 0
}

func (m *ChannelBalanceResponse) GetPendingOpenRemoteBalance() float64 {
	if m != nil {
		return m.PendingOpenRemoteBalance
	}
	return 0
}

type CloseChannelRequest struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *CloseChannelRequest) Reset()         { *m = CloseChannelRequest{} }
func (m *CloseChannelRequest) String() string { return proto.CompactTextString(m) }
func (*CloseChannelRequest) ProtoMessage()    {}
func (*CloseChannelRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{21}
}

func (m *CloseChannelRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_CloseChannelRequest.Unmarshal(m, b)
}
func (m *CloseChannelRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_CloseChannelRequest.Marshal(b, m, deterministic)
}
func (m *CloseChannelRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_CloseChannelRequest.Merge(m, src)
}
func (m *CloseChannelRequest) XXX_Size() int {
	return xxx_messageInfo_CloseChannelRequest.Size(m)
}
func (m *CloseChannelRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_CloseChannelRequest.DiscardUnknown(m)
}

var xxx_messageInfo_CloseChannelRequest proto.InternalMessageInfo

func (m *CloseChannelRequest) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

type CloseChannelResponse struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	LocalBalance         float64  `protobuf:"fixed64,2,opt,name=local_balance,json=localBalance,proto3" json:"local_balance,omitempty"`
	RemoteBalance        float64  `protobuf:"fixed64,3,opt,name=remote_balance,json=remoteBalance,proto3" json:"remote_balance,omitempty"`
	TotalAmount          float64  `protobuf:"fixed64,4,opt,name=total_amount,json=totalAmount,proto3" json:"total_amount,omitempty"`
	PropertyId           int64    `protobuf:"varint,5,opt,name=property_id,json=propertyId,proto3" json:"property_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *CloseChannelResponse) Reset()         { *m = CloseChannelResponse{} }
func (m *CloseChannelResponse) String() string { return proto.CompactTextString(m) }
func (*CloseChannelResponse) ProtoMessage()    {}
func (*CloseChannelResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{22}
}

func (m *CloseChannelResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_CloseChannelResponse.Unmarshal(m, b)
}
func (m *CloseChannelResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_CloseChannelResponse.Marshal(b, m, deterministic)
}
func (m *CloseChannelResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_CloseChannelResponse.Merge(m, src)
}
func (m *CloseChannelResponse) XXX_Size() int {
	return xxx_messageInfo_CloseChannelResponse.Size(m)
}
func (m *CloseChannelResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_CloseChannelResponse.DiscardUnknown(m)
}

var xxx_messageInfo_CloseChannelResponse proto.InternalMessageInfo

func (m *CloseChannelResponse) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

func (m *CloseChannelResponse) GetLocalBalance() float64 {
	if m != nil {
		return m.LocalBalance
	}
	return 0
}

func (m *CloseChannelResponse) GetRemoteBalance() float64 {
	if m != nil {
		return m.RemoteBalance
	}
	return 0
}

func (m *CloseChannelResponse) GetTotalAmount() float64 {
	if m != nil {
		return m.TotalAmount
	}
	return 0
}

func (m *CloseChannelResponse) GetPropertyId() int64 {
	if m != nil {
		return m.PropertyId
	}
	return 0
}

type ChanInfoRequest struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ChanInfoRequest) Reset()         { *m = ChanInfoRequest{} }
func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) }
func (*ChanInfoRequest) ProtoMessage()    {}
func (*ChanInfoRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{23}
}

func (m *ChanInfoRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ChanInfoRequest.Unmarshal(m, b)
}
func (m *ChanInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ChanInfoRequest.Marshal(b, m, deterministic)
}
func (m *ChanInfoRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ChanInfoRequest.Merge(m, src)
}
func (m *ChanInfoRequest) XXX_Size() int {
	return xxx_messageInfo_ChanInfoRequest.Size(m)
}
func (m *ChanInfoRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ChanInfoRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ChanInfoRequest proto.InternalMessageInfo

func (m *ChanInfoRequest) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

type ChannelEdge struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	TotalAmount          float64  `protobuf:"fixed64,2,opt,name=total_amount,json=totalAmount,proto3" json:"total_amount,omitempty"`
	PropertyId           int64    `protobuf:"varint,3,opt,name=property_id,json=propertyId,proto3" json:"property_id,omitempty"`
	ChannelAddress       string   `protobuf:"bytes,4,opt,name=channel_address,json=channelAddress,proto3" json:"channel_address,omitempty"`
	Node1Pub             string   `protobuf:"bytes,5,opt,name=node1_pub,json=node1Pub,proto3" json:"node1_pub,omitempty"`
	Node2Pub             string   `protobuf:"bytes,6,opt,name=node2_pub,json=node2Pub,proto3" json:"node2_pub,omitempty"`
	CurrState            int64    `protobuf:"varint,7,opt,name=curr_state,json=currState,proto3" json:"curr_state,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ChannelEdge) Reset()         { *m = ChannelEdge{} }
func (m *ChannelEdge) String() string { return proto.CompactTextString(m) }
func (*ChannelEdge) ProtoMessage()    {}
func (*ChannelEdge) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{24}
}

func (m *ChannelEdge) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ChannelEdge.Unmarshal(m, b)
}
func (m *ChannelEdge) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ChannelEdge.Marshal(b, m, deterministic)
}
func (m *ChannelEdge) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ChannelEdge.Merge(m, src)
}
func (m *ChannelEdge) XXX_Size() int {
	return xxx_messageInfo_ChannelEdge.Size(m)
}
func (m *ChannelEdge) XXX_DiscardUnknown() {
	xxx_messageInfo_ChannelEdge.DiscardUnknown(m)
}

var xxx_messageInfo_ChannelEdge proto.InternalMessageInfo

func (m *ChannelEdge) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

func (m *ChannelEdge) GetTotalAmount() float64 {
	if m != nil {
		return m.TotalAmount
	}
	return 0
}

func (m *ChannelEdge) GetPropertyId() int64 {
	if m != nil {
		return m.PropertyId
	}
	return 0
}

func (m *ChannelEdge) GetChannelAddress() string {
	if m != nil {
		return m.ChannelAddress
	}
	return ""
}

func (m *ChannelEdge) GetNode1Pub() string {
	if m != nil {
		return m.Node1Pub
	}
	return ""
}

func (m *ChannelEdge) GetNode2Pub() string {
	if m != nil {
		return m.Node2Pub
	}
	return ""
}

func (m *ChannelEdge) GetCurrState() int64 {
	if m != nil {
		return m.CurrState
	}
	return 0
}

type ClosedChannelsRequest struct {
	PageSize             int32    `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
	PageIndex            int32    `protobuf:"varint,2,opt,name=page_index,json=pageIndex,proto3" json:"page_index,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ClosedChannelsRequest) Reset()         { *m = ClosedChannelsRequest{} }
func (m *ClosedChannelsRequest) String() string { return proto.CompactTextString(m) }
func (*ClosedChannelsRequest) ProtoMessage()    {}
func (*ClosedChannelsRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{25}
}

func (m *ClosedChannelsRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ClosedChannelsRequest.Unmarshal(m, b)
}
func (m *ClosedChannelsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ClosedChannelsRequest.Marshal(b, m, deterministic)
}
func (m *ClosedChannelsRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ClosedChannelsRequest.Merge(m, src)
}
func (m *ClosedChannelsRequest) XXX_Size() int {
	return xxx_messageInfo_ClosedChannelsRequest.Size(m)
}
func (m *ClosedChannelsRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ClosedChannelsRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ClosedChannelsRequest proto.InternalMessageInfo

func (m *ClosedChannelsRequest) GetPageSize() int32 {
	if m != nil {
		return m.PageSize
	}
	return 0
}

func (m *ClosedChannelsRequest) GetPageIndex() int32 {
	if m != nil {
		return m.PageIndex
	}
	return 0
}

type ClosedChannelsResponse struct {
	Channels             []*Channel `protobuf:"bytes,1,rep,name=channels,proto3" json:"channels,omitempty"`
	XXX_NoUnkeyedLiteral struct{}   `json:"-"`
	XXX_unrecognized     []byte     `json:"-"`
	XXX_sizecache        int32      `json:"-"`
}

func (m *ClosedChannelsResponse) Reset()         { *m = ClosedChannelsResponse{} }
func (m *ClosedChannelsResponse) String() string { return proto.CompactTextString(m) }
func (*ClosedChannelsResponse) ProtoMessage()    {}
func (*ClosedChannelsResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_77a6da22d6a3feb1, []int{26}
}

func (m *ClosedChannelsResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ClosedChannelsResponse.Unmarshal(m, b)
}
func (m *ClosedChannelsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ClosedChannelsResponse.Marshal(b, m, deterministic)
}
func (m *ClosedChannelsResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ClosedChannelsResponse.Merge(m, src)
}
func (m *ClosedChannelsResponse) XXX_Size() int {
	return xxx_messageInfo_ClosedChannelsResponse.Size(m)
}
func (m *ClosedChannelsResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_ClosedChannelsResponse.DiscardUnknown(m)
}

var xxx_messageInfo_ClosedChannelsResponse proto.InternalMessageInfo

func (m *ClosedChannelsResponse) GetChannels() []*Channel {
	if m != nil {
		return m.Channels
	}
	return nil
}

func init() {
	proto.RegisterType((*RecipientNodeInfo)(nil), "proxy.RecipientNodeInfo")
	proto.RegisterType((*ConnectPeerRequest)(nil), "proxy.ConnectPeerRequest")
	proto.RegisterType((*ConnectPeerResponse)(nil), "proxy.ConnectPeerResponse")
	proto.RegisterType((*DisconnectPeerRequest)(nil), "proxy.DisconnectPeerRequest")
	proto.RegisterType((*DisconnectPeerResponse)(nil), "proxy.DisconnectPeerResponse")
	proto.RegisterType((*OpenChannelRequest)(nil), "proxy.OpenChannelRequest")
	proto.RegisterType((*OpenChannelResponse)(nil), "proxy.OpenChannelResponse")
	proto.RegisterType((*FundChannelRequest)(nil), "proxy.FundChannelRequest")
	proto.RegisterType((*FundChannelResponse)(nil), "proxy.FundChannelResponse")
	proto.RegisterType((*HelloRequest)(nil), "proxy.HelloRequest")
	proto.RegisterType((*HelloResponse)(nil), "proxy.HelloResponse")
	proto.RegisterType((*ListChannelsRequest)(nil), "proxy.ListChannelsRequest")
	proto.RegisterType((*Channel)(nil), "proxy.Channel")
	proto.RegisterType((*PendingChannelsRequest)(nil), "proxy.PendingChannelsRequest")
	proto.RegisterType((*ListChannelsResponse)(nil), "proxy.ListChannelsResponse")
	proto.RegisterType((*LatestTransactionRequest)(nil), "proxy.LatestTransactionRequest")
	proto.RegisterType((*Transaction)(nil), "proxy.Transaction")
	proto.RegisterType((*GetTransactionsRequest)(nil), "proxy.GetTransactionsRequest")
	proto.RegisterType((*TransactionDetails)(nil), "proxy.TransactionDetails")
	proto.RegisterType((*ChannelBalanceRequest)(nil), "proxy.ChannelBalanceRequest")
	proto.RegisterType((*ChannelBalanceResponse)(nil), "proxy.ChannelBalanceResponse")
	proto.RegisterType((*CloseChannelRequest)(nil), "proxy.CloseChannelRequest")
	proto.RegisterType((*CloseChannelResponse)(nil), "proxy.CloseChannelResponse")
	proto.RegisterType((*ChanInfoRequest)(nil), "proxy.ChanInfoRequest")
	proto.RegisterType((*ChannelEdge)(nil), "proxy.ChannelEdge")
	proto.RegisterType((*ClosedChannelsRequest)(nil), "proxy.ClosedChannelsRequest")
	proto.RegisterType((*ClosedChannelsResponse)(nil), "proxy.ClosedChannelsResponse")
}

func init() {
	proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1)
}

var fileDescriptor_77a6da22d6a3feb1 = []byte{
	// 1620 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x5b, 0x6e, 0xdb, 0x46,
	0x17, 0x06, 0x75, 0xd7, 0x91, 0x6c, 0xc7, 0x23, 0x5b, 0xa6, 0x65, 0x07, 0x71, 0x94, 0xff, 0x62,
	0x24, 0x3f, 0x8c, 0xbf, 0x4e, 0x11, 0x34, 0x28, 0x5a, 0xc0, 0x97, 0xc4, 0x36, 0xe2, 0x34, 0x06,
	0x9d, 0xa0, 0x40, 0x5f, 0x08, 0x8a, 0x1c, 0x5b, 0x44, 0xa8, 0x21, 0xcb, 0x19, 0x25, 0x56, 0x80,
	0x6e, 0xa0, 0x6b, 0x28, 0xfa, 0xde, 0xc7, 0x2e, 0xa2, 0x1b, 0xe8, 0x26, 0xfa, 0x58, 0xa0, 0x2b,
	0x28, 0xe6, 0xcc, 0x90, 0x22, 0x29, 0xc5, 0x76, 0x80, 0xbe, 0x89, 0xdf, 0xb9, 0xcc, 0xb9, 0xcf,
	0x19, 0x41, 0x33, 0x8e, 0xdc, 0x9d, 0x28, 0x0e, 0x45, 0x48, 0xaa, 0x51, 0x1c, 0x5e, 0x4d, 0xfa,
	0x3f, 0xc0, 0xb2, 0x45, 0x5d, 0x3f, 0xf2, 0x29, 0x13, 0xdf, 0x84, 0x1e, 0x3d, 0x61, 0x17, 0x21,
	0x79, 0x0c, 0xdd, 0x38, 0x01, 0x6d, 0x16, 0x7a, 0xd4, 0x8e, 0x28, 0x8d, 0x6d, 0xdf, 0x33, 0x8d,
	0x2d, 0x63, 0xbb, 0x69, 0x75, 0xe2, 0xac, 0xc8, 0x19, 0xa5, 0xf1, 0x89, 0x97, 0x17, 0x1a, 0x73,
	0x1a, 0xa7, 0x42, 0xa5, 0x82, 0xd0, 0x1b, 0x4e, 0x63, 0x25, 0xd4, 0xdf, 0x06, 0x72, 0x10, 0x32,
	0x46, 0x5d, 0x21, 0x01, 0x8b, 0x7e, 0x3f, 0xa6, 0x5c, 0x10, 0x02, 0x15, 0xc7, 0xf3, 0x62, 0x7d,
	0x1a, 0xfe, 0xee, 0xaf, 0x42, 0x27, 0xc7, 0xc9, 0xa3, 0x90, 0x71, 0xda, 0x7f, 0x04, 0xab, 0x87,
	0x3e, 0x77, 0x6f, 0xa7, 0xc3, 0x84, 0x6e, 0x91, 0x59, 0xab, 0xf9, 0xc9, 0x00, 0xf2, 0x2a, 0xa2,
	0xec, 0x60, 0xe8, 0x30, 0x46, 0x83, 0x44, 0xc9, 0xff, 0x80, 0x28, 0xf7, 0xc7, 0x83, 0xb7, 0x74,
	0x62, 0x73, 0x11, 0xfb, 0xec, 0x52, 0xab, 0xbc, 0x23, 0x29, 0x67, 0x48, 0x38, 0x47, 0x9c, 0x98,
	0x50, 0x8f, 0x62, 0xff, 0x9d, 0x23, 0x28, 0xba, 0xdc, 0xb0, 0x92, 0x4f, 0xf2, 0x35, 0x2c, 0xa4,
	0xde, 0xcb, 0x08, 0x9b, 0xe5, 0x2d, 0x63, 0xbb, 0xb5, 0x6b, 0xee, 0x60, 0x12, 0x76, 0x66, 0x32,
	0x60, 0xe5, 0xd9, 0xfb, 0xcf, 0xa0, 0x93, 0xb3, 0x4e, 0x59, 0x4d, 0x76, 0xa0, 0x23, 0xe8, 0x28,
	0x0a, 0x1c, 0x41, 0x6d, 0x57, 0xd1, 0xa6, 0x49, 0x5a, 0x4e, 0x48, 0x5a, 0xea, 0xc4, 0xeb, 0xff,
	0x61, 0x00, 0x79, 0x3e, 0x66, 0x5e, 0xc1, 0xcb, 0x4f, 0x54, 0x43, 0xee, 0x02, 0x0c, 0x84, 0x6b,
	0x3b, 0xa3, 0x70, 0xcc, 0x04, 0xba, 0x6a, 0x58, 0xcd, 0x81, 0x70, 0xf7, 0x10, 0x20, 0xf7, 0xa0,
	0x15, 0xc5, 0x61, 0x44, 0x63, 0x31, 0x91, 0x6a, 0xa4, 0xab, 0x65, 0x0b, 0x12, 0xe8, 0xc4, 0x23,
	0xf7, 0xa1, 0xed, 0x70, 0x4e, 0x45, 0xa2, 0xa1, 0x82, 0x1a, 0x5a, 0x88, 0x69, 0x1d, 0x33, 0x01,
	0xab, 0x7e, 0x5a, 0xc0, 0x3e, 0x87, 0x4e, 0xce, 0x51, 0x1d, 0xb0, 0xbb, 0x00, 0x33, 0x0e, 0x36,
	0xdd, 0x34, 0x3e, 0xff, 0x82, 0xf6, 0x31, 0x0d, 0x82, 0x30, 0x09, 0xcc, 0x0a, 0x54, 0xb9, 0x33,
	0x19, 0xfa, 0x9a, 0x53, 0x7d, 0xf4, 0x1f, 0xc0, 0x82, 0xe6, 0xd2, 0x5a, 0x09, 0x54, 0x62, 0xca,
	0xa3, 0xa4, 0xd4, 0xe4, 0xef, 0xfe, 0x9f, 0x06, 0x74, 0x4e, 0x7d, 0x2e, 0xb4, 0x05, 0x3c, 0x51,
	0x79, 0x0f, 0x5a, 0x8e, 0x2b, 0xfc, 0x77, 0xd4, 0x0e, 0x59, 0x30, 0x41, 0x91, 0x86, 0x05, 0x0a,
	0x7a, 0xc5, 0x82, 0x09, 0x79, 0x00, 0x0b, 0x3e, 0xcb, 0xb2, 0xa8, 0x52, 0x6a, 0x27, 0x20, 0x32,
	0xc9, 0x10, 0x8f, 0x07, 0x81, 0xef, 0x2a, 0x96, 0xb2, 0xd2, 0xa2, 0x20, 0x64, 0xb8, 0x0f, 0x6d,
	0x5d, 0x7b, 0x8a, 0xa3, 0x82, 0x1c, 0x2d, 0x8d, 0x21, 0x0b, 0x81, 0x8a, 0x6c, 0x50, 0x8c, 0x6c,
	0xdb, 0xc2, 0xdf, 0x64, 0x03, 0x9a, 0x91, 0x73, 0x49, 0x6d, 0xee, 0x7f, 0xa0, 0x66, 0x6d, 0xcb,
	0xd8, 0xae, 0x5a, 0x0d, 0x09, 0x9c, 0xfb, 0x1f, 0x30, 0x78, 0x48, 0xf4, 0x99, 0x47, 0xaf, 0xcc,
	0x3a, 0x52, 0x91, 0xfd, 0x44, 0x02, 0xfd, 0x1f, 0x6b, 0x50, 0xd7, 0xde, 0x92, 0x2e, 0xd4, 0x94,
	0xb5, 0xda, 0x41, 0xfd, 0x25, 0x9d, 0x8b, 0xe9, 0x28, 0x14, 0x49, 0x47, 0xe9, 0xd1, 0xd0, 0x56,
	0xa0, 0x6a, 0x26, 0xc9, 0x94, 0x24, 0x29, 0x0a, 0x7d, 0x26, 0xd0, 0xbd, 0xa6, 0xd5, 0xd6, 0xe0,
	0x99, 0xc4, 0xc8, 0x1a, 0xd4, 0xe5, 0xb7, 0x4c, 0x63, 0x05, 0xc9, 0x35, 0xf9, 0x79, 0xe2, 0x91,
	0x1e, 0x34, 0x5c, 0x27, 0x72, 0x5c, 0x5f, 0x4c, 0xd0, 0xb5, 0xb2, 0x95, 0x7e, 0x4b, 0xcd, 0x41,
	0xe8, 0x3a, 0x81, 0x3d, 0x70, 0x02, 0x87, 0xb9, 0xca, 0xc5, 0xb2, 0xd5, 0x46, 0x70, 0x5f, 0x61,
	0xe4, 0xdf, 0xb0, 0xa8, 0x6d, 0x4c, 0xb8, 0xea, 0xc8, 0xa5, 0x2d, 0x4f, 0xd8, 0x64, 0x29, 0x85,
	0xa3, 0x91, 0x2f, 0xec, 0x0b, 0x4a, 0xcd, 0x06, 0xb2, 0x34, 0x15, 0xf2, 0x9c, 0xa2, 0xa7, 0x9a,
	0xfc, 0x9e, 0xfa, 0x97, 0x43, 0x61, 0x36, 0xd5, 0x51, 0x0a, 0xfc, 0x16, 0x31, 0xb2, 0x09, 0x70,
	0x41, 0xe5, 0x70, 0x8d, 0xed, 0xb7, 0xef, 0x4d, 0x50, 0xd6, 0x5e, 0x50, 0x7a, 0x46, 0xe3, 0x17,
	0xef, 0xc9, 0x23, 0x58, 0x1e, 0x33, 0x4e, 0x85, 0x08, 0xa8, 0x97, 0xda, 0xd2, 0x42, 0xa6, 0x3b,
	0x29, 0x21, 0x31, 0x47, 0xf6, 0x70, 0x28, 0x9c, 0xc0, 0xe6, 0x8e, 0x08, 0xf9, 0xd0, 0xe7, 0x36,
	0xa7, 0x4c, 0x98, 0x6d, 0x64, 0x5f, 0x46, 0xd2, 0xb9, 0xa6, 0x9c, 0x53, 0x26, 0xc8, 0x13, 0x58,
	0x2b, 0xf0, 0xc7, 0xd4, 0xa5, 0xfe, 0x3b, 0xea, 0x99, 0x0b, 0x28, 0xb3, 0x9a, 0x93, 0xb1, 0x34,
	0x51, 0x56, 0x1e, 0x1b, 0x8f, 0xec, 0x71, 0xe4, 0x39, 0x82, 0x72, 0x73, 0x71, 0xcb, 0xd8, 0xae,
	0x58, 0xc0, 0xc6, 0xa3, 0x37, 0x0a, 0xc9, 0x0e, 0xc1, 0xe5, 0xfc, 0x10, 0xdc, 0x84, 0xa6, 0xcf,
	0x7c, 0xe1, 0x3b, 0x22, 0x8c, 0x4d, 0x82, 0xb4, 0x29, 0x40, 0x1e, 0xc2, 0x32, 0x26, 0x94, 0x0b,
	0x47, 0x8c, 0xb9, 0x7d, 0x11, 0x38, 0x97, 0xdc, 0xec, 0x60, 0x6a, 0x97, 0x24, 0xe1, 0x1c, 0xf1,
	0xe7, 0x12, 0x96, 0x39, 0x0e, 0xfc, 0x0b, 0x2a, 0xfc, 0x11, 0x35, 0xd7, 0x54, 0xd4, 0x92, 0x6f,
	0x59, 0x7a, 0xe3, 0x08, 0x29, 0x26, 0x52, 0xf4, 0x17, 0x26, 0x24, 0x08, 0x39, 0xb5, 0xe5, 0x4d,
	0x40, 0x39, 0x37, 0xd7, 0x75, 0x55, 0x49, 0x70, 0x4f, 0x61, 0xe4, 0x3f, 0xb0, 0x14, 0x8d, 0xf9,
	0x50, 0x0f, 0x26, 0x19, 0x1b, 0x73, 0x03, 0x3d, 0x5c, 0x90, 0xb0, 0x9a, 0x4d, 0xe7, 0xce, 0xcc,
	0x88, 0xdb, 0x2c, 0x8e, 0xb8, 0xfe, 0x6b, 0xe8, 0x9e, 0x51, 0xe6, 0xf9, 0xec, 0xb2, 0x38, 0x00,
	0x72, 0x2d, 0x66, 0x5c, 0xdb, 0x62, 0xa5, 0x62, 0x8b, 0xed, 0xc3, 0x4a, 0x7e, 0xa6, 0xe8, 0x01,
	0xf4, 0x10, 0x1a, 0xba, 0x39, 0xb8, 0x69, 0x6c, 0x95, 0xb7, 0x5b, 0xbb, 0x8b, 0x7a, 0x50, 0x26,
	0x03, 0x30, 0xa5, 0xf7, 0x9f, 0x82, 0x79, 0x2a, 0x13, 0x25, 0x5e, 0xc7, 0x0e, 0xe3, 0xb2, 0x2f,
	0x43, 0x96, 0xd8, 0x76, 0xc3, 0x78, 0xfc, 0xb9, 0x04, 0xad, 0x8c, 0xd4, 0x0d, 0xec, 0x64, 0x1d,
	0x1a, 0x3a, 0x8e, 0x8e, 0xbe, 0x24, 0xea, 0xea, 0x7b, 0x2f, 0x43, 0x1a, 0x60, 0x77, 0xa7, 0xa4,
	0x7d, 0xb2, 0x0a, 0x35, 0xdc, 0x1b, 0x1c, 0xdd, 0xd7, 0x55, 0xf9, 0xb5, 0x97, 0xc2, 0x03, 0x6c,
	0x6a, 0x0d, 0xef, 0xa3, 0x09, 0xe3, 0x38, 0xc6, 0xaa, 0x49, 0x26, 0x56, 0x53, 0x22, 0xb2, 0x5c,
	0xa8, 0x9c, 0x12, 0xe2, 0xca, 0x1e, 0x3a, 0x7c, 0x88, 0x4d, 0xdc, 0xb4, 0x6a, 0xe2, 0xea, 0xd8,
	0xe1, 0x43, 0x4d, 0x10, 0x93, 0x48, 0xb5, 0x6e, 0x55, 0x12, 0x5e, 0x4f, 0x22, 0x4a, 0xda, 0x60,
	0x0c, 0xb1, 0x57, 0x9b, 0x96, 0x31, 0x94, 0x5f, 0x31, 0xf6, 0x65, 0xd3, 0x32, 0x62, 0x9c, 0xdd,
	0xca, 0xea, 0xa1, 0x08, 0x5c, 0x6c, 0x45, 0xc3, 0x02, 0x05, 0x1d, 0x8b, 0xc0, 0xed, 0x73, 0xe8,
	0x1e, 0xd1, 0x6c, 0x60, 0xf9, 0xed, 0x22, 0x9b, 0x2f, 0x8a, 0xd2, 0xb5, 0x45, 0x51, 0x2e, 0x16,
	0xc5, 0x2f, 0x06, 0x90, 0xcc, 0x91, 0x87, 0x54, 0x38, 0x7e, 0xc0, 0xc9, 0x13, 0x68, 0x8b, 0x8c,
	0x21, 0xba, 0x2e, 0x88, 0xae, 0x8b, 0x6c, 0xf2, 0x73, 0x7c, 0xd2, 0x49, 0x35, 0x18, 0xdc, 0xf4,
	0x76, 0xaf, 0x5a, 0x80, 0xd0, 0x01, 0x5e, 0xcd, 0x39, 0x5b, 0xcb, 0xd7, 0xda, 0x5a, 0x29, 0xda,
	0xba, 0x06, 0xab, 0xba, 0x22, 0xf5, 0xdc, 0xd2, 0xf1, 0xe9, 0xff, 0x5e, 0x82, 0x6e, 0x91, 0xa2,
	0x8b, 0x7b, 0x66, 0x68, 0x1b, 0x18, 0xf7, 0x9b, 0x86, 0xb6, 0xaa, 0xb8, 0xc2, 0xd0, 0x7e, 0x02,
	0x6b, 0xd3, 0x91, 0x9a, 0xd7, 0xaa, 0xca, 0x70, 0x35, 0x25, 0x9f, 0x66, 0xd5, 0x7f, 0x01, 0xe6,
	0x54, 0xae, 0x70, 0x90, 0xda, 0x5e, 0xba, 0x29, 0xdd, 0xca, 0x9d, 0xf8, 0x25, 0xf4, 0x22, 0x35,
	0x08, 0xec, 0x30, 0xa2, 0xac, 0x70, 0x68, 0x15, 0x65, 0xd7, 0x34, 0x87, 0x5c, 0xf1, 0x72, 0xc7,
	0x7e, 0x05, 0x1b, 0x39, 0xe1, 0xc2, 0xc9, 0x35, 0x94, 0x36, 0x33, 0xd2, 0xb9, 0xb3, 0xe5, 0x12,
	0x74, 0x20, 0xa7, 0x5b, 0x61, 0xdd, 0xbb, 0xa1, 0xcb, 0x7f, 0x33, 0x60, 0x25, 0x2f, 0x76, 0xab,
	0xe5, 0x69, 0x36, 0x4f, 0xa5, 0x5b, 0xe5, 0xa9, 0x3c, 0x2f, 0x4f, 0xf7, 0xa1, 0xad, 0x8a, 0x30,
	0xbf, 0x21, 0x22, 0x36, 0x7f, 0xcb, 0xac, 0xce, 0x8c, 0xe0, 0xff, 0xc3, 0x92, 0xf4, 0x00, 0xb7,
	0xc3, 0xdb, 0x79, 0xfe, 0x97, 0x01, 0x2d, 0xed, 0xf4, 0x33, 0xef, 0xf2, 0x46, 0x87, 0x8b, 0x46,
	0x96, 0x6e, 0x34, 0x72, 0x76, 0x15, 0xfe, 0x2f, 0x2c, 0x25, 0x47, 0x24, 0xf7, 0x92, 0x1a, 0x7b,
	0x8b, 0x1a, 0x4e, 0x6e, 0xa6, 0x0d, 0x68, 0xca, 0xf7, 0xc6, 0x67, 0x72, 0x71, 0xd2, 0x23, 0xb0,
	0x81, 0xc0, 0xd9, 0x78, 0x90, 0x10, 0x77, 0x91, 0x58, 0x9b, 0x12, 0x77, 0x25, 0x31, 0x3f, 0x22,
	0xeb, 0x7a, 0x51, 0x49, 0x46, 0x64, 0xff, 0x1c, 0x56, 0x31, 0xdb, 0xde, 0x3f, 0x79, 0x51, 0x1d,
	0x42, 0xb7, 0xa8, 0xf4, 0xd3, 0xaf, 0xaa, 0xdd, 0x5f, 0xeb, 0xd0, 0x3c, 0x95, 0x8b, 0x12, 0x93,
	0xaf, 0xab, 0x5d, 0xa8, 0xe2, 0xda, 0x4d, 0x3a, 0x5a, 0x20, 0xbb, 0xaa, 0xf7, 0x56, 0xf2, 0xa0,
	0x3e, 0xed, 0x10, 0x5a, 0x99, 0x47, 0x23, 0x59, 0x4f, 0x8e, 0x9a, 0x79, 0x2e, 0xf6, 0x7a, 0xf3,
	0x48, 0x5a, 0xcb, 0x4b, 0x58, 0xcc, 0x3f, 0x1b, 0xc9, 0xa6, 0xe6, 0x9e, 0xfb, 0xf4, 0xec, 0xdd,
	0xfd, 0x08, 0x75, 0x6a, 0x54, 0xe6, 0x31, 0x97, 0x1a, 0x35, 0xfb, 0xfc, 0x4c, 0x8d, 0x9a, 0xf7,
	0xf6, 0x3b, 0x82, 0x76, 0xb6, 0x4b, 0x49, 0xea, 0xc0, 0x6c, 0xc7, 0xf7, 0x36, 0xe6, 0xd2, 0xa6,
	0xde, 0xe5, 0x73, 0x95, 0x7a, 0x37, 0xb7, 0x2e, 0x52, 0xef, 0x3e, 0x92, 0xe0, 0x43, 0x68, 0x65,
	0x5e, 0x5e, 0xa9, 0x77, 0xb3, 0xcf, 0xce, 0xd4, 0xbb, 0x79, 0x0f, 0xb5, 0x23, 0x68, 0x67, 0x37,
	0x9d, 0xd4, 0xbb, 0x39, 0x4f, 0xaa, 0xd4, 0xbb, 0xb9, 0xab, 0xd1, 0x53, 0x68, 0x1d, 0x51, 0x91,
	0x0c, 0x02, 0xd2, 0xcd, 0x14, 0x5b, 0x66, 0x32, 0xf4, 0x48, 0xbe, 0x08, 0xb1, 0xfd, 0x5f, 0xc2,
	0x52, 0x61, 0x87, 0x23, 0x89, 0xef, 0xf3, 0x77, 0xbb, 0xeb, 0x2d, 0x39, 0x86, 0xe5, 0x99, 0xc5,
	0x8b, 0xdc, 0x4b, 0x24, 0x3e, 0xb2, 0x92, 0xf5, 0xe6, 0x5c, 0xd8, 0xe4, 0x05, 0x2c, 0x15, 0xd6,
	0x8c, 0xd4, 0xb0, 0xf9, 0xeb, 0x47, 0x6f, 0x7d, 0x56, 0x4b, 0xb2, 0x27, 0xc8, 0xf4, 0xe7, 0x2e,
	0xde, 0x69, 0xfa, 0xe7, 0xdd, 0xd4, 0xd3, 0xf4, 0xcf, 0xbd, 0xad, 0xf7, 0x2b, 0xdf, 0x95, 0xa2,
	0xc1, 0xa0, 0x86, 0xff, 0x31, 0x3d, 0xfe, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x13, 0x13, 0x31, 0xda,
	0x70, 0x12, 0x00, 0x00,
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// LightningClient is the client API for Lightning service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type LightningClient interface {
	// obdcli: `hello`
	//hello is a `say hi` gRPC.
	Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error)
	ConnectPeer(ctx context.Context, in *ConnectPeerRequest, opts ...grpc.CallOption) (*ConnectPeerResponse, error)
	DisconnectPeer(ctx context.Context, in *DisconnectPeerRequest, opts ...grpc.CallOption) (*DisconnectPeerResponse, error)
	OpenChannel(ctx context.Context, in *OpenChannelRequest, opts ...grpc.CallOption) (*OpenChannelResponse, error)
	CloseChannel(ctx context.Context, in *CloseChannelRequest, opts ...grpc.CallOption) (*CloseChannelResponse, error)
	ClosedChannels(ctx context.Context, in *ClosedChannelsRequest, opts ...grpc.CallOption) (*ClosedChannelsResponse, error)
	FundChannel(ctx context.Context, in *FundChannelRequest, opts ...grpc.CallOption) (*FundChannelResponse, error)
	ListChannels(ctx context.Context, in *ListChannelsRequest, opts ...grpc.CallOption) (*ListChannelsResponse, error)
	GetChanInfo(ctx context.Context, in *ChanInfoRequest, opts ...grpc.CallOption) (*ChannelEdge, error)
	PendingChannels(ctx context.Context, in *PendingChannelsRequest, opts ...grpc.CallOption) (*ListChannelsResponse, error)
	LatestTransaction(ctx context.Context, in *LatestTransactionRequest, opts ...grpc.CallOption) (*Transaction, error)
	GetTransactions(ctx context.Context, in *GetTransactionsRequest, opts ...grpc.CallOption) (*TransactionDetails, error)
	//*
	//ChannelBalance returns a report on the total funds across all open channels,
	//categorized in
	//local/remote,
	//pending local/remote
	//and unsettled local/remote balances.
	ChannelBalance(ctx context.Context, in *ChannelBalanceRequest, opts ...grpc.CallOption) (*ChannelBalanceResponse, error)
}

type lightningClient struct {
	cc grpc.ClientConnInterface
}

func NewLightningClient(cc grpc.ClientConnInterface) LightningClient {
	return &lightningClient{cc}
}

func (c *lightningClient) Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) {
	out := new(HelloResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/Hello", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) ConnectPeer(ctx context.Context, in *ConnectPeerRequest, opts ...grpc.CallOption) (*ConnectPeerResponse, error) {
	out := new(ConnectPeerResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/ConnectPeer", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) DisconnectPeer(ctx context.Context, in *DisconnectPeerRequest, opts ...grpc.CallOption) (*DisconnectPeerResponse, error) {
	out := new(DisconnectPeerResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/DisconnectPeer", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) OpenChannel(ctx context.Context, in *OpenChannelRequest, opts ...grpc.CallOption) (*OpenChannelResponse, error) {
	out := new(OpenChannelResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/OpenChannel", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) CloseChannel(ctx context.Context, in *CloseChannelRequest, opts ...grpc.CallOption) (*CloseChannelResponse, error) {
	out := new(CloseChannelResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/CloseChannel", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) ClosedChannels(ctx context.Context, in *ClosedChannelsRequest, opts ...grpc.CallOption) (*ClosedChannelsResponse, error) {
	out := new(ClosedChannelsResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/ClosedChannels", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) FundChannel(ctx context.Context, in *FundChannelRequest, opts ...grpc.CallOption) (*FundChannelResponse, error) {
	out := new(FundChannelResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/FundChannel", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) ListChannels(ctx context.Context, in *ListChannelsRequest, opts ...grpc.CallOption) (*ListChannelsResponse, error) {
	out := new(ListChannelsResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/ListChannels", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) GetChanInfo(ctx context.Context, in *ChanInfoRequest, opts ...grpc.CallOption) (*ChannelEdge, error) {
	out := new(ChannelEdge)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/GetChanInfo", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) PendingChannels(ctx context.Context, in *PendingChannelsRequest, opts ...grpc.CallOption) (*ListChannelsResponse, error) {
	out := new(ListChannelsResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/PendingChannels", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) LatestTransaction(ctx context.Context, in *LatestTransactionRequest, opts ...grpc.CallOption) (*Transaction, error) {
	out := new(Transaction)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/LatestTransaction", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) GetTransactions(ctx context.Context, in *GetTransactionsRequest, opts ...grpc.CallOption) (*TransactionDetails, error) {
	out := new(TransactionDetails)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/GetTransactions", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *lightningClient) ChannelBalance(ctx context.Context, in *ChannelBalanceRequest, opts ...grpc.CallOption) (*ChannelBalanceResponse, error) {
	out := new(ChannelBalanceResponse)
	err := c.cc.Invoke(ctx, "/proxy.Lightning/ChannelBalance", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// LightningServer is the server API for Lightning service.
type LightningServer interface {
	// obdcli: `hello`
	//hello is a `say hi` gRPC.
	Hello(context.Context, *HelloRequest) (*HelloResponse, error)
	ConnectPeer(context.Context, *ConnectPeerRequest) (*ConnectPeerResponse, error)
	DisconnectPeer(context.Context, *DisconnectPeerRequest) (*DisconnectPeerResponse, error)
	OpenChannel(context.Context, *OpenChannelRequest) (*OpenChannelResponse, error)
	CloseChannel(context.Context, *CloseChannelRequest) (*CloseChannelResponse, error)
	ClosedChannels(context.Context, *ClosedChannelsRequest) (*ClosedChannelsResponse, error)
	FundChannel(context.Context, *FundChannelRequest) (*FundChannelResponse, error)
	ListChannels(context.Context, *ListChannelsRequest) (*ListChannelsResponse, error)
	GetChanInfo(context.Context, *ChanInfoRequest) (*ChannelEdge, error)
	PendingChannels(context.Context, *PendingChannelsRequest) (*ListChannelsResponse, error)
	LatestTransaction(context.Context, *LatestTransactionRequest) (*Transaction, error)
	GetTransactions(context.Context, *GetTransactionsRequest) (*TransactionDetails, error)
	//*
	//ChannelBalance returns a report on the total funds across all open channels,
	//categorized in
	//local/remote,
	//pending local/remote
	//and unsettled local/remote balances.
	ChannelBalance(context.Context, *ChannelBalanceRequest) (*ChannelBalanceResponse, error)
}

// UnimplementedLightningServer can be embedded to have forward compatible implementations.
type UnimplementedLightningServer struct {
}

func (*UnimplementedLightningServer) Hello(ctx context.Context, req *HelloRequest) (*HelloResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method Hello not implemented")
}
func (*UnimplementedLightningServer) ConnectPeer(ctx context.Context, req *ConnectPeerRequest) (*ConnectPeerResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ConnectPeer not implemented")
}
func (*UnimplementedLightningServer) DisconnectPeer(ctx context.Context, req *DisconnectPeerRequest) (*DisconnectPeerResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method DisconnectPeer not implemented")
}
func (*UnimplementedLightningServer) OpenChannel(ctx context.Context, req *OpenChannelRequest) (*OpenChannelResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method OpenChannel not implemented")
}
func (*UnimplementedLightningServer) CloseChannel(ctx context.Context, req *CloseChannelRequest) (*CloseChannelResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method CloseChannel not implemented")
}
func (*UnimplementedLightningServer) ClosedChannels(ctx context.Context, req *ClosedChannelsRequest) (*ClosedChannelsResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ClosedChannels not implemented")
}
func (*UnimplementedLightningServer) FundChannel(ctx context.Context, req *FundChannelRequest) (*FundChannelResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method FundChannel not implemented")
}
func (*UnimplementedLightningServer) ListChannels(ctx context.Context, req *ListChannelsRequest) (*ListChannelsResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ListChannels not implemented")
}
func (*UnimplementedLightningServer) GetChanInfo(ctx context.Context, req *ChanInfoRequest) (*ChannelEdge, error) {
	return nil, status.Errorf(codes.Unimplemented, "method GetChanInfo not implemented")
}
func (*UnimplementedLightningServer) PendingChannels(ctx context.Context, req *PendingChannelsRequest) (*ListChannelsResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method PendingChannels not implemented")
}
func (*UnimplementedLightningServer) LatestTransaction(ctx context.Context, req *LatestTransactionRequest) (*Transaction, error) {
	return nil, status.Errorf(codes.Unimplemented, "method LatestTransaction not implemented")
}
func (*UnimplementedLightningServer) GetTransactions(ctx context.Context, req *GetTransactionsRequest) (*TransactionDetails, error) {
	return nil, status.Errorf(codes.Unimplemented, "method GetTransactions not implemented")
}
func (*UnimplementedLightningServer) ChannelBalance(ctx context.Context, req *ChannelBalanceRequest) (*ChannelBalanceResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ChannelBalance not implemented")
}

func RegisterLightningServer(s *grpc.Server, srv LightningServer) {
	s.RegisterService(&_Lightning_serviceDesc, srv)
}

func _Lightning_Hello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(HelloRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).Hello(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/Hello",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).Hello(ctx, req.(*HelloRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_ConnectPeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ConnectPeerRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).ConnectPeer(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/ConnectPeer",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).ConnectPeer(ctx, req.(*ConnectPeerRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_DisconnectPeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(DisconnectPeerRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).DisconnectPeer(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/DisconnectPeer",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).DisconnectPeer(ctx, req.(*DisconnectPeerRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_OpenChannel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(OpenChannelRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).OpenChannel(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/OpenChannel",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).OpenChannel(ctx, req.(*OpenChannelRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_CloseChannel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(CloseChannelRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).CloseChannel(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/CloseChannel",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).CloseChannel(ctx, req.(*CloseChannelRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_ClosedChannels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ClosedChannelsRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).ClosedChannels(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/ClosedChannels",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).ClosedChannels(ctx, req.(*ClosedChannelsRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_FundChannel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(FundChannelRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).FundChannel(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/FundChannel",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).FundChannel(ctx, req.(*FundChannelRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_ListChannels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ListChannelsRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).ListChannels(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/ListChannels",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).ListChannels(ctx, req.(*ListChannelsRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_GetChanInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ChanInfoRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).GetChanInfo(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/GetChanInfo",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).GetChanInfo(ctx, req.(*ChanInfoRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_PendingChannels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(PendingChannelsRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).PendingChannels(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/PendingChannels",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).PendingChannels(ctx, req.(*PendingChannelsRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_LatestTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(LatestTransactionRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).LatestTransaction(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/LatestTransaction",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).LatestTransaction(ctx, req.(*LatestTransactionRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_GetTransactions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(GetTransactionsRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).GetTransactions(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/GetTransactions",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).GetTransactions(ctx, req.(*GetTransactionsRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Lightning_ChannelBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ChannelBalanceRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(LightningServer).ChannelBalance(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Lightning/ChannelBalance",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(LightningServer).ChannelBalance(ctx, req.(*ChannelBalanceRequest))
	}
	return interceptor(ctx, in, info, handler)
}

var _Lightning_serviceDesc = grpc.ServiceDesc{
	ServiceName: "proxy.Lightning",
	HandlerType: (*LightningServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "Hello",
			Handler:    _Lightning_Hello_Handler,
		},
		{
			MethodName: "ConnectPeer",
			Handler:    _Lightning_ConnectPeer_Handler,
		},
		{
			MethodName: "DisconnectPeer",
			Handler:    _Lightning_DisconnectPeer_Handler,
		},
		{
			MethodName: "OpenChannel",
			Handler:    _Lightning_OpenChannel_Handler,
		},
		{
			MethodName: "CloseChannel",
			Handler:    _Lightning_CloseChannel_Handler,
		},
		{
			MethodName: "ClosedChannels",
			Handler:    _Lightning_ClosedChannels_Handler,
		},
		{
			MethodName: "FundChannel",
			Handler:    _Lightning_FundChannel_Handler,
		},
		{
			MethodName: "ListChannels",
			Handler:    _Lightning_ListChannels_Handler,
		},
		{
			MethodName: "GetChanInfo",
			Handler:    _Lightning_GetChanInfo_Handler,
		},
		{
			MethodName: "PendingChannels",
			Handler:    _Lightning_PendingChannels_Handler,
		},
		{
			MethodName: "LatestTransaction",
			Handler:    _Lightning_LatestTransaction_Handler,
		},
		{
			MethodName: "GetTransactions",
			Handler:    _Lightning_GetTransactions_Handler,
		},
		{
			MethodName: "ChannelBalance",
			Handler:    _Lightning_ChannelBalance_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "rpc.proto",
}


<|start_filename|>tool/tool_test.go<|end_filename|>
package tool

import (
	"log"
	"testing"
)

func TestGenerateInitHashCode(t *testing.T) {
	log.Println(GenerateInitHashCode())
}

func TestSignMsgWithMd5(t *testing.T) {
	log.Println(SignMsgWithMd5([]byte("mrt1gppm")))
}


<|start_filename|>service/htlc_tx_query.go<|end_filename|>
package service

import (
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/tool"
	"github.com/tidwall/gjson"
	"sync"
)

type htlcQueryTxManager struct {
	operationFlag sync.Mutex
}

var HtlcQueryTxManager htlcQueryTxManager

func (service *htlcQueryTxManager) ListInvoices(jsonData string, user bean.User) (data map[string]interface{}, err error) {

	indexOffset := gjson.Get(jsonData, "index_offset").Int()
	if indexOffset < 0 {
		indexOffset = 0
	}
	numMaxInvoices := gjson.Get(jsonData, "num_max_invoices").Int()
	if numMaxInvoices < 0 {
		numMaxInvoices = 1
	}
	reversed := gjson.Get(jsonData, "reversed").Bool()

	var list []dao.InvoiceInfo
	if reversed {
		err = user.Db.Select().Reverse().Skip(int(indexOffset)).Limit(int(numMaxInvoices)).Find(&list)
	} else {
		err = user.Db.Select().Skip(int(indexOffset)).Limit(int(numMaxInvoices)).Find(&list)
	}
	if len(list) < int(numMaxInvoices) {
		numMaxInvoices = int64(len(list))
	}
	data = make(map[string]interface{})
	data["invoices"] = list
	data["first_index_offset"] = indexOffset
	data["last_index_offset"] = numMaxInvoices + indexOffset
	return data, err
}

func (service *htlcQueryTxManager) GetLatestHT1aOrHE1b(msgData string, user bean.User) (data interface{}, err error) {
	if tool.CheckIsString(&msgData) == false {
		return nil, errors.New(enum.Tips_common_empty + "msg data")
	}
	channelId := gjson.Get(msgData, "channel_id").Str
	if tool.CheckIsString(&channelId) == false {
		return nil, errors.New(enum.Tips_common_empty + "channel_id")
	}
	tx, _ := user.Db.Begin(true)
	defer tx.Rollback()

	commitmentTxInfo, err := getLatestCommitmentTxUseDbTx(tx, channelId, user.PeerId)
	if err != nil {
		return nil, errors.New(enum.Tips_channel_notFoundLatestCommitmentTx)
	}
	ht1aOrHe1b := dao.HTLCTimeoutTxForAAndExecutionForB{}
	_ = tx.Select(q.Eq("ChannelId", channelId), q.Eq("CommitmentTxId", commitmentTxInfo.Id)).First(&ht1aOrHe1b)
	if ht1aOrHe1b.Id == 0 {
		return nil, errors.New(enum.Tips_common_notFound)
	}
	_ = tx.Commit()
	return ht1aOrHe1b, nil
}

func (service *htlcQueryTxManager) GetHT1aOrHE1bBySomeCommitmentId(msgData string, user bean.User) (data interface{}, err error) {
	if tool.CheckIsString(&msgData) == false {
		return nil, errors.New(enum.Tips_common_empty + "msg data")
	}

	channelId := gjson.Get(msgData, "channel_id").Str
	if tool.CheckIsString(&channelId) == false {
		return nil, errors.New(enum.Tips_common_empty + "channel_id")
	}
	commitmentTxId := gjson.Get(msgData, "commitment_tx_id").Int()
	if commitmentTxId < 1 {
		return nil, errors.New(enum.Tips_common_wrong + "commitment_tx_id")
	}
	tx, _ := user.Db.Begin(true)
	defer tx.Rollback()
	commitmentTransaction := dao.CommitmentTransaction{}
	_ = tx.Select(q.Eq("ChannelId", channelId), q.Eq("Id", commitmentTxId)).First(&commitmentTransaction)
	if commitmentTransaction.Id == 0 {
		return nil, errors.New("commitmentTransaction " + enum.Tips_common_notFound)
	}

	ht1aOrHe1b := dao.HTLCTimeoutTxForAAndExecutionForB{}
	_ = tx.Select(q.Eq("ChannelId", channelId), q.Eq("CommitmentTxId", commitmentTransaction.Id)).First(&ht1aOrHe1b)
	if ht1aOrHe1b.Id == 0 {
		return nil, errors.New(enum.Tips_common_notFound)
	}
	_ = tx.Commit()
	return ht1aOrHe1b, nil
}


<|start_filename|>admin/htlc_close.go<|end_filename|>
package admin

import (
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/service"
)

func HtlcRequestCloseHtlc(c3xData interface{}, user *bean.User) (reqData *bean.HtlcCloseRequestCurrTx, err error) {
	c3x := c3xData.(*dao.CommitmentTransaction)

	reqData = &bean.HtlcCloseRequestCurrTx{}
	reqData.ChannelId = c3x.ChannelId

	walletInfo, _ := service.HDWalletService.GetAddressByIndex(user, uint32(c3x.RSMCTempAddressIndex))
	reqData.LastRsmcTempAddressPrivateKey = walletInfo.Wif

	walletInfo, _ = service.HDWalletService.GetAddressByIndex(user, uint32(c3x.HTLCTempAddressIndex))
	reqData.LastHtlcTempAddressPrivateKey = walletInfo.Wif

	htTx := &dao.HTLCTimeoutTxForAAndExecutionForB{}
	user.Db.Select(q.Eq("ChannelId", c3x.ChannelId), q.Eq("CommitmentTxId", c3x.Id)).First(htTx)
	if htTx.Id > 0 {
		walletInfo, _ = service.HDWalletService.GetAddressByIndex(user, uint32(htTx.RSMCTempAddressIndex))
		reqData.LastHtlcTempAddressForHtnxPrivateKey = walletInfo.Wif
	}

	walletInfo, _ = service.HDWalletService.CreateNewAddress(user)
	reqData.CurrTempAddressIndex = walletInfo.Index
	reqData.CurrTempAddressPubKey = walletInfo.PubKey
	return reqData, nil
}

func HtlcCloseAliceSignedCxa(hexData interface{}, user *bean.User) (signedData *bean.AliceSignedRsmcDataForC4a, err error) {
	needSignData := hexData.(bean.NeedAliceSignRsmcDataForC4a)
	signedData = &bean.AliceSignedRsmcDataForC4a{ChannelId: needSignData.ChannelId}

	channelWalletInfo, _ := getChannelWalletInfo(needSignData.ChannelId, user)
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C4aRsmcRawData.Hex, convertBean(needSignData.C4aRsmcRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.RsmcPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C4aCounterpartyRawData.Hex, convertBean(needSignData.C4aCounterpartyRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.CounterpartyPartialSignedHex = hex

	return signedData, nil
}

func HtlcCloseBobSignCloseHtlcRequest(hexData interface{}, user *bean.User) (signedData *bean.HtlcBobSignCloseCurrTx, err error) {
	needSignData := hexData.(*bean.AliceRequestCloseHtlcCurrTxOfP2pToBobClient)
	signedData = &bean.HtlcBobSignCloseCurrTx{MsgHash: needSignData.MsgHash}

	latestCommitmentTx := getCurrCommitmentTx(needSignData.ChannelId, *user)
	htTx := &dao.HTLCTimeoutTxForAAndExecutionForB{}
	user.Db.Select(q.Eq("ChannelId", needSignData.ChannelId), q.Eq("CommitmentTxId", latestCommitmentTx.Id)).First(htTx)
	if htTx.Id == 0 {
		return nil, errors.New("not found the htTx")
	}
	wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(latestCommitmentTx.RSMCTempAddressIndex))
	signedData.LastRsmcTempAddressPrivateKey = wallet.Wif
	wallet, _ = service.HDWalletService.GetAddressByIndex(user, uint32(latestCommitmentTx.HTLCTempAddressIndex))
	signedData.LastHtlcTempAddressPrivateKey = wallet.Wif
	wallet, _ = service.HDWalletService.GetAddressByIndex(user, uint32(htTx.RSMCTempAddressIndex))
	signedData.LastHtlcTempAddressForHtnxPrivateKey = wallet.Wif

	wallet, _ = service.HDWalletService.CreateNewAddress(user)
	signedData.CurrTempAddressIndex = wallet.Index
	signedData.CurrTempAddressPubKey = wallet.PubKey

	channelWalletInfo, _ := getChannelWalletInfo(needSignData.ChannelId, user)
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C4aRsmcPartialSignedData.Hex, convertBean(needSignData.C4aRsmcPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4aRsmcCompleteSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C4aCounterpartyPartialSignedData.Hex, convertBean(needSignData.C4aCounterpartyPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4aCounterpartyCompleteSignedHex = hex

	return signedData, nil
}

func HtlcCloseBobSignedCxb(hexData interface{}, user *bean.User) (signedData *bean.BobSignedRsmcDataForC4b, err error) {
	needSignData := hexData.(bean.NeedBobSignRawDataForC4b)
	signedData = &bean.BobSignedRsmcDataForC4b{ChannelId: needSignData.ChannelId}
	signedData.C4aBrId = int64(needSignData.C4aBrRawData.BrId)

	channelWalletInfo, _ := getChannelWalletInfo(needSignData.ChannelId, user)
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C4bRsmcRawData.Hex, convertBean(needSignData.C4bRsmcRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4bRsmcPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C4bCounterpartyRawData.Hex, convertBean(needSignData.C4bCounterpartyRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4bCounterpartyPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C4aRdRawData.Hex, convertBean(needSignData.C4aRdRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4aRdPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C4aBrRawData.Hex, convertBean(needSignData.C4aBrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4aBrPartialSignedHex = hex

	return signedData, nil
}

func HtlcCloseAliceSignedCxb(hexData interface{}, user *bean.User) (signedData *bean.AliceSignedRsmcTxForC4b, err error) {
	needSignData := hexData.(bean.NeedAliceSignRsmcTxForC4b)
	signedData = &bean.AliceSignedRsmcTxForC4b{ChannelId: needSignData.ChannelId}

	currCommitmentTx := getCurrCommitmentTx(needSignData.ChannelId, *user)
	wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(currCommitmentTx.RSMCTempAddressIndex))
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C4aRdPartialSignedData.Hex, convertBean(needSignData.C4aRdPartialSignedData.Inputs), wallet.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4aRdCompleteSignedHex = hex

	channelWalletInfo, _ := getChannelWalletInfo(needSignData.ChannelId, user)
	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C4bRsmcPartialSignedData.Hex, convertBean(needSignData.C4bRsmcPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4bRsmcCompleteSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C4bCounterpartyPartialSignedData.Hex, convertBean(needSignData.C4bCounterpartyPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4bCounterpartyCompleteSignedHex = hex

	return signedData, nil
}

func HtlcCloseAliceSignedCxbBubTx(hexData interface{}, user *bean.User) (signedData *bean.AliceSignedRdTxForC4b, err error) {
	needSignData := hexData.(bean.NeedAliceSignRdTxForC4b)
	signedData = &bean.AliceSignedRdTxForC4b{ChannelId: needSignData.ChannelId}

	channelWalletInfo, _ := getChannelWalletInfo(needSignData.ChannelId, user)
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C4bRdRawData.Hex, convertBean(needSignData.C4bRdRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4bRdPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C4bBrRawData.Hex, convertBean(needSignData.C4bBrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4bBrPartialSignedHex = hex
	signedData.C4bBrId = int64(needSignData.C4bBrRawData.BrId)

	return signedData, nil
}
func HtlcCloseBobSignedCxbSubTx(hexData interface{}, user *bean.User) (signedData *bean.BobSignedRdTxForC4b, err error) {
	needSignData := hexData.(bean.NeedBobSignRdTxForC4b)
	signedData = &bean.BobSignedRdTxForC4b{ChannelId: needSignData.ChannelId}

	currCommitmentTx := getCurrCommitmentTx(needSignData.ChannelId, *user)
	wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(currCommitmentTx.RSMCTempAddressIndex))

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C4bRdPartialSignedData.Hex, convertBean(needSignData.C4bRdPartialSignedData.Inputs), wallet.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C4bRdCompleteSignedHex = hex

	return signedData, nil
}


<|start_filename|>omnicore/rpcpayload_test.go<|end_filename|>
package omnicore

import (
	"fmt"
	"testing"
)

func TestOmni_createpayload_simplesend(t *testing.T) {

	_, payload_hex := Omni_createpayload_simplesend("2", "0.1", true)
	fmt.Println("expect: 00000000000000020000000000989680")

	fmt.Println(payload_hex)

}


<|start_filename|>omnicore/MultiSigAddress.go<|end_filename|>
package omnicore

import (
	"encoding/hex"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/txscript"
	"github.com/btcsuite/btcutil"
)

func CreateMultiSigAddr(addr1_pubkey_str string, addr2_pubkey_str string, defaultNet *chaincfg.Params) (string, string, string) {

	addr1_pubkey_byte_arr, _ := hex.DecodeString(addr1_pubkey_str)
	addr2_pubkey_byte_arr, _ := hex.DecodeString(addr2_pubkey_str)

	address1_pubkey, err := btcutil.NewAddressPubKey(addr1_pubkey_byte_arr, defaultNet)
	if err != nil {
		return "", "", ""
	}
	address2_pubkey, err := btcutil.NewAddressPubKey(addr2_pubkey_byte_arr, defaultNet)
	if err != nil {
		return "", "", ""
	}
	pkScript, err := txscript.MultiSigScript([]*btcutil.AddressPubKey{address1_pubkey, address2_pubkey}, 2)
	if err != nil {
		return "", "", ""
	}
	scriptAddr, _ := btcutil.NewAddressScriptHash(pkScript, defaultNet)
	scriptPkScript, err := txscript.PayToAddrScript(scriptAddr)

	return scriptAddr.EncodeAddress(), hex.EncodeToString(pkScript), hex.EncodeToString(scriptPkScript)

}


<|start_filename|>service/addrtool_mnemonic_test.go<|end_filename|>
package service

import (
	"encoding/json"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcutil/hdkeychain"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/tool"
	"github.com/tyler-smith/go-bip39"
	"log"
	"testing"
)

func Test_Demo3(t *testing.T) {

}
func Test_Demo2(t *testing.T) {
	mnemonic := "coyote antenna senior reward diesel vault into used veteran model throw relief"
	userId := tool.SignMsgWithSha256([]byte(mnemonic))

	changeExtKey, _ := HDWalletService.CreateChangeExtKey(mnemonic)

	user := &bean.User{}
	user.CurrAddrIndex = 0
	user.ChangeExtKey = changeExtKey
	user.Mnemonic = mnemonic
	user.PeerId = userId
	for i := 0; i < 4; i++ {
		wallet, _ := HDWalletService.GetAddressByIndex(user, uint32(i))
		bytes, _ := json.Marshal(wallet)
		log.Println(string(bytes))
	}

}

func Test_Demo1(t *testing.T) {
	mnemonic := "unfold tortoise zoo hand sausage project boring corn test same elevator mansion bargain coffee brick tilt forum purpose hundred embody weapon ripple when narrow"
	seed := bip39.NewSeed(mnemonic, "")
	masterKey, _ := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
	// This gives the path: m/44H
	acc44H, _ := masterKey.Child(hdkeychain.HardenedKeyStart + 44)
	// This gives the path: m/44H/60H
	acc44H60H, _ := acc44H.Child(hdkeychain.HardenedKeyStart + 1)
	// This gives the path: m/44H/60H/0H
	acc44H60H0H, _ := acc44H60H.Child(hdkeychain.HardenedKeyStart + 0)
	// This gives the path: m/44H/60H/0H/0
	acc44H60H0H0, _ := acc44H60H0H.Child(0)
	// This gives the path: m/44H/60H/0H/0/0
	acc44H60H0H00, _ := acc44H60H0H0.Child(0)
	addr, _ := acc44H60H0H00.Address(&chaincfg.TestNet3Params)
	log.Println(addr)
	btcecPrivKey, _ := acc44H60H0H00.ECPrivKey()

	privateKey := btcecPrivKey.ToECDSA()

	log.Println(privateKey)
}


<|start_filename|>service/addrtool_mnemonic.go<|end_filename|>
package service

import (
	"errors"
	"github.com/tyler-smith/go-bip39"
)

func (service *hdWalletManager) Bip39GenMnemonic(size int) (mnemonic string, err error) {
	entropy, err := bip39.NewEntropy(size)
	if err != nil {
		return "", nil
	}
	return bip39.NewMnemonic(entropy)
}

func (service *hdWalletManager) Bip39MnemonicToSeed(mnemonic string, password string) ([]byte, error) {
	if !bip39.IsMnemonicValid(mnemonic) {
		return nil, errors.New("mnemonic not valid")
	}
	return bip39.NewSeed(mnemonic, password), nil
}


<|start_filename|>config/cfg.go<|end_filename|>
package config

import (
	"flag"
	"github.com/mitchellh/go-homedir"
	"log"
	"testing"
	"time"

	"github.com/go-ini/ini"
)

var (
	//Cfg               *ini.File
	configPath   = flag.String("configPath", "config/conf.ini", "Config file path")
	ServerPort   = 60020
	ReadTimeout  = 60 * time.Second
	WriteTimeout = 60 * time.Second

	GrpcServerPort = 50051

	HtlcFeeRate = 0.0001
	HtlcMaxFee  = 0.01

	TrackerHost = "127.0.0.1:60060"

	ChainNodeType = "regtest"
	//P2P
	P2P_hostIp     = "127.0.0.1"
	P2P_port       = 4001
	BootstrapPeers addrList

	Init_node_chain_hash = "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P"

	DataDirectory     = ""
	dataDirectoryName = ".obd"
)

func Init() {
	testing.Init()
	flag.Parse()
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	//Cfg, err := ini.Load("config/conf.ini")
	Cfg, err := ini.Load(*configPath)
	if err != nil {
		log.Println(err)
		return
	}
	section, err := Cfg.GetSection("server")
	if err != nil {
		log.Println(err)
		return
	}
	ServerPort = section.Key("port").MustInt(60020)
	GrpcServerPort = section.Key("grpc_server_port").MustInt(50051)
	ReadTimeout = time.Duration(section.Key("readTimeout").MustInt(60)) * time.Second
	WriteTimeout = time.Duration(section.Key("writeTimeout").MustInt(60)) * time.Second

	specifiedDataDirectory, err := section.GetKey("dataDirectory")
	if err == nil {
		DataDirectory = specifiedDataDirectory.Value()
	} else {
		homeDirectory, err := homedir.Dir()
		if err != nil {
			panic(err.Error())
		}
		DataDirectory = homeDirectory + "/" + dataDirectoryName
	}

	htlcNode, err := Cfg.GetSection("htlc")
	if err != nil {
		log.Println(err)
		return
	}
	HtlcFeeRate = htlcNode.Key("feeRate").MustFloat64(0.0001)
	HtlcMaxFee = htlcNode.Key("maxFee").MustFloat64(0.01)

	p2pNode, err := Cfg.GetSection("p2p")
	if err != nil {
		log.Println(err)
		return
	}
	P2P_hostIp = p2pNode.Key("hostIp").String()
	P2P_port = p2pNode.Key("port").MustInt()

	//tracker
	tracker, err := Cfg.GetSection("tracker")
	if err != nil {
		log.Println(err)
		return
	}
	TrackerHost = tracker.Key("host").MustString("localhost:60060")
}


<|start_filename|>omnicore/VerifySignature.go<|end_filename|>
package omnicore

import (
	"bytes"
	"encoding/hex"
	"fmt"

	"github.com/btcsuite/btcd/txscript"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/wire"
)

func VerifySignature(pubkey_hex string, signature_hex string, scriptSig string, signed_tx_hex string) bool {

	signed_tx := wire.NewMsgTx(wire.TxVersion)

	bytes_arr, _ := hex.DecodeString(signed_tx_hex)

	if err := signed_tx.Deserialize(bytes.NewReader(bytes_arr)); err != nil {
		fmt.Println("VerifySignature(...): error deserializing unsigned tx_hex")
	}
	// Decode hex-encoded serialized public key.
	pubKeyBytes, _ := hex.DecodeString(pubkey_hex)
	pubKey, _ := btcec.ParsePubKey(pubKeyBytes, btcec.S256())

	// Decode hex-encoded serialized signature.
	sig_bytes, _ := hex.DecodeString(signature_hex)
	signature, _ := btcec.ParseSignature(sig_bytes, btcec.S256())

	// Verify the signature for the message using the public key.

	messageHash, error := txscript.CalcSignatureHash([]byte(scriptSig), txscript.SigHashAll, signed_tx, 0)
	//messageHash, error := txscript.CalcSignatureHash([]byte(scriptSig_true.Hex), 1, &tx, 0)
	if error != nil {
		fmt.Println("VerifySignature(...)  can not calculate signature hash.")
		return false
	}

	return signature.Verify(messageHash, pubKey)

}

func VerifySignatureFromTxHex(unsigned_tx_hex string, signed_tx_hex string) bool {
	unsigned_tx := wire.NewMsgTx(wire.TxVersion)

	u_bytes_arr, _ := hex.DecodeString(unsigned_tx_hex)

	if err := unsigned_tx.Deserialize(bytes.NewReader(u_bytes_arr)); err != nil {
		fmt.Println("VerifySignatureFromTxHex(...): error deserializing unsigned tx_hex")
	}

	signed_tx := wire.NewMsgTx(wire.TxVersion)

	bytes_arr, _ := hex.DecodeString(signed_tx_hex)

	if err := signed_tx.Deserialize(bytes.NewReader(bytes_arr)); err != nil {
		fmt.Println("VerifySignatureFromTxHex(...): error deserializing signed tx_hex")
	}

	// Prove that the transaction has been validly signed by executing the
	// script pair.
	flags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures |
		txscript.ScriptStrictMultiSig |
		txscript.ScriptDiscourageUpgradableNops
	vm, err := txscript.NewEngine(unsigned_tx.TxOut[0].PkScript, signed_tx, 0,
		flags, nil, nil, -1)
	if err != nil {
		fmt.Println(err)
		return false
	}
	if err := vm.Execute(); err != nil {
		fmt.Println(err)
		return false
	}

	fmt.Println("Transaction successfully signed")

	return true
}


<|start_filename|>tracker/rpc/btcclient.go<|end_filename|>
package rpc

import (
	"encoding/json"
	"errors"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/tool"
	"github.com/shopspring/decimal"
	"github.com/tidwall/gjson"
	"math"
	"strconv"
)

//https://developer.bitcoin.org/reference/rpc/index.html
func (client *Client) GetBlockChainInfo() (result string, err error) {
	return client.send("getblockchaininfo", nil)
}

//https://developer.bitcoin.org/reference/rpc/estimatesmartfee.html
func (client *Client) EstimateSmartFee(confTarget int) (feeRate float64) {

	result, err := client.send("estimatesmartfee", []interface{}{confTarget})
	if err == nil {
		return gjson.Get(result, "feerate").Float() * 100000
	}
	return 0
}

func (client *Client) GetTransactionById(txid string) (result string, err error) {
	return client.send("gettransaction", []interface{}{txid})
}

func (client *Client) ListReceivedByAddress(address string) (result string, err error) {
	_, _ = client.ValidateAddress(address)
	return client.send("listreceivedbyaddress", []interface{}{0, false, true, address})
}

//https://bitcoin.org/en/developer-reference#testmempoolaccept
func (client *Client) TestMemPoolAccept(signedhex string) (result string, err error) {
	rawtxs := make([]string, 0)
	rawtxs = append(rawtxs, signedhex)
	result, err = client.send("testmempoolaccept", []interface{}{rawtxs})
	return result, err
}

func (client *Client) GetTxOut(txid string, num int) (result string, err error) {
	return client.send("gettxout", []interface{}{txid, num})
}

func (client *Client) GetNewAddress(label string) (address string, err error) {
	return client.send("getnewaddress", []interface{}{label})
}

func (client *Client) ListUnspent(address string) (result string, err error) {
	_, err = client.ValidateAddress(address)
	if err != nil {
		return "", err
	}
	return client.send("listunspent", []interface{}{0, math.MaxInt32, []string{address}})
}
func (client *Client) GetBalanceByAddress(address string) (balance decimal.Decimal, err error) {
	result, err := client.ListUnspent(address)
	balance = decimal.NewFromFloat(0)
	if err != nil {
		return balance, err
	}
	array := gjson.Parse(result).Array()
	for _, item := range array {
		amount := item.Get("amount").Float()
		balance = balance.Add(decimal.NewFromFloat(amount))
	}
	return balance, nil
}

//https://developer.bitcoin.org/reference/rpc/createrawtransaction.html
func (client *Client) CreateRawTransaction(inputs []map[string]interface{}, outputs map[string]interface{}) (result string, err error) {
	return client.send("createrawtransaction", []interface{}{inputs, outputs})
}

//https://developer.bitcoin.org/reference/rpc/signrawtransactionwithkey.html
func (client *Client) SignRawTransactionWithKey(hex string, privkeys []string, prevtxs []map[string]interface{}, sighashtype string) (result string, err error) {
	return client.send("signrawtransactionwithkey", []interface{}{hex, privkeys, prevtxs, sighashtype})
}

func (client *Client) SendRawTransaction(hex string) (result string, err error) {
	return client.send("sendrawtransaction", []interface{}{hex})
}

func (client *Client) OmniDecodeTransaction(hex string) (result string, err error) {
	result, err = client.send("omni_decodetransaction", []interface{}{hex})
	return result, err
}

func (client *Client) OmniDecodeTransactionWithPrevTxs(hex string, prevtxs []bean.TransactionInputItem) (result string, err error) {
	result, err = client.send("omni_decodetransaction", []interface{}{hex, prevtxs})
	return result, err
}

func (client *Client) GetBlockCount() (result int, err error) {
	height, err := client.send("getblockcount", nil)
	if err == nil {
		result, err = strconv.Atoi(height)
	}
	return result, err
}

func (client *Client) GetDifficulty() (result string, err error) {
	return client.send("getdifficulty", nil)
}

func (client *Client) GetMiningInfo() (result string, err error) {
	return client.send("getmininginfo", nil)
}

func (client *Client) GetNetworkInfo() (result string, err error) {
	return client.send("getnetworkinfo", nil)
}

func (client *Client) SignMessageWithPrivKey(privkey string, message string) (result string, err error) {
	return client.send("signmessagewithprivkey", []interface{}{privkey, message})
}

func (client *Client) VerifyMessage(address string, signature string, message string) (result string, err error) {
	_, err = client.ValidateAddress(address)
	if err != nil {
		return "", err
	}
	return client.send("verifymessage", []interface{}{address, signature, message})
}
func (client *Client) DecodeScript(hexString string) (result string, err error) {
	return client.send("decodescript", []interface{}{hexString})
}

func (client *Client) ValidateAddress(address string) (isValid bool, err error) {
	if tool.CheckIsAddress(address) == false {
		return false, errors.New("address not exist")
	}
	_, _ = client.send("importaddress", []interface{}{address, "", false})
	return true, nil
}

func (client *Client) GetAddressInfo(address string) (result string, err error) {
	result, err = client.send("getaddressinfo", []interface{}{address})
	if err != nil {
		return "", err
	}
	return result, nil
}

func (client *Client) ImportPrivKey(privkey string) (result string, err error) {
	return client.send("importprivkey", []interface{}{privkey, "", false})
}

type NeedSignData struct {
	Hex    string                   `json:"hex"`
	Prvkey string                   `json:"prvkey"`
	Inputs []map[string]interface{} `json:"inputs"`
}

func (client *Client) BtcSignRawTransactionFromJson(dataJson string) (signHex string, err error) {
	inputData := &NeedSignData{}
	err = json.Unmarshal([]byte(dataJson), inputData)
	if err != nil {
		return "", err
	}

	signHexObj, err := client.SignRawTransactionWithKey(inputData.Hex, []string{inputData.Prvkey}, inputData.Inputs, "ALL")
	if err != nil {
		return "", err
	}
	signHex = gjson.Get(signHexObj, "hex").String()
	return signHex, nil
}


<|start_filename|>omnicore/CreateRawOmniTransactionOpreturn.go<|end_filename|>
package omnicore

import (
	"bytes"
	"fmt"

	"github.com/btcsuite/btcd/wire"
)

/*
 * Script opcodes, defined in omnicore script/script.h
 */
const (
	// push value
	OP_0 = 0x00
	//OP_FALSE = OP_0
	OP_FALSE     = 0x00
	OP_PUSHDATA1 = 0x4c
	OP_PUSHDATA2 = 0x4d
	OP_PUSHDATA4 = 0x4e
	OP_1NEGATE   = 0x4f
	OP_RESERVED  = 0x50
	OP_1         = 0x51
	OP_TRUE      = 0x51
	OP_2         = 0x52
	OP_3         = 0x53
	OP_4         = 0x54
	OP_5         = 0x55
	OP_6         = 0x56
	OP_7         = 0x57
	OP_8         = 0x58
	OP_9         = 0x59
	OP_10        = 0x5a
	OP_11        = 0x5b
	OP_12        = 0x5c
	OP_13        = 0x5d
	OP_14        = 0x5e
	OP_15        = 0x5f
	OP_16        = 0x60

	// control
	OP_NOP      = 0x61
	OP_VER      = 0x62
	OP_IF       = 0x63
	OP_NOTIF    = 0x64
	OP_VERIF    = 0x65
	OP_VERNOTIF = 0x66
	OP_ELSE     = 0x67
	OP_ENDIF    = 0x68
	OP_VERIFY   = 0x69
	OP_RETURN   = 0x6a

	// stack ops
	OP_TOALTSTACK   = 0x6b
	OP_FROMALTSTACK = 0x6c
	OP_2DROP        = 0x6d
	OP_2DUP         = 0x6e
	OP_3DUP         = 0x6f
	OP_2OVER        = 0x70
	OP_2ROT         = 0x71
	OP_2SWAP        = 0x72
	OP_IFDUP        = 0x73
	OP_DEPTH        = 0x74
	OP_DROP         = 0x75
	OP_DUP          = 0x76
	OP_NIP          = 0x77
	OP_OVER         = 0x78
	OP_PICK         = 0x79
	OP_ROLL         = 0x7a
	OP_ROT          = 0x7b
	OP_SWAP         = 0x7c
	OP_TUCK         = 0x7d

	// splice ops
	OP_CAT    = 0x7e
	OP_SUBSTR = 0x7f
	OP_LEFT   = 0x80
	OP_RIGHT  = 0x81
	OP_SIZE   = 0x82

	// bit logic
	OP_INVERT      = 0x83
	OP_AND         = 0x84
	OP_OR          = 0x85
	OP_XOR         = 0x86
	OP_EQUAL       = 0x87
	OP_EQUALVERIFY = 0x88
	OP_RESERVED1   = 0x89
	OP_RESERVED2   = 0x8a

	// numeric
	OP_1ADD      = 0x8b
	OP_1SUB      = 0x8c
	OP_2MUL      = 0x8d
	OP_2DIV      = 0x8e
	OP_NEGATE    = 0x8f
	OP_ABS       = 0x90
	OP_NOT       = 0x91
	OP_0NOTEQUAL = 0x92

	OP_ADD    = 0x93
	OP_SUB    = 0x94
	OP_MUL    = 0x95
	OP_DIV    = 0x96
	OP_MOD    = 0x97
	OP_LSHIFT = 0x98
	OP_RSHIFT = 0x99

	OP_BOOLAND            = 0x9a
	OP_BOOLOR             = 0x9b
	OP_NUMEQUAL           = 0x9c
	OP_NUMEQUALVERIFY     = 0x9d
	OP_NUMNOTEQUAL        = 0x9e
	OP_LESSTHAN           = 0x9f
	OP_GREATERTHAN        = 0xa0
	OP_LESSTHANOREQUAL    = 0xa1
	OP_GREATERTHANOREQUAL = 0xa2
	OP_MIN                = 0xa3
	OP_MAX                = 0xa4

	OP_WITHIN = 0xa5

	// crypto
	OP_RIPEMD160           = 0xa6
	OP_SHA1                = 0xa7
	OP_SHA256              = 0xa8
	OP_HASH160             = 0xa9
	OP_HASH256             = 0xaa
	OP_CODESEPARATOR       = 0xab
	OP_CHECKSIG            = 0xac
	OP_CHECKSIGVERIFY      = 0xad
	OP_CHECKMULTISIG       = 0xae
	OP_CHECKMULTISIGVERIFY = 0xaf

	// expansion
	OP_NOP1                = 0xb0
	OP_CHECKLOCKTIMEVERIFY = 0xb1
	OP_NOP2                = OP_CHECKLOCKTIMEVERIFY
	OP_CHECKSEQUENCEVERIFY = 0xb2
	OP_NOP3                = OP_CHECKSEQUENCEVERIFY
	OP_NOP4                = 0xb3
	OP_NOP5                = 0xb4
	OP_NOP6                = 0xb5
	OP_NOP7                = 0xb6
	OP_NOP8                = 0xb7
	OP_NOP9                = 0xb8
	OP_NOP10               = 0xb9

	// template matching params
	OP_SMALLINTEGER = 0xfa
	OP_PUBKEYS      = 0xfb
	OP_PUBKEYHASH   = 0xfd
	OP_PUBKEY       = 0xfe

	OP_INVALIDOPCODE = 0xff
)

/**
 * script/standard.h
 * Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
 * +2 for the pushdata opcodes.
 */
const MAX_OP_RETURN_RELAY uint = 83

/*
 * defined in standard.cpp
 */
const nMaxDatacarrierBytes uint = MAX_OP_RETURN_RELAY

/**
 * Embeds a payload in an OP_RETURN output, prefixed with a transaction marker.
 *
 * The request is rejected, if the size of the payload with marker is larger than
 * the allowed data carrier size ("-datacarriersize=n").
 *
 * encoding.cpp bool OmniCore_Encode_ClassC(const std::vector<unsigned char>& vchPayload,
 *	std::vector<std::pair <CScript, int64_t> >& vecOutputs)
 *
 * This is the golang version.
 */
func OmniCore_Encode_ClassC(payload_bytes []byte) []byte {

	vchOmBytes := GetOmMarker()
	s := make([][]byte, 2)

	s[0] = vchOmBytes
	s[1] = payload_bytes

	sep := []byte("")
	omni_payload := bytes.Join(s, sep)

	if (uint(len(omni_payload))) > nMaxDatacarrierBytes {
		fmt.Println("omni_payload is too long, only 83 bytes are allowed")
		return nil
	}
	//add op code data

	//CScript script;
	//script << OP_RETURN << vchData;

	//add op code, which is OP_RETURN in this case, and data .
	op_return_data := make([][]byte, 2)
	op_return_data[0] = []byte{OP_RETURN}
	op_return_data[1] = addOpCodeData(omni_payload)
	op_return := bytes.Join(op_return_data, sep)

	return op_return
}

// integer to byte array
/*
func UIntToBytes(integer uint, b int) ([]byte,error) {
	switch b {
	case 8:
		tmp := uint8(integer)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(),nil
	case 16:
		tmp := uint16(integer)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(),nil
	case 32:
		tmp := Uint32(integer)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(),nil
	}
	return nil,fmt.Errorf("UIntToBytes b param is invaild, must be 8, 16 or 32")
*/
/*
 * omnicore.cpp, const std::vector<unsigned char> GetOmMarker()
 * static unsigned char pch[] = {0x6f, 0x6d, 0x6e, 0x69}; // Hex-encoded: "omni"
 * return std::vector<unsigned char>(pch, pch + sizeof(pch) / sizeof(pch[0]));
 *
 * This is the golang version.
 */
func GetOmMarker() []byte {
	//var a = []byte("omni")
	//var a = [...]byte{0x6f, 0x6d, 0x6e, 0x69}
	return []byte{0x6f, 0x6d, 0x6e, 0x69}
}

/*
 * Embeds a payload with class C (op-return) encoding.
 */
func AddOpReturn(tx *wire.MsgTx, data []byte) *wire.MsgTx {

	outputs := OmniCore_Encode_ClassC(data)

	new_output := wire.NewTxOut(0, outputs)
	tx.AddTxOut(new_output)
	return tx
}

/*
 * step 4) Attach payload output
 * omnicore-cli "omni_createrawtx_opreturn" "0100000002de95b97cf4c67ec01485fd698ec154a325ff69dd3e58435d7024bae7f69534c20000000000ffffffffb3b60aaa69b860c9bf31e742e3b37e75a2a553fd0bebf8aaf7da0e9bb07316ee0200000000ffffffff0000000000" "00000000000000020000000000989680"
 *
 */
func Omni_createrawtx_opreturn(base_tx *wire.MsgTx, payload_bytes []byte, payload_str string) (*wire.MsgTx, error) {

	// extend the transaction
	//tx = OmniTxBuilder(tx)
	//        .addOpReturn(payload)
	//        .build();

	tx := AddOpReturn(base_tx, payload_bytes)
	return tx, nil
}

/*
 * script.h overloaded operator <<. Here we translate it to golang func, but for OP_RETURN only
 * https://wiki.bitcoinsv.io/index.php/Pushdata_Opcodes
 */
func addOpCodeData(data []byte) []byte {
	var data_length []byte
	length := len(data)

	if length < OP_PUSHDATA1 {
		//insert(end(), (unsigned char)b.size());
		len_8 := uint8(length)
		data_length = []byte{len_8}

	} else if length <= 0xff {

		//insert(end(), OP_PUSHDATA1);
		//insert(end(), (unsigned char)b.size());
		len_8 := uint8(length)
		data_length = []byte{OP_PUSHDATA1, len_8}

	} else {
		fmt.Println("Only support Opcodes 1-75 (0x01 - 0x4B)  and OP_PUSHDATA1 (76 or 0x4C)")
		return nil
	}

	s := make([][]byte, 2)
	s[0] = data_length
	s[1] = data
	opcode_data := bytes.Join(s, []byte(""))
	return opcode_data
}


<|start_filename|>tracker/service/p2p_service.go<|end_filename|>
package service

import (
	"bufio"
	"context"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/asdine/storm/q"
	"github.com/libp2p/go-libp2p"
	circuit "github.com/libp2p/go-libp2p-circuit"
	"github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	discovery "github.com/libp2p/go-libp2p-discovery"
	dht "github.com/libp2p/go-libp2p-kad-dht"
	ma "github.com/multiformats/go-multiaddr"
	"github.com/omnilaboratory/obd/bean"
	cfg "github.com/omnilaboratory/obd/tracker/config"
	"github.com/omnilaboratory/obd/tracker/dao"
	"log"
	"math/rand"
	"strconv"
	"strings"
	"sync"
	"time"
)

const protocolIdForScanObd = "obd/forScanObd/1.0.1"
const obdRendezvousString = "obd meet at tracker"
const trackerRendezvousString = "tracker meet here"

var ctx = context.Background()
var kademliaDHT *dht.IpfsDHT
var routingDiscovery *discovery.RoutingDiscovery
var hostNode host.Host

func StartP2PNode() {

	nodeId := int64(binary.BigEndian.Uint64([]byte(GetTrackerNodeId())))
	r := rand.New(rand.NewSource(nodeId))
	prvKey, _, err := crypto.GenerateECDSAKeyPair(r)
	if err != nil {
		log.Println(err)
		return
	}

	sourceMultiAddr, _ := ma.NewMultiaddr("/ip4/0.0.0.0/tcp/" + strconv.Itoa(cfg.P2P_sourcePort))
	hostNode, err = libp2p.New(
		ctx,
		libp2p.ListenAddrs(sourceMultiAddr),
		libp2p.Identity(prvKey),
		libp2p.EnableRelay(circuit.OptHop),
	)
	if err != nil {
		log.Println(err)
		return
	}

	hostNode.SetStreamHandler(bean.ProtocolIdForUserState, handleUserStateStream)
	hostNode.SetStreamHandler(bean.ProtocolIdForChannelInfoChange, handleChannelStream)

	cfg.P2pLocalAddress = fmt.Sprintf("/ip4/%s/tcp/%v/p2p/%s", cfg.P2P_hostIp, cfg.P2P_sourcePort, hostNode.ID().Pretty())
	log.Println("local p2p node address: ", cfg.P2pLocalAddress)

	kademliaDHT, err = dht.New(ctx, hostNode, dht.Mode(dht.ModeServer))

	if err != nil {
		log.Println(err)
		return
	}

	err = kademliaDHT.Bootstrap(ctx)
	if err != nil {
		log.Println(err)
		return
	}
	routingDiscovery = discovery.NewRoutingDiscovery(kademliaDHT)

	startSchedule()
}

func startSchedule() {
	announceSelf()
	scanNodes()
	go func() {
		ticker := time.NewTicker(1 * time.Minute)
		defer ticker.Stop()

		for {
			select {
			case t := <-ticker.C:
				log.Println("timer 1m", t)
				announceSelf()
				scanNodes()
			}
		}
	}()
	go func() {
		ticker := time.NewTicker(10 * time.Second)
		defer ticker.Stop()
		for {
			select {
			case t := <-ticker.C:
				log.Println("timer 10s", t)
				go updateLockChannel()
			}
		}
	}()
}

func announceSelf() {
	needAnnounceSelf := false
	if len(cfg.BootstrapPeers) > 0 {
		var wg sync.WaitGroup
		for _, peerAddr := range cfg.BootstrapPeers {
			peerInfo, _ := peer.AddrInfoFromP2pAddr(peerAddr)
			if peerInfo.ID == hostNode.ID() {
				continue
			}
			log.Println("connecting to bootstrap node: ", peerAddr)
			wg.Add(1)
			needAnnounceSelf = true
			go func() {
				defer wg.Done()
				err := hostNode.Connect(ctx, *peerInfo)
				if err != nil {
					log.Println(err, peerInfo)
				} else {
					log.Println("connect to bootstrap node ", *peerInfo)
				}
			}()
		}
		wg.Wait()
	}

	if needAnnounceSelf {
		log.Println("announce self")
		discovery.Advertise(ctx, routingDiscovery, trackerRendezvousString)
	}
}

func scanNodes() {
	log.Println("scanNodes")
	peerChan, err := routingDiscovery.FindPeers(ctx, obdRendezvousString)
	if err != nil {
		log.Println(err)
		return
	}

	for node := range peerChan {
		log.Println("target p2p node id", node.ID)
		if node.ID == hostNode.ID() {
			continue
		}

		//和tracker直接连接的obd，不需要同步数据 因为用户登录，都会直接向tracker报告登录状态
		if obdOnlineNodesMap[node.ID.Pretty()] != nil {
			continue
		}

		log.Println("begin to connect ", node.ID, node.Addrs)
		err = hostNode.Connect(ctx, node)
		if err == nil {
			stream, err := hostNode.NewStream(ctx, node.ID, protocolIdForScanObd)
			if err == nil {
				go handleScanStream(stream)
			}
		} else {
			delete(userOnlineOfOtherObdMap, node.ID.Pretty())
		}
	}
}

var userOnlineOfOtherObdMap = make(map[string]map[string]string)

func handleScanStream(stream network.Stream) {
	log.Println("begin scan obd channel")
	rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
	str, err := rw.ReadString('~')
	if err != nil {
		return
	}

	if str == "" {
		return
	}
	if str != "" {
		str = strings.TrimSuffix(str, "~")
		data := make(map[string]string)
		err = json.Unmarshal([]byte(str), &data)
		if err == nil {
			//online user
			delete(userOnlineOfOtherObdMap, stream.Conn().RemotePeer().Pretty())
			if _, ok := data["userInfo"]; ok == true {
				log.Println(data["userInfo"])
				userInfo := make(map[string]string)
				err = json.Unmarshal([]byte(data["userInfo"]), &userInfo)
				if err == nil {
					userOnlineOfOtherObdMap[stream.Conn().RemotePeer().Pretty()] = userInfo
				}
			}
			//channel
			if _, ok := data["channelInfo"]; ok == true {
				_ = ChannelService.updateChannelInfo(data["obdP2pNodeId"], data["channelInfo"])
			}
		}
	}
	_ = stream.Close()
}

func handleUserStateStream(stream network.Stream) {
	rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
	str, err := rw.ReadString('~')
	if err != nil {
		return
	}
	if str == "" {
		return
	}
	if str != "" {
		str = strings.TrimSuffix(str, "~")
		log.Println("handleUserStateStream", str)
		params := strings.Split(str, "_")
		if len(params) > 1 {
			if _, ok := userOnlineOfOtherObdMap[params[0]]; ok == true {
				if _, ok = userOnlineOfOtherObdMap[params[0]][params[1]]; ok == true {
					delete(userOnlineOfOtherObdMap[params[0]], params[1])
				} else {
					if userOnlineOfOtherObdMap[params[0]] == nil {
						userOnlineOfOtherObdMap[params[0]] = make(map[string]string)
					}
					userOnlineOfOtherObdMap[params[0]][params[1]] = params[2]
				}
			} else {
				if userOnlineOfOtherObdMap[params[0]] == nil {
					userOnlineOfOtherObdMap[params[0]] = make(map[string]string)
				}
				userOnlineOfOtherObdMap[params[0]][params[1]] = params[2]
			}
		}
	}
	_ = stream.Close()
}

func handleChannelStream(stream network.Stream) {
	rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
	str, err := rw.ReadString('~')
	if err != nil {
		return
	}
	if str == "" {
		return
	}
	if str != "" {
		str = strings.TrimSuffix(str, "~")
		log.Println("handleChannelStream", str)
		if len(str) > 0 {
			_ = ChannelService.updateChannelInfo(stream.Conn().RemotePeer().Pretty(), str)
		}
	}
	_ = stream.Close()
}

func sendChannelLockInfoToObd(channelId, userId, obdP2pNodeId string) bool {
	findID, err := peer.Decode(obdP2pNodeId)
	if err == nil {
		findPeer, err := kademliaDHT.FindPeer(ctx, findID)
		if err == nil {
			stream, err := hostNode.NewStream(ctx, findPeer.ID, bean.ProtocolIdForLockChannel)
			if err == nil {
				rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
				request := bean.TrackerLockChannelRequest{UserId: userId, ChannelId: channelId}
				marshal, _ := json.Marshal(request)

				_, _ = rw.WriteString(string(marshal) + "~")
				err = rw.Flush()
				if err == nil {
					str, err := rw.ReadString('~')
					if err != nil {
						return false
					}
					if str == "" {
						return false
					}
					if str != "" {
						str = strings.TrimSuffix(str, "~")
						log.Println("OnSendChannelLockInfoToObd", str)
						if str == "1" {
							return true
						}
					}
				}
				_ = stream.Close()
			}
		}
	}
	return false
}

func updateLockChannel() {
	var infos []dao.LockHtlcPath
	now := time.Now().Add(-20 * time.Second)
	_ = db.Select(q.Or(q.Eq("CurrState", 0), q.Eq("CurrState", 1)), q.Lt("CreateAt", now)).Find(&infos)
	for _, item := range infos {
		paths := item.Path
		index := len(paths) - 1
		channelId := paths[index]
		channelInfo := &dao.ChannelInfo{}

		if item.CurrState == 0 {
			// get anc check First channel, whether the path is invalid
			err := db.Select(q.Eq("ChannelId", channelId)).First(channelInfo)
			if err == nil {
				if channelInfo.CurrState == bean.ChannelState_LockByTracker {
					item.CurrState = 1
					_ = db.Update(&item)
				}
				if channelInfo.CurrState != bean.ChannelState_LockByTracker {
					item.CurrState = 2
					_ = db.Update(&item)
					return
				}
			}
		}

		notifyObdFinish := true
		for index = len(paths) - 1; index >= 0; index-- {
			channelId = paths[index]
			err := db.Select(q.Eq("ChannelId", channelId)).First(channelInfo)
			if err == nil {
				if sendChannelUnlockInfoToObd(channelInfo.ChannelId, channelInfo.PeerIdA, channelInfo.ObdNodeIdA) &&
					sendChannelUnlockInfoToObd(channelInfo.ChannelId, channelInfo.PeerIdB, channelInfo.ObdNodeIdB) {
					channelInfo.CurrState = bean.ChannelState_CanUse
					_ = db.Update(channelInfo)
				} else {
					notifyObdFinish = false
				}
			}
		}
		if notifyObdFinish {
			item.CurrState = 2
			_ = db.Update(&item)
		}
	}
}

func sendChannelUnlockInfoToObd(channelId, userId, obdP2pNodeId string) bool {
	if len(obdP2pNodeId) == 0 {
		return false
	}
	findID, err := peer.Decode(obdP2pNodeId)
	if err == nil {
		findPeer, err := kademliaDHT.FindPeer(ctx, findID)
		if err == nil {
			stream, err := hostNode.NewStream(ctx, findPeer.ID, bean.ProtocolIdForUnlockChannel)
			if err == nil {
				rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
				request := bean.TrackerLockChannelRequest{UserId: userId, ChannelId: channelId}
				marshal, _ := json.Marshal(request)

				_, _ = rw.WriteString(string(marshal) + "~")
				err = rw.Flush()
				if err == nil {
					str, err := rw.ReadString('~')
					if err != nil {
						return false
					}
					if str == "" {
						return false
					}
					if str != "" {
						str = strings.TrimSuffix(str, "~")
						if str == "1" {
							return true
						}
					}
				}
				_ = stream.Close()
			}
		}
	}
	return false
}


<|start_filename|>tracker/dao/dbmanager.go<|end_filename|>
package dao

import (
	"github.com/asdine/storm"
	"github.com/omnilaboratory/obd/config"
	"github.com/omnilaboratory/obd/tool"
	"log"
)

type dbManager struct {
	Db *storm.DB //db
}

var DBService dbManager

func (manager dbManager) GetTrackerDB(chainType string) (*storm.DB, error) {
	if DBService.Db == nil {
		_dir := "dbdata" + "/" + chainType
		_ = tool.PathExistsAndCreate(_dir)
		db, e := storm.Open(_dir + "/" + config.TrackerDbName)
		if e != nil {
			log.Println("open db fail")
			return nil, e
		}
		DBService.Db = db
	}
	return DBService.Db, nil
}


<|start_filename|>lightclient/router.go<|end_filename|>
package lightclient

import (
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/config"
	"github.com/omnilaboratory/obd/tool"
	"github.com/satori/go.uuid"
	"github.com/unrolled/secure"
	"log"
	"net/http"
	"strconv"
)

func InitRouter() *gin.Engine {
	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	router.Use(gin.Logger())
	router.Use(gin.Recovery())
	//router.Use(TlsHandler())

	go GlobalWsClientManager.Start()
	bean.CurrObdNodeInfo.WebsocketLink = "ws://" + config.P2P_hostIp + ":" + strconv.Itoa(config.ServerPort) + "/ws" + config.ChainNodeType
	router.GET("/ws"+config.ChainNodeType, wsClientConnect)

	return router
}

func TlsHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		secureMiddleware := secure.New(secure.Options{
			SSLRedirect: true,
			SSLHost:     config.P2P_hostIp + ":" + strconv.Itoa(config.ServerPort),
		})
		err := secureMiddleware.Process(c.Writer, c.Request)

		// If there was an error, do not continue.
		if err != nil {
			return
		}

		c.Next()
	}
}

func wsClientConnect(c *gin.Context) {

	wsConn, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}).Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Println(err)
		http.NotFound(c.Writer, c.Request)
		return
	}

	client := &Client{
		Id:          uuid.NewV4().String(),
		Socket:      wsConn,
		SendChannel: make(chan []byte)}

	session := c.GetHeader("session")
	if session == tool.GetGRpcSession() {
		client.IsGRpcRequest = true
	}

	go client.Write()
	go client.Read()
	GlobalWsClientManager.Connected <- client
}


<|start_filename|>service/rsmc_commitment_query.go<|end_filename|>
package service

import (
	"encoding/json"
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/tool"
	"github.com/tidwall/gjson"
)

type requestGetInfoByChannelId struct {
	ChannelId string `json:"channel_id"`
}

func getChannelIdFromJson(jsonData string) (channelId string, err error) {
	if tool.CheckIsString(&jsonData) == false {
		return "", errors.New(enum.Tips_common_empty + "input data")
	}
	var reqData = &requestGetInfoByChannelId{}
	err = json.Unmarshal([]byte(jsonData), reqData)
	if err != nil {
		return "", err
	}

	if tool.CheckIsString(&reqData.ChannelId) == false {
		return "", errors.New(enum.Tips_common_empty + "channel_id")
	}
	return reqData.ChannelId, nil
}

func (this *commitmentTxManager) DelItemByChannelId(jsonData string, user *bean.User) (err error) {
	if tool.CheckIsString(&jsonData) == false {
		return errors.New(enum.Tips_common_empty + "input data")
	}
	var reqData = &requestGetInfoByChannelId{}
	err = json.Unmarshal([]byte(jsonData), reqData)
	if err != nil {
		return err
	}
	if tool.CheckIsString(&reqData.ChannelId) == false {
		return errors.New(enum.Tips_common_empty + "channel_id")
	}
	tx, err := user.Db.Begin(true)
	if err != nil {
		return err
	}
	defer tx.Rollback()

	latestCommitmentTxUseDbTx, err := getLatestCommitmentTxUseDbTx(tx, reqData.ChannelId, user.PeerId)
	if err != nil {
		return err
	}
	if latestCommitmentTxUseDbTx.CurrState != dao.TxInfoState_Init && latestCommitmentTxUseDbTx.CurrState != dao.TxInfoState_Create {
		return errors.New("can not delete")
	}
	tx.DeleteStruct(latestCommitmentTxUseDbTx)
	tx.Commit()
	return nil
}

func (this *commitmentTxManager) GetItemsByChannelId(jsonData string, user *bean.User) (nodes []dao.CommitmentTransaction, count *int, err error) {
	channelId, err := getChannelIdFromJson(jsonData)
	if err != nil {
		return nil, nil, err
	}

	channelInfo := &dao.ChannelInfo{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId)).
		First(channelInfo)
	if err != nil {
		return nil, nil, err
	}

	pageIndex := gjson.Get(jsonData, "page_index").Int()
	if pageIndex <= 0 {
		pageIndex = 1
	}
	pageSize := gjson.Get(jsonData, "page_size").Int()
	if pageSize <= 0 {
		pageSize = 10
	}
	skip := (pageIndex - 1) * pageSize

	nodes = []dao.CommitmentTransaction{}
	tempCount, err := user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("Owner", user.PeerId)).
		Count(&dao.CommitmentTransaction{})
	if err != nil {
		return nil, nil, err
	}
	count = &tempCount
	err = user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("Owner", user.PeerId)).
		OrderBy("CreateAt").Reverse().
		Skip(int(skip)).
		Limit(int(pageSize)).
		Find(&nodes)
	return nodes, count, err
}

func (this *commitmentTxManager) GetItemById(id int, user bean.User) (node *dao.CommitmentTransaction, err error) {
	node = &dao.CommitmentTransaction{}
	err = user.Db.Select(
		q.Eq("Id", id)).
		First(node)
	return node, nil
}

func (this *commitmentTxManager) TotalCount(jsonData string, user bean.User) (count int, err error) {
	channelId, err := getChannelIdFromJson(jsonData)
	if err != nil {
		return 0, err
	}
	return user.Db.Select(q.Eq("ChannelId", channelId)).Count(&dao.CommitmentTransaction{})
}

func (this *commitmentTxManager) GetLatestCommitmentTxByChannelId(jsonData string, user *bean.User) (node *dao.CommitmentTransaction, err error) {
	channelId, err := getChannelIdFromJson(jsonData)
	if err != nil {
		return nil, err
	}

	channelInfo := &dao.ChannelInfo{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId)).
		First(channelInfo)
	if err != nil {
		return nil, err
	}

	node = &dao.CommitmentTransaction{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("Owner", user.PeerId),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		OrderBy("CreateAt").Reverse().
		First(node)
	return node, err
}

func (this *commitmentTxManager) GetLatestRDTxByChannelId(jsonData string, user *bean.User) (node *dao.RevocableDeliveryTransaction, err error) {
	channelId, err := getChannelIdFromJson(jsonData)
	if err != nil {
		return nil, err
	}

	channelInfo := &dao.ChannelInfo{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId)).
		First(channelInfo)
	if err != nil {
		return nil, err
	}

	node = &dao.RevocableDeliveryTransaction{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("Owner", user.PeerId)).
		OrderBy("CreateAt").Reverse().
		First(node)
	return node, err
}

func (this *commitmentTxManager) GetAllRDByChannelId(jsonData string, user *bean.User) (nodes []dao.RevocableDeliveryTransaction, err error) {
	channelId, err := getChannelIdFromJson(jsonData)
	if err != nil {
		return nil, err
	}

	channelInfo := &dao.ChannelInfo{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId)).
		First(channelInfo)
	if err != nil {
		return nil, err
	}

	nodes = []dao.RevocableDeliveryTransaction{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("Owner", user.PeerId)).
		OrderBy("CreateAt").Reverse().
		Find(&nodes)
	return nodes, err
}

func (this *commitmentTxManager) GetAllBRByChannelId(jsonData string, user *bean.User) (nodes []dao.BreachRemedyTransaction, err error) {
	channelId, err := getChannelIdFromJson(jsonData)
	if err != nil {
		return nil, err
	}

	channelInfo := &dao.ChannelInfo{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId)).
		First(channelInfo)
	if err != nil {
		return nil, err
	}

	nodes = []dao.BreachRemedyTransaction{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("Owner", user.PeerId)).
		OrderBy("CreateAt").Reverse().
		Find(&nodes)
	return nodes, err
}

func (this *commitmentTxManager) GetLatestBRTxByChannelId(jsonData string, user *bean.User) (node *dao.BreachRemedyTransaction, err error) {
	channelId, err := getChannelIdFromJson(jsonData)
	if err != nil {
		return nil, err
	}

	channelInfo := &dao.ChannelInfo{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId)).
		First(channelInfo)
	if err != nil {
		return nil, err
	}

	node = &dao.BreachRemedyTransaction{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("Owner", user.PeerId)).
		OrderBy("CreateAt").Reverse().
		First(node)
	return node, err
}


<|start_filename|>lightclient/wsclient_htlc.go<|end_filename|>
package lightclient

import (
	"encoding/json"
	"github.com/omnilaboratory/obd/admin"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	conn2tracker "github.com/omnilaboratory/obd/conn"
	"github.com/omnilaboratory/obd/service"
	"log"
)

var tempClientMap = make(map[string]*Client)

func htlcTrackerDealModule(msg bean.RequestMessage) {
	status := false
	data := ""
	client := tempClientMap[msg.RecipientUserPeerId]
	if client == nil {
		log.Println("not found client")
		return
	}
	switch msg.Type {
	case enum.MsgType_Tracker_GetHtlcPath_351:
		respond, err := service.HtlcForwardTxService.GetResponseFromTrackerOfPayerRequestFindPath(msg.Data, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, _ := json.Marshal(respond)
			data = string(bytes)
			status = true
			if client.User.IsAdmin {
				invoiceInfo := respond.(map[string]interface{})
				amountToPayee := invoiceInfo["amount"].(float64)
				amount := invoiceInfo["amount_and_fee"].(float64)
				invoiceInfo["amount"] = amount
				invoiceInfo["amount_to_payee"] = amountToPayee
				newMsg := bean.RequestMessage{Type: enum.MsgType_HTLC_SendAddHTLC_40}
				newMsg.RecipientUserPeerId = invoiceInfo["next_node_peerId"].(string)
				newMsg.RecipientNodePeerId = conn2tracker.GetUserP2pNodeId(newMsg.RecipientUserPeerId)
				newMsg.SenderNodePeerId = client.User.P2PLocalPeerId
				newMsg.SenderUserPeerId = client.User.PeerId
				marshal, _ := json.Marshal(invoiceInfo)
				newMsg.Data = string(marshal)
				_, bytes, status = client.HtlcHModule(newMsg)
				data = string(bytes)
			}
		}
		client.SendToMyself(enum.MsgType_HTLC_FindPath_401, status, data)
	}
}

//htlc h module
func (client *Client) HtlcHModule(msg bean.RequestMessage) (enum.SendTargetType, []byte, bool) {
	status := false
	var sendType = enum.SendTargetType_SendToNone
	data := ""

	switch msg.Type {
	case enum.MsgType_HTLC_Invoice_402:
		htlcHRequest := &bean.HtlcRequestInvoice{}
		err := json.Unmarshal([]byte(msg.Data), htlcHRequest)
		if err != nil {
			data = err.Error()
		} else {
			msg.SenderNodePeerId = client.User.P2PLocalPeerId
			msg.SenderUserPeerId = client.User.PeerId
			if client.User.IsAdmin {
				err := admin.HtlcCreateInvoice(&msg, client.User)
				if err != nil {
					data = err.Error()
					client.SendToMyself(msg.Type, status, data)
					sendType = enum.SendTargetType_SendToSomeone
					break
				}
			}
			respond, err := service.HtlcForwardTxService.CreateHtlcInvoice(msg, *client.User)
			if err != nil {
				data = err.Error()
			} else {
				status = true
				data = respond.(string)
			}
		}
		client.SendToMyself(msg.Type, status, data)
		sendType = enum.SendTargetType_SendToSomeone
	case enum.MsgType_HTLC_FindPath_401:
		tempClientMap[client.User.PeerId] = client
		respond, isPrivate, err := service.HtlcForwardTxService.PayerRequestFindPath(msg.Data, *client.User)
		if err != nil {
			data = err.Error()
			client.SendToMyself(msg.Type, status, data)
		} else {
			bytes, _ := json.Marshal(respond)
			data = string(bytes)
			status = true
			if isPrivate {
				client.SendToMyself(msg.Type, status, data)
				if client.User.IsAdmin {
					invoiceInfo := respond.(map[string]interface{})
					amountToPayee := invoiceInfo["amount"].(float64)
					amount := invoiceInfo["amount_and_fee"].(float64)
					invoiceInfo["amount"] = amount
					invoiceInfo["amount_to_payee"] = amountToPayee
					newMsg := bean.RequestMessage{Type: enum.MsgType_HTLC_SendAddHTLC_40}
					newMsg.RecipientUserPeerId = invoiceInfo["next_node_peerId"].(string)
					newMsg.RecipientNodePeerId = conn2tracker.GetUserP2pNodeId(newMsg.RecipientUserPeerId)
					newMsg.SenderNodePeerId = client.User.P2PLocalPeerId
					newMsg.SenderUserPeerId = client.User.PeerId
					marshal, _ := json.Marshal(invoiceInfo)
					newMsg.Data = string(marshal)
					sendType, bytes, status = client.HtlcHModule(newMsg)
					data = string(bytes)
				}
			}
		}
		sendType = enum.SendTargetType_SendToSomeone
	case enum.MsgType_HTLC_ParseInvoice_403:
		invoice, err := service.HtlcForwardTxService.ParseInvoice(msg.Data, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, _ := json.Marshal(invoice)
			data = string(bytes)
			status = true
		}
		client.SendToMyself(msg.Type, status, data)
		sendType = enum.SendTargetType_SendToSomeone

	case enum.MsgType_HTLC_SendAddHTLC_40:
		if client.User.IsAdmin {
			err := admin.HtlcBeforeAliceAddHtlcAtAliceSide(&msg, client.User)
			if err == nil {
				if P2pChannelMap[msg.RecipientNodePeerId] == nil {
					err = ScanAndConnNode(msg.RecipientNodePeerId)
				}
			}
			if err != nil {
				msg.Type = enum.MsgType_HTLC_SendAddHTLC_40
				client.SendToMyself(msg.Type, false, err.Error())
				break
			}
		}
		respond, needSign, err := service.HtlcForwardTxService.AliceAddHtlcAtAliceSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(respond)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
			if status {
				if needSign == false {
					msg.Type = enum.MsgType_HTLC_AddHTLC_40
					err = client.sendDataToP2PUser(msg, true, data)
					if err != nil {
						status = false
						data = err.Error()
					}
				}
			}
		}

		if status && needSign {
			if client.User.IsAdmin {
				//签名完成
				signedData, err := admin.HtlcAliceSignC3aAtAliceSide(respond, client.User)
				if err == nil {
					signedDataBytes, _ := json.Marshal(signedData)
					msg.Data = string(signedDataBytes)

					_, toBob, err := service.HtlcForwardTxService.OnAliceSignedC3aAtAliceSide(msg, *client.User)
					if err != nil {
						log.Println(err)
						data = err.Error()
					} else {
						bytes, err := json.Marshal(toBob)
						if err != nil {
							data = err.Error()
						} else {
							data = string(bytes)
							status = true
						}

						if status {
							msg.Type = enum.MsgType_HTLC_AddHTLC_40
							err = client.sendDataToP2PUser(msg, true, data)
							if err != nil {
								status = false
								data = err.Error()
							}
						}
					}
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_SendAddHTLC_40
		client.SendToMyself(msg.Type, status, data)

	case enum.MsgType_HTLC_ClientSign_Alice_C3a_100:
		toAlice, toBob, err := service.HtlcForwardTxService.OnAliceSignedC3aAtAliceSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toBob)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}

			if status {
				msg.Type = enum.MsgType_HTLC_AddHTLC_40
				err = client.sendDataToP2PUser(msg, true, data)
				if err != nil {
					status = false
					data = err.Error()
				}
			}

			if status {
				bytes, err := json.Marshal(toAlice)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_ClientSign_Alice_C3a_100
		client.SendToMyself(msg.Type, status, data)

	case enum.MsgType_HTLC_SendAddHTLCSigned_41:
		returnData, err := service.HtlcForwardTxService.BobSignedAddHtlcAtBobSide(msg.Data, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(returnData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_ClientSign_Bob_C3b_101:
		toAlice, toBob, err := service.HtlcForwardTxService.OnBobSignedC3bAtBobSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toAlice)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
			if status {
				msg.Type = enum.MsgType_HTLC_NeedPayerSignC3b_41
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					status = false
					data = err.Error()
				}
			}
			if status {
				bytes, err := json.Marshal(toBob)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_ClientSign_Bob_C3b_101
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_ClientSign_Alice_C3b_102:
		returnData, err := service.HtlcForwardTxService.OnAliceSignC3bAtAliceSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(returnData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_ClientSign_Alice_C3bSub_103:
		toAlice, toBob, err := service.HtlcForwardTxService.OnAliceSignedC3bSubTxAtAliceSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toBob)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}

			if status {
				msg.Type = enum.MsgType_HTLC_PayeeCreateHTRD1a_42
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					status = false
					data = err.Error()
				}
			}
			if status {
				bytes, err := json.Marshal(toAlice)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_ClientSign_Alice_C3bSub_103
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_ClientSign_Bob_C3bSub_104:
		returnData, err := service.HtlcForwardTxService.OnBobSignedC3bSubTxAtBobSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(returnData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_ClientSign_Alice_He_105:
		toAlice, toBob, err := service.HtlcForwardTxService.OnBobSignHtRdAtBobSide_42(msg.Data, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toAlice)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
			if status {
				msg.Type = enum.MsgType_HTLC_PayerSignHTRD1a_43
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					status = false
					data = err.Error()
				}
			}
			if status {
				bytes, err := json.Marshal(toBob)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_ClientSign_Alice_He_105
		client.SendToMyself(msg.Type, status, data)
	}
	return sendType, []byte(data), status
}

//htlc tx
func (client *Client) htlcQueryModule(msg bean.RequestMessage) (enum.SendTargetType, []byte, bool) {
	status := false
	var sendType = enum.SendTargetType_SendToSomeone
	data := ""
	switch msg.Type {
	case enum.MsgType_Htlc_GetLatestHT1aOrHE1b_3250:
		respond, err := service.HtlcQueryTxManager.GetLatestHT1aOrHE1b(msg.Data, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(respond)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_Htlc_GetHT1aOrHE1bBySomeCommitmentId_3251:
		respond, err := service.HtlcQueryTxManager.GetHT1aOrHE1bBySomeCommitmentId(msg.Data, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(respond)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	default:
		sendType = enum.SendTargetType_SendToNone
	}
	return sendType, []byte(data), status
}

//htlc tx
func (client *Client) htlcTxModule(msg bean.RequestMessage) (enum.SendTargetType, []byte, bool) {
	status := false
	var sendType = enum.SendTargetType_SendToSomeone
	data := ""
	switch msg.Type {
	case enum.MsgType_HTLC_SendVerifyR_45:
		respond, err := service.HtlcBackwardTxService.SendRToPreviousNodeAtBobSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(respond)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_ClientSign_Bob_HeSub_106:
		respond, err := service.HtlcBackwardTxService.OnBobSignedHeRdAtBobSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(respond)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
				msg.Type = enum.MsgType_HTLC_VerifyR_45
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_ClientSign_Bob_HeSub_106
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_ClientSign_Alice_HeSub_46:
		toAlice, toBob, err := service.HtlcBackwardTxService.OnAliceSignedHeRdAtAliceSide(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toBob)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
				msg.Type = enum.MsgType_HTLC_SendHerdHex_46
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}
			if status {
				bytes, _ := json.Marshal(toAlice)
				data = string(bytes)
				status = true
			}
		}
		msg.Type = enum.MsgType_HTLC_ClientSign_Alice_HeSub_46
		client.SendToMyself(msg.Type, status, data)
	}
	return sendType, []byte(data), status
}

//htlc tx
func (client *Client) htlcCloseModule(msg bean.RequestMessage) (enum.SendTargetType, []byte, bool) {
	status := false
	var sendType = enum.SendTargetType_SendToNone
	data := ""
	switch msg.Type {
	case enum.MsgType_HTLC_Close_SendRequestCloseCurrTx_49:
		outData, needSign, err := service.HtlcCloseTxService.RequestCloseHtlc(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(outData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
				if needSign == false {
					msg.Type = enum.MsgType_HTLC_Close_RequestCloseCurrTx_49
					err = client.sendDataToP2PUser(msg, status, data)
					if err != nil {
						data = err.Error()
						status = false
					}
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_Close_SendRequestCloseCurrTx_49
		client.SendToMyself(msg.Type, status, data)
		sendType = enum.SendTargetType_SendToSomeone
	case enum.MsgType_HTLC_Close_ClientSign_Alice_C4a_110:
		toAlice, toBob, err := service.HtlcCloseTxService.OnAliceSignedCxa(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toBob)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
			if status {
				msg.Type = enum.MsgType_HTLC_Close_RequestCloseCurrTx_49
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}

			if status {
				bytes, err = json.Marshal(toAlice)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_Close_ClientSign_Alice_C4a_110
		client.SendToMyself(msg.Type, status, data)
		sendType = enum.SendTargetType_SendToSomeone

	case enum.MsgType_HTLC_Close_SendCloseSigned_50:
		outData, err := service.HtlcCloseTxService.OnBobSignCloseHtlcRequest(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, _ := json.Marshal(outData)
			data = string(bytes)
			status = true

		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_Close_ClientSign_Bob_C4b_111:
		toAlice, toBob, err := service.HtlcCloseTxService.OnBobSignedCxb(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toAlice)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
			if status {
				msg.Type = enum.MsgType_HTLC_CloseHtlcRequestSignBR_50
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}
			if status {
				bytes, err := json.Marshal(toBob)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_Close_ClientSign_Bob_C4b_111
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_Close_ClientSign_Alice_C4b_112:
		toAlice, err := service.HtlcCloseTxService.OnAliceSignedCxb(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toAlice)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_Close_ClientSign_Alice_C4bSub_113:
		toAlice, toBob, err := service.HtlcCloseTxService.OnAliceSignedCxbBubTx(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(toBob)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}

			if status {
				msg.Type = enum.MsgType_HTLC_CloseHtlcUpdateCnb_51
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}
			if status {
				bytes, err := json.Marshal(toAlice)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		msg.Type = enum.MsgType_HTLC_Close_ClientSign_Alice_C4bSub_113
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_HTLC_Close_ClientSign_Bob_C4bSubResult_114:
		toBob, err := service.HtlcCloseTxService.OnBobSignedCxbSubTx(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, _ := json.Marshal(toBob)
			data = string(bytes)
			status = true
		}
		client.SendToMyself(msg.Type, status, data)
	}
	return sendType, []byte(data), status
}
func (client *Client) atomicSwapModule(msg bean.RequestMessage) (enum.SendTargetType, []byte, bool) {
	status := false
	var sendType = enum.SendTargetType_SendToNone
	data := ""
	switch msg.Type {
	case enum.MsgType_Atomic_SendSwap_80:
		outData, err := service.AtomicSwapService.AtomicSwap(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(outData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
				msg.Type = enum.MsgType_Atomic_Swap_80
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}
		}
		msg.Type = enum.MsgType_Atomic_SendSwap_80
		client.SendToMyself(msg.Type, status, data)
		break
	case enum.MsgType_Atomic_SendSwapAccept_81:
		outData, err := service.AtomicSwapService.AtomicSwapAccepted(msg, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(outData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
				msg.Type = enum.MsgType_Atomic_SwapAccept_81
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}
		}
		msg.Type = enum.MsgType_Atomic_SendSwapAccept_81
		client.SendToMyself(msg.Type, status, data)
		break
	}
	return sendType, []byte(data), status
}


<|start_filename|>admin/rsmc.go<|end_filename|>
package admin

import (
	"encoding/json"
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/service"
)

func RsmcAliceCreateTx(msg *bean.RequestMessage, user *bean.User) (err error) {
	reqData := &bean.RequestCreateCommitmentTx{}
	err = json.Unmarshal([]byte(msg.Data), reqData)
	if err != nil {
		return err
	}
	channelInfo := dao.ChannelInfo{}
	_ = user.Db.Select(q.Eq("ChannelId", reqData.ChannelId)).First(&channelInfo)
	if channelInfo.Id == 0 {
		return errors.New("not found the channel")
	}

	latestCommitmentTx := getLatestCommitmentTx(channelInfo.ChannelId, *user)
	if latestCommitmentTx.Id > 0 {
		lastWalletInfo, err := service.HDWalletService.GetAddressByIndex(user, uint32(latestCommitmentTx.RSMCTempAddressIndex))
		if err != nil {
			return err
		}
		reqData.LastTempAddressPrivateKey = lastWalletInfo.Wif
	}
	address, err := service.HDWalletService.CreateNewAddress(user)
	if err != nil {
		return err
	}
	reqData.CurrTempAddressIndex = address.Index
	reqData.CurrTempAddressPubKey = address.PubKey
	marshal, _ := json.Marshal(reqData)
	msg.Data = string(marshal)
	return nil
}

func RsmcAliceFirstSignC2a(signData interface{}, user *bean.User) (signedDataForC2a *bean.AliceSignedRsmcDataForC2a, err error) {
	needSignData := signData.(bean.NeedAliceSignRsmcDataForC2a)
	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}

	signedDataForC2a = &bean.AliceSignedRsmcDataForC2a{}
	signedDataForC2a.ChannelId = needSignData.ChannelId
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.RsmcRawData.Hex, convertBean(needSignData.RsmcRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedDataForC2a.RsmcSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.CounterpartyRawData.Hex, convertBean(needSignData.CounterpartyRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedDataForC2a.CounterpartySignedHex = hex
	return signedDataForC2a, nil
}

func RsmcBobSecondSignC2a(needSignData *bean.PayerRequestCommitmentTxToBobClient, user *bean.User) (signedData *bean.PayeeSendSignCommitmentTx, err error) {

	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}
	signedData = &bean.PayeeSendSignCommitmentTx{}
	signedData.ChannelId = needSignData.ChannelId
	signedData.MsgHash = needSignData.MsgHash
	signedData.Approval = true

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.RsmcRawData.Hex, convertBean(needSignData.RsmcRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C2aRsmcSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.CounterpartyRawData.Hex, convertBean(needSignData.CounterpartyRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C2aCounterpartySignedHex = hex

	latestCommitmentTx := getLatestCommitmentTx(needSignData.ChannelId, *user)
	if latestCommitmentTx.Id > 0 {
		latestRsmcAddressInfo, _ := service.HDWalletService.GetAddressByIndex(user, uint32(latestCommitmentTx.RSMCTempAddressIndex))
		signedData.LastTempAddressPrivateKey = latestRsmcAddressInfo.Wif
	}

	address, err := service.HDWalletService.CreateNewAddress(user)
	if err != nil {
		return nil, err
	}
	signedData.CurrTempAddressIndex = address.Index
	signedData.CurrTempAddressPubKey = address.PubKey

	return signedData, nil
}

func RsmcBobFirstSignC2b(c2bData interface{}, user *bean.User) (signedDataForC2b *bean.BobSignedRsmcDataForC2b, err error) {

	needSignData := c2bData.(bean.NeedBobSignRawDataForC2b)

	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}

	signedDataForC2b = &bean.BobSignedRsmcDataForC2b{}
	signedDataForC2b.ChannelId = needSignData.ChannelId

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C2aRdRawData.Hex, convertBean(needSignData.C2aRdRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedDataForC2b.C2aRdSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C2aBrRawData.Hex, convertBean(needSignData.C2aBrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedDataForC2b.C2aBrSignedHex = hex
	signedDataForC2b.C2aBrId = int64(needSignData.C2aBrRawData.BrId)

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C2bRsmcRawData.Hex, convertBean(needSignData.C2bRsmcRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedDataForC2b.C2bRsmcSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C2bCounterpartyRawData.Hex, convertBean(needSignData.C2bCounterpartyRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedDataForC2b.C2bCounterpartySignedHex = hex

	return signedDataForC2b, nil
}

func RsmcAliceSignC2b(data interface{}, user *bean.User) (signedData *bean.AliceSignedRsmcTxForC2b, err error) {

	needSignData := data.(bean.NeedAliceSignRsmcTxForC2b)

	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}

	signedData = &bean.AliceSignedRsmcTxForC2b{}
	signedData.ChannelId = needSignData.ChannelId

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C2bRsmcPartialData.Hex, convertBean(needSignData.C2bRsmcPartialData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C2bRsmcSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C2bCounterpartyPartialData.Hex, convertBean(needSignData.C2bCounterpartyPartialData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C2bCounterpartySignedHex = hex

	commitmentTransaction := getCurrCommitmentTx(needSignData.ChannelId, *user)
	tempAddressInfo, _ := service.HDWalletService.GetAddressByIndex(user, uint32(commitmentTransaction.RSMCTempAddressIndex))
	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C2aRdPartialData.Hex, convertBean(needSignData.C2aRdPartialData.Inputs), tempAddressInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C2aRdSignedHex = hex

	return signedData, nil
}

func RsmcAliceSignRdOfC2b(data interface{}, user *bean.User) (signedData *bean.AliceSignedRdTxForC2b, err error) {

	needSignData := data.(bean.NeedAliceSignRdTxForC2b)

	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}

	signedData = &bean.AliceSignedRdTxForC2b{}
	signedData.ChannelId = needSignData.ChannelId

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C2bRdRawData.Hex, convertBean(needSignData.C2bRdRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C2bRdSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C2bBrRawData.Hex, convertBean(needSignData.C2bBrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C2bBrSignedHex = hex
	signedData.C2bBrId = int64(needSignData.C2bBrRawData.BrId)

	return signedData, nil
}

func RsmcBobSignRdOfC2b(needSignData bean.NeedBobSignRdTxForC2b, user *bean.User) (signedData *bean.BobSignedRdTxForC2b, err error) {
	signedData = &bean.BobSignedRdTxForC2b{}
	signedData.ChannelId = needSignData.ChannelId
	commitmentTransaction := getCurrCommitmentTx(signedData.ChannelId, *user)
	wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(commitmentTransaction.RSMCTempAddressIndex))

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C2bRdPartialData.Hex, convertBean(needSignData.C2bRdPartialData.Inputs), wallet.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C2bRdSignedHex = hex

	return signedData, nil
}


<|start_filename|>proxy/cli/commands.go<|end_filename|>
package main

import (
	context "context"
	fmt "fmt"
	"log"
	"os"

	proxy "github.com/omnilaboratory/obd/proxy/pb"
	"github.com/urfave/cli"
	grpc "google.golang.org/grpc"
)


var HelloCommand = cli.Command{
	Name:      "hello",
	Category:  "testing",
	Usage:     "Say Hello to Proxy Mode of OBD",
	ArgsUsage: "your_name",
	Description: "Say Hello to Proxy Mode of OBD",
	Action: cliHello,
}

func cliHello(ctx *cli.Context) error {
	
	client, cleanUp := getClientConn(ctx)
	defer cleanUp()

	inputParam := ctx.Args().First()

	var outputInfo string
	switch inputParam {
	case "":
		outputInfo = "You can try to input anything."
		return fmt.Errorf(outputInfo)
	}

	ctxb := context.Background()
	resp, err := client.Hello(ctxb, &proxy.HelloRequest{
		Sayhi: inputParam,
	})

	if err != nil {
		return err
	}

	fmt.Println(resp)
	return nil
}

func getClientConn(ctx *cli.Context) (proxy.ProxyClient, func()) {

	fmt.Println("Get client connection ...")

	opts := grpc.WithInsecure()
	cc, err := grpc.Dial("localhost:50051", opts)
	if err != nil {
		// log.Fatal(err)
		fmt.Printf("unable to connect to RPC server: %v", err)
	}
	// defer cc.Close()

	cleanUp := func() {
		cc.Close()
	}

	return proxy.NewProxyClient(cc), cleanUp
}

func main() {
	app := cli.NewApp()
	app.Name = "obdcli"
	app.Version = "0.0.1-beta"
	app.Usage = "Control plane for your Omni Bolt Daemon (obd)"
	app.Commands = []cli.Command{
		HelloCommand,
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

<|start_filename|>omnicore/VerifySignature_test.go<|end_filename|>
package omnicore

import (
	"encoding/hex"
	"fmt"

	"testing"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/txscript"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
)

func TestVerifySignature(t *testing.T) {
	// Testing data is from the issue: https://github.com/btcsuite/btcd/issues/1309
	//But somehow it doesn't work.

	tx_hex := "01000000013dcd7d87904c9cb7f4b79f36b5a03f96e2e729284c09856238d5353e1182b00200000000fd5d01004730440220762ce7bca626942975bfd5b130ed3470b9f538eb2ac120c2043b445709369628022051d73c80328b543f744aa64b7e9ebefa7ade3e5c716eab4a09b408d2c307ccd701483045022100abf740b58d79cab000f8b0d328c2fff7eb88933971d1b63f8b99e89ca3f2dae602203354770db3cc2623349c87dea7a50cee1f78753141a5052b2d58aeb592bcf50f014cc9524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353aeffffffff0130d90000000000001976a914569076ba39fc4ff6a2291d9ea9196d8c08f9c7ab88ac00000000"

	fmt.Println(DecodeRawTransaction(tx_hex, &chaincfg.MainNetParams))

	pubkey_hex := "04a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd"
	signature_hex := "30440220762ce7bca626942975bfd5b130ed3470b9f538eb2ac120c2043b445709369628022051d73c80328b543f744aa64b7e9ebefa7ade3e5c716eab4a09b408d2c307ccd701"
	scriptSig := "<KEY>"
	if VerifySignature(pubkey_hex, signature_hex, scriptSig, tx_hex) {
		fmt.Println("Signature is correct!")
	} else {
		fmt.Println("Wrong signature!")
	}

}

func TestVerifySignatureFromTxHex(t *testing.T) {

	// txs are created by the example in TestSignature(t *testing.T)
	unsiged_tx := "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff020000ffffffff0100e1f505000000001976a9143dee47716e3cfa57df45113473a6312ebeaef31188ac00000000"
	siged_tx := "01000000013e7b20e5029f0a4edc65dcfaa0ba145a4c8ccdc522de366515fbddbbd2609f34000000006b483045022100ed3969fcdae3d50ead3e4ba5d985335ecaf1ce497870285a619c82189a90e8d602204133c58290b0263e5a2fee5c2c05e2588fcf1b23637a7d2ff240f6e1abfb830f012102a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5ffffffff0100000000000000000000000000"

	if VerifySignatureFromTxHex(unsiged_tx, siged_tx) {
		fmt.Println("Signature is correct!")
	} else {
		fmt.Println("Wrong signature!")
	}
}

/*
 * https://github.com/btcsuite/btcd/blob/master/txscript/example_test.go
 * ExampleSignTxOutput()
 * This is an example from above link.
 */
func TestSignature(t *testing.T) {

	// Ordinarily the private key would come from whatever storage mechanism
	// is being used, but for this example just hard code it.
	privKeyBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2" +
		"d4f8720ee63e502ee2869afab7de234b80c")
	if err != nil {
		fmt.Println(err)
		return
	}
	privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
	pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed())
	addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash,
		&chaincfg.MainNetParams)
	if err != nil {
		fmt.Println(err)
		return
	}

	// For this example, create a fake transaction that represents what
	// would ordinarily be the real transaction that is being spent.  It
	// contains a single output that pays to address in the amount of 1 BTC.
	originTx := wire.NewMsgTx(wire.TxVersion)
	prevOut := wire.NewOutPoint(&chainhash.Hash{}, ^uint32(0))
	txIn := wire.NewTxIn(prevOut, []byte{txscript.OP_0, txscript.OP_0}, nil)
	originTx.AddTxIn(txIn)
	pkScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		fmt.Println(err)
		return
	}
	txOut := wire.NewTxOut(100000000, pkScript)
	originTx.AddTxOut(txOut)
	originTxHash := originTx.TxHash()

	fmt.Println("unsigned tx is: ")
	fmt.Println(TxToHex(originTx))
	fmt.Println("got it.")

	// Create the transaction to redeem the fake transaction.
	redeemTx := wire.NewMsgTx(wire.TxVersion)

	// Add the input(s) the redeeming transaction will spend.  There is no
	// signature script at this point since it hasn't been created or signed
	// yet, hence nil is provided for it.
	prevOut = wire.NewOutPoint(&originTxHash, 0)
	txIn = wire.NewTxIn(prevOut, nil, nil)
	redeemTx.AddTxIn(txIn)

	// Ordinarily this would contain that actual destination of the funds,
	// but for this example don't bother.
	txOut = wire.NewTxOut(0, nil)
	redeemTx.AddTxOut(txOut)

	// SignRawHex the redeeming transaction.
	lookupKey := func(a btcutil.Address) (*btcec.PrivateKey, bool, error) {
		// Ordinarily this function would involve looking up the private
		// key for the provided address, but since the only thing being
		// signed in this example uses the address associated with the
		// private key from above, simply return it with the compressed
		// flag set since the address is using the associated compressed
		// public key.
		//
		// NOTE: If you want to prove the code is actually signing the
		// transaction properly, uncomment the following line which
		// intentionally returns an invalid key to sign with, which in
		// turn will result in a failure during the script execution
		// when verifying the signature.
		//
		// privKey.D.SetInt64(12345)
		//
		return privKey, true, nil
	}
	// Notice that the script database parameter is nil here since it isn't
	// used.  It must be specified when pay-to-script-hash transactions are
	// being signed.
	sigScript, err := txscript.SignTxOutput(&chaincfg.MainNetParams,
		redeemTx, 0, originTx.TxOut[0].PkScript, txscript.SigHashAll,
		txscript.KeyClosure(lookupKey), nil, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	redeemTx.TxIn[0].SignatureScript = sigScript

	fmt.Println("signed tx is: ")
	fmt.Println(TxToHex(redeemTx))
	fmt.Println("got it.")

	// Prove that the transaction has been validly signed by executing the
	// script pair.
	flags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures |
		txscript.ScriptStrictMultiSig |
		txscript.ScriptDiscourageUpgradableNops
	vm, err := txscript.NewEngine(originTx.TxOut[0].PkScript, redeemTx, 0,
		flags, nil, nil, -1)
	if err != nil {
		fmt.Println(err)
		return
	}
	if err := vm.Execute(); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Transaction successfully signed")

	// Output:
	// Transaction successfully signed
}


<|start_filename|>omnicore/rpcpayload.go<|end_filename|>
package omnicore

import (
	"bytes"
	"encoding/hex"
	"errors"
	"fmt"
	"strconv"
	"unsafe"

	"github.com/btcsuite/btcd/wire"
)

/*
* parsing.cpp, static bool isBigEndian()
 */
func IsLittleEndian() bool {
	n := 0x1234
	return *(*byte)(unsafe.Pointer(&n)) == 0x34
}

/**
 * Swaps byte order of 16 bit wide numbers on little-endian systems.
 * parsing.cpp, void SwapByteOrder16(uint16_t& us)
 */
func SwapByteOrder16(us uint16) uint16 {
	if IsLittleEndian() {
		us = (us >> 8) |
			(us << 8)
	}
	return us
}

/**
 * Swaps byte order of 32 bit wide numbers on little-endian systems.
 */
func SwapByteOrder32(ui uint32) uint32 {
	if IsLittleEndian() {
		ui = (ui >> 24) |
			((ui << 8) & 0x00FF0000) |
			((ui >> 8) & 0x0000FF00) |
			(ui << 24)
	}
	return ui
}

/**
 * Swaps byte order of 64 bit wide numbers on little-endian systems.
 */
func SwapByteOrder64(ull uint64) uint64 {
	if IsLittleEndian() {
		ull = (ull >> 56) |
			((ull << 40) & 0x00FF000000000000) |
			((ull << 24) & 0x0000FF0000000000) |
			((ull << 8) & 0x000000FF00000000) |
			((ull >> 8) & 0x00000000FF000000) |
			((ull >> 24) & 0x0000000000FF0000) |
			((ull >> 40) & 0x000000000000FF00) |
			(ull << 56)
	}

	return ull
}

func Uint16ToBytes(n uint16) []byte {
	return []byte{
		byte(n),
		byte(n >> 8),
	}
}
func Uint32ToBytes(n uint32) []byte {
	return []byte{
		byte(n),
		byte(n >> 8),
		byte(n >> 16),
		byte(n >> 24),
	}
}
func Uint64ToBytes(n uint64) []byte {
	return []byte{
		byte(n),
		byte(n >> 8),
		byte(n >> 16),
		byte(n >> 24),
		byte(n >> 32),
		byte(n >> 40),
		byte(n >> 48),
		byte(n >> 56),
	}
}

// createPayload.cpp, std::vector<unsigned char> CreatePayload_SimpleSend(uint32_t propertyId, uint64_t amount)
// This is a straight forward translation in golang.
func OmniCreatePayloadSimpleSend(property_id uint32, amount uint64) []byte {

	var messageType uint16 = 0
	var messageVer uint16 = 0
	messageType = SwapByteOrder16(messageType)
	messageVer = SwapByteOrder16(messageVer)
	property_id = SwapByteOrder32(property_id)
	amount = SwapByteOrder64(amount)

	len := 4
	s := make([][]byte, len)

	s[0] = Uint16ToBytes(messageType)
	s[1] = Uint16ToBytes(messageVer)
	s[2] = Uint32ToBytes(property_id)
	s[3] = Uint64ToBytes(amount)

	sep := []byte("")
	return bytes.Join(s, sep)

}

/*
 * rpcvalue.cpp, uint32_t ParsePropertyId(const UniValue& value)
 */
func ParsePropertyId(property_id string) (uint32, error) {
	id, err := strconv.ParseInt(property_id, 10, 64)
	if err == nil {
		//fmt.Printf("i64 %v \n", id)
	}

	if id < 1 || int64(4294967295) < id {
		fmt.Println("Property identifier is out of range")
		return 0, errors.New("Property identifier is out of range")
	}

	return uint32(id), nil

}

/*
 * step 2) Construct payload
 * omnicore-cli "omni_createpayload_simplesend" 2 "0.1"
 *
 * rpcpayload.cpp, static UniValue omni_createpayload_simplesend(const JSONRPCRequest& request)
 *
 */
func Omni_createpayload_simplesend(property_id_str string, amount_str string, divisible bool) ([]byte, string) {
	property_id, _ := ParsePropertyId(property_id_str)
	amount := StrToInt64(amount_str, divisible)

	//because amount must be less than the biggest unsigned 64-bit integer, and bigger than 0
	//so that here we transform amount to be uint64
	//TO DO: add check here.
	amount_uint64 := uint64(amount)

	payload := OmniCreatePayloadSimpleSend(property_id, amount_uint64)

	return payload, HexStr(payload)

}

func TxToHex(tx *wire.MsgTx) string {
	buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize()))
	tx.Serialize(buf)
	return hex.EncodeToString(buf.Bytes())
}


<|start_filename|>proxy/rpc/server.go<|end_filename|>
package rpc

import (
	"github.com/omnilaboratory/obd/config"
	proxy "github.com/omnilaboratory/obd/proxy/pb"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	"log"
	"net"
	"strconv"
)

func StartGrpcServer() {

	log.Println("startGrpcServer")
	err := ConnToObd()
	if err != nil {
		log.Println(err)
		return
	}

	address := "0.0.0.0:" + strconv.Itoa(config.GrpcServerPort)
	lis, err := net.Listen("tcp", address)
	if err != nil {
		log.Fatalf("Error %v", err)
	}
	log.Printf("grpc Server is listening on %v ...", address)

	s := grpc.NewServer()
	reflection.Register(s)
	proxy.RegisterLightningServer(s, &RpcServer{})
	proxy.RegisterWalletServer(s, &RpcServer{})
	proxy.RegisterRsmcServer(s, &RpcServer{})
	proxy.RegisterHtlcServer(s, &RpcServer{})
	s.Serve(lis)
}


<|start_filename|>service/htlc_tx_common.go<|end_filename|>
package service

import (
	"errors"
	"github.com/asdine/storm"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/tidwall/gjson"
	"log"
	"time"
)

func createHtlcHLockTxObj(tx storm.Node, owner string, channelInfo dao.ChannelInfo, h string, commitmentTxInfo dao.CommitmentTransaction, outputBean map[string]interface{}, timeout int, user bean.User) (henxTx *dao.HtlcLockTxByH, err error) {
	henxTx = &dao.HtlcLockTxByH{}
	henxTx.ChannelId = channelInfo.ChannelId
	henxTx.CommitmentTxId = commitmentTxInfo.Id
	henxTx.PropertyId = commitmentTxInfo.PropertyId
	henxTx.HtlcH = commitmentTxInfo.HtlcH
	henxTx.Owner = owner
	count, err := tx.Select(
		q.Eq("ChannelId", henxTx.ChannelId),
		q.Eq("CommitmentTxId", henxTx.CommitmentTxId),
		q.Eq("Owner", owner)).
		Count(henxTx)
	if err == nil {
		if count > 0 {
			return nil, errors.New("already exist")
		}
	}
	//input
	henxTx.InputHex = commitmentTxInfo.HtlcTxHex
	henxTx.InputTxid = commitmentTxInfo.HTLCTxid

	henxTx.PayeeChannelPubKey = outputBean["otherSideChannelPubKey"].(string)
	multiAddr, err := omnicore.CreateMultiSig(2, []string{h, henxTx.PayeeChannelPubKey})
	if err != nil {
		return nil, err
	}
	henxTx.OutputAddress = gjson.Get(multiAddr, "address").String()
	henxTx.RedeemScript = gjson.Get(multiAddr, "redeemScript").String()
	henxTx.ScriptPubKey = gjson.Get(multiAddr, "scriptPubKey").String()
	henxTx.OutAmount = outputBean["amount"].(float64)
	henxTx.Timeout = timeout
	henxTx.CreateBy = user.PeerId
	henxTx.CreateAt = time.Now()
	return henxTx, nil
}

func createHtlcTimeoutTxObj(tx storm.Node, owner string, channelInfo dao.ChannelInfo, commitmentTxInfo *dao.CommitmentTransaction, outputBean commitmentTxOutputBean, timeout int, user bean.User) (*dao.HTLCTimeoutTxForAAndExecutionForB, error) {
	htlcTimeoutTx := &dao.HTLCTimeoutTxForAAndExecutionForB{}
	htlcTimeoutTx.ChannelId = channelInfo.ChannelId
	htlcTimeoutTx.CommitmentTxId = commitmentTxInfo.Id
	htlcTimeoutTx.PropertyId = commitmentTxInfo.PropertyId
	htlcTimeoutTx.Owner = owner
	count, err := tx.Select(
		q.Eq("ChannelId", htlcTimeoutTx.ChannelId),
		q.Eq("CommitmentTxId", htlcTimeoutTx.CommitmentTxId),
		q.Eq("Owner", owner)).
		Count(htlcTimeoutTx)
	if err == nil {
		if count > 0 {
			return nil, errors.New("already exist")
		}
	}
	//input
	htlcTimeoutTx.InputHex = commitmentTxInfo.HtlcTxHex
	htlcTimeoutTx.InputAmount = commitmentTxInfo.AmountToHtlc

	//output to rsmc
	htlcTimeoutTx.RSMCTempAddressPubKey = outputBean.RsmcTempPubKey
	multiAddr, err := omnicore.CreateMultiSig(2, []string{htlcTimeoutTx.RSMCTempAddressPubKey, outputBean.OppositeSideChannelPubKey})
	if err != nil {
		return nil, err
	}
	htlcTimeoutTx.RSMCMultiAddress = gjson.Get(multiAddr, "address").String()
	htlcTimeoutTx.RSMCRedeemScript = gjson.Get(multiAddr, "redeemScript").String()
	htlcTimeoutTx.RSMCMultiAddressScriptPubKey = gjson.Get(multiAddr, "scriptPubKey").String()
	htlcTimeoutTx.RSMCOutAmount = outputBean.AmountToRsmc
	htlcTimeoutTx.Timeout = timeout
	htlcTimeoutTx.CreateBy = user.PeerId
	htlcTimeoutTx.CreateAt = time.Now()
	return htlcTimeoutTx, nil
}

func createHtlcRDTxObj(owner string, channelInfo *dao.ChannelInfo, htlcTimeoutTx *dao.HTLCTimeoutTxForAAndExecutionForB, toAddress string,
	user *bean.User) (*dao.RevocableDeliveryTransaction, error) {
	htrd := &dao.RevocableDeliveryTransaction{}
	htrd.ChannelId = channelInfo.ChannelId
	htrd.CommitmentTxId = htlcTimeoutTx.Id
	htrd.PeerIdA = channelInfo.PeerIdA
	htrd.PeerIdB = channelInfo.PeerIdB
	htrd.PropertyId = htlcTimeoutTx.PropertyId
	htrd.Owner = owner
	htrd.RDType = 1

	//input
	htrd.InputTxHex = htlcTimeoutTx.RSMCTxHex
	htrd.InputTxid = htlcTimeoutTx.RSMCTxid
	htrd.InputVout = 0
	htrd.InputAmount = htlcTimeoutTx.RSMCOutAmount
	//output
	htrd.OutputAddress = toAddress
	htrd.Sequence = 1000
	htrd.Amount = htlcTimeoutTx.RSMCOutAmount

	htrd.CreateBy = user.PeerId
	htrd.CreateAt = time.Now()
	htrd.LastEditTime = time.Now()

	return htrd, nil
}

//为alice生成HT1a
func createHT1aForAlice(channelInfo dao.ChannelInfo, aliceDataJson bean.CreateHtlcTxForC3aOfP2p, signedHtlcHex string,
	bobChannelPubKey string, propertyId int64, amountToHtlc float64, htlcTimeOut int) (*bean.NeedClientSignTxData, error) {
	aliceHtlcMultiAddr, err := omnicore.CreateMultiSig(2, []string{aliceDataJson.CurrHtlcTempAddressPubKey, bobChannelPubKey})
	if err != nil {
		return nil, err
	}
	aliceHtlcMultiAddress := gjson.Get(aliceHtlcMultiAddr, "address").String()
	aliceHtlcRedeemScript := gjson.Get(aliceHtlcMultiAddr, "redeemScript").String()
	aliceHtlcMultiAddressScriptPubKey := gjson.Get(aliceHtlcMultiAddr, "scriptPubKey").String()

	htlcInputs, err := getInputsForNextTxByParseTxHashVout(signedHtlcHex, aliceHtlcMultiAddress, aliceHtlcMultiAddressScriptPubKey, aliceHtlcRedeemScript)
	if err != nil || len(htlcInputs) == 0 {
		log.Println(err)
		return nil, err
	}

	aliceHt1aMultiAddr, err := omnicore.CreateMultiSig(2, []string{aliceDataJson.CurrHtlcTempAddressForHt1aPubKey, bobChannelPubKey})
	if err != nil {
		return nil, err
	}
	aliceHt1aMultiAddress := gjson.Get(aliceHt1aMultiAddr, "address").String()
	aliceHt1aTxData, err := omnicore.OmniCreateRawTransactionUseUnsendInput(
		aliceHtlcMultiAddress,
		htlcInputs,
		aliceHt1aMultiAddress,
		aliceHt1aMultiAddress,
		propertyId,
		amountToHtlc,
		getBtcMinerAmount(channelInfo.BtcAmount),
		htlcTimeOut,
		&aliceHtlcRedeemScript)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	ht1aTxData := bean.NeedClientSignTxData{}
	ht1aTxData.Hex = aliceHt1aTxData["hex"].(string)
	ht1aTxData.Inputs = aliceHt1aTxData["inputs"]
	ht1aTxData.IsMultisig = true
	return &ht1aTxData, nil
}

func saveHT1aForAlice(tx storm.Node, channelInfo dao.ChannelInfo, commitmentTransaction *dao.CommitmentTransaction,
	signedHtlaHex string, htlcRequestInfo dao.AddHtlcRequestInfo, payeePubKey string, htlcTimeOut int, user bean.User) (htlcTimeoutTx *dao.HTLCTimeoutTxForAAndExecutionForB, err error) {

	outputBean := commitmentTxOutputBean{}
	outputBean.AmountToRsmc = commitmentTransaction.AmountToHtlc
	outputBean.RsmcTempPubKey = htlcRequestInfo.CurrHtlcTempAddressForHt1aPubKey
	outputBean.OppositeSideChannelPubKey = payeePubKey
	htlcTimeoutTx, err = createHtlcTimeoutTxObj(tx, user.PeerId, channelInfo, commitmentTransaction, outputBean, htlcTimeOut, user)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	htlcTimeoutTx.RSMCTempAddressIndex = htlcRequestInfo.CurrHtlcTempAddressForHt1aIndex

	payerHt1aInputsFromHtlc, err := getInputsForNextTxByParseTxHashVout(
		commitmentTransaction.HtlcTxHex,
		commitmentTransaction.HTLCMultiAddress,
		commitmentTransaction.HTLCMultiAddressScriptPubKey,
		commitmentTransaction.HTLCRedeemScript)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	htlcTimeoutTx.InputTxid = payerHt1aInputsFromHtlc[0].Txid

	htlcTimeoutTx.RSMCTxid = omnicore.GetTxId(signedHtlaHex)
	htlcTimeoutTx.RSMCTxHex = signedHtlaHex
	htlcTimeoutTx.SignAt = time.Now()
	htlcTimeoutTx.CurrState = dao.TxInfoState_CreateAndSign
	err = tx.Save(htlcTimeoutTx)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	return htlcTimeoutTx, nil
}

// 收款方在41号协议用签名完成toHtlc的Hex，就用这个完整交易Hex，构建C3a方的Hlock交易
func createHtlcLockByHForBobAtPayeeSide(channelInfo dao.ChannelInfo, aliceDataJson bean.CreateHtlcTxForC3aOfP2p, signedHtlcHex string,
	bobChannelPubKey string, propertyId int64, amountToHtlc float64) (*bean.NeedClientSignTxData, error) {
	aliceHtlcMultiAddr, err := omnicore.CreateMultiSig(2, []string{aliceDataJson.CurrHtlcTempAddressPubKey, bobChannelPubKey})
	if err != nil {
		return nil, err
	}
	aliceHtlcMultiAddress := gjson.Get(aliceHtlcMultiAddr, "address").String()
	aliceHtlcRedeemScript := gjson.Get(aliceHtlcMultiAddr, "redeemScript").String()
	aliceHtlcMultiAddressScriptPubKey := gjson.Get(aliceHtlcMultiAddr, "scriptPubKey").String()

	htlcInputs, err := getInputsForNextTxByParseTxHashVout(signedHtlcHex, aliceHtlcMultiAddress, aliceHtlcMultiAddressScriptPubKey, aliceHtlcRedeemScript)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	htlcLockByHMultiAddr, err := omnicore.CreateMultiSig(2, []string{aliceDataJson.H, bobChannelPubKey})
	if err != nil {
		return nil, err
	}
	htlcLockByHMultiAddress := gjson.Get(htlcLockByHMultiAddr, "address").String()
	hlockHexData, err := omnicore.OmniCreateRawTransactionUseUnsendInput(
		aliceHtlcMultiAddress,
		htlcInputs,
		htlcLockByHMultiAddress,
		htlcLockByHMultiAddress,
		propertyId,
		amountToHtlc,
		getBtcMinerAmount(channelInfo.BtcAmount),
		0,
		&aliceHtlcRedeemScript)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	c2bBrRawData := bean.NeedClientSignTxData{}
	c2bBrRawData.Hex = hlockHexData["hex"].(string)
	c2bBrRawData.Inputs = hlockHexData["inputs"]
	c2bBrRawData.IsMultisig = true

	return &c2bBrRawData, nil
}

func saveHtlcLockByHTxAtPayerSide(tx storm.Node, channelInfo dao.ChannelInfo,
	commitmentTransaction *dao.CommitmentTransaction, signedHLockHex string, user bean.User) (henxTx *dao.HtlcLockTxByH, err error) {
	payeePubKey := channelInfo.PubKeyB
	if user.PeerId == channelInfo.PeerIdB {
		payeePubKey = channelInfo.PubKeyA
	}
	outputBean := make(map[string]interface{})
	outputBean["amount"] = commitmentTransaction.AmountToHtlc
	outputBean["otherSideChannelPubKey"] = payeePubKey

	hlockTx, err := createHtlcHLockTxObj(tx, user.PeerId, channelInfo, commitmentTransaction.HtlcH, *commitmentTransaction, outputBean, 0, user)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	htlcOutputs, err := getInputsForNextTxByParseTxHashVout(
		commitmentTransaction.HtlcTxHex,
		commitmentTransaction.HTLCMultiAddress,
		commitmentTransaction.HTLCMultiAddressScriptPubKey,
		commitmentTransaction.HTLCRedeemScript)
	if err != nil || len(htlcOutputs) == 0 {
		log.Println(err)
		return nil, err
	}

	hlockTx.Txid = omnicore.GetTxId(signedHLockHex)
	hlockTx.TxHex = signedHLockHex
	hlockTx.CreateAt = time.Now()
	hlockTx.CurrState = dao.TxInfoState_Create
	err = tx.Save(hlockTx)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	return hlockTx, err
}

// 创建和保存收款方的He的Raw交易
func saveHtlcHeTxForPayee(tx storm.Node, channelInfo dao.ChannelInfo, commitmentTransaction *dao.CommitmentTransaction, reqData bean.BobSignedHtlcSubTxOfC3b, c3bHlockHex string, user bean.User) (c3bHeRawData *bean.NeedClientSignTxData, err error) {
	he1b := &dao.HTLCTimeoutTxForAAndExecutionForB{}
	_ = tx.Select(
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("CommitmentTxId", commitmentTransaction.Id),
		q.Eq("Owner", user.PeerId)).First(he1b)

	payeeChannelPubKey := channelInfo.PubKeyB
	payerChannelPubkey := channelInfo.PubKeyA
	if user.PeerId == channelInfo.PeerIdA {
		payeeChannelPubKey = channelInfo.PubKeyA
		payerChannelPubkey = channelInfo.PubKeyB
	}

	c3bHlockMultiAddress, c3bHlockRedeemScript, c3bHlockAddrScriptPubKey, err := createMultiSig(commitmentTransaction.HtlcH, payeeChannelPubKey)
	if err != nil {
		return nil, err
	}

	c3bHeMultiAddress, redeemScript, scriptPubKey, err := createMultiSig(reqData.CurrHtlcTempAddressForHePubKey, payerChannelPubkey)
	if err != nil {
		return nil, err
	}

	c3bHlocOutputs, err := getInputsForNextTxByParseTxHashVout(c3bHlockHex, c3bHlockMultiAddress, c3bHlockAddrScriptPubKey, c3bHlockRedeemScript)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	c3bHeTx, err := omnicore.OmniCreateRawTransactionUseUnsendInput(
		c3bHlockMultiAddress,
		c3bHlocOutputs,
		c3bHeMultiAddress,
		c3bHeMultiAddress,
		channelInfo.PropertyId,
		commitmentTransaction.AmountToHtlc,
		getBtcMinerAmount(channelInfo.BtcAmount),
		0,
		&c3bHlockRedeemScript)
	if err != nil {
		log.Println(err)
		return nil, errors.New("fail to create HTD1b for C3b")
	}

	c3bHeRawData = &bean.NeedClientSignTxData{}
	c3bHeRawData.Hex = c3bHeTx["hex"].(string)
	c3bHeRawData.Inputs = c3bHeTx["inputs"]
	c3bHeRawData.IsMultisig = true
	c3bHeRawData.PubKeyA = commitmentTransaction.HtlcH
	c3bHeRawData.PubKeyB = payeeChannelPubKey

	if he1b.Id == 0 {
		he1b.InputHex = c3bHlockHex
		he1b.InputTxid = c3bHlocOutputs[0].Txid
		he1b.InputAmount = commitmentTransaction.AmountToHtlc

		he1b.RSMCTempAddressIndex = reqData.CurrHtlcTempAddressForHeIndex
		he1b.RSMCTempAddressPubKey = reqData.CurrHtlcTempAddressForHePubKey
		he1b.RSMCMultiAddress = c3bHeMultiAddress
		he1b.RSMCRedeemScript = redeemScript
		he1b.RSMCMultiAddressScriptPubKey = scriptPubKey
		he1b.RSMCOutAmount = commitmentTransaction.AmountToHtlc
		he1b.RSMCTxHex = c3bHeRawData.Hex

		he1b.ChannelId = channelInfo.ChannelId
		he1b.CommitmentTxId = commitmentTransaction.Id
		he1b.Owner = user.PeerId
		he1b.CreateBy = user.PeerId
		he1b.CreateAt = time.Now()
		he1b.CurrState = dao.TxInfoState_Init
		err = tx.Save(he1b)
		if err != nil {
			log.Println(err)
			return nil, err
		}
	}
	return c3bHeRawData, nil
}

// bob对He完成第一次签名，更新收款方的He交易
func updateHtlcHeTxForPayee(tx storm.Node, channelInfo dao.ChannelInfo, commitmentTransaction *dao.CommitmentTransaction, signedHex string) (err error) {
	he1b := &dao.HTLCTimeoutTxForAAndExecutionForB{}
	_ = tx.Select(
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("CurrState", dao.TxInfoState_Init),
		q.Eq("CommitmentTxId", commitmentTransaction.Id)).First(he1b)
	if he1b.Id == 0 {
		return errors.New("Not found he1b in the database")
	}
	he1b.RSMCTxid = omnicore.GetTxId(signedHex)
	he1b.RSMCTxHex = signedHex
	he1b.CurrState = dao.TxInfoState_Create
	err = tx.Update(he1b)
	if err != nil {
		log.Println(err)
		return err
	}
	return nil
}

// 付款方在42号协议，用签名完成toHtlc的Hex，就用这个完整交易Hex，构建C3b方的Hlock交易
func createHtlcLockByHForBobAtPayerSide(channelInfo dao.ChannelInfo, bobDataJson bean.NeedAliceSignHtlcTxOfC3bP2p, signedHtlcHex string, h string, payeeChannelPubKey string,
	aliceChannelPubKey string, propertyId int64, amountToHtlc float64) (txData bean.NeedClientSignTxData, err error) {
	bobHtlcMultiAddr, err := omnicore.CreateMultiSig(2, []string{bobDataJson.PayeeCurrHtlcTempAddressPubKey, aliceChannelPubKey})
	if err != nil {
		return txData, err
	}
	bobHtlcMultiAddress := gjson.Get(bobHtlcMultiAddr, "address").String()
	bobHtlcRedeemScript := gjson.Get(bobHtlcMultiAddr, "redeemScript").String()
	bobHtlcMultiAddressScriptPubKey := gjson.Get(bobHtlcMultiAddr, "scriptPubKey").String()

	htlcInputs, err := getInputsForNextTxByParseTxHashVout(signedHtlcHex, bobHtlcMultiAddress, bobHtlcMultiAddressScriptPubKey, bobHtlcRedeemScript)
	if err != nil {
		log.Println(err)
		return txData, err
	}

	htlcLockByHMultiAddr, err := omnicore.CreateMultiSig(2, []string{h, payeeChannelPubKey})
	if err != nil {
		return txData, err
	}
	htlcLockByHMultiAddress := gjson.Get(htlcLockByHMultiAddr, "address").String()
	hlockTx, err := omnicore.OmniCreateRawTransactionUseUnsendInput(
		bobHtlcMultiAddress,
		htlcInputs,
		htlcLockByHMultiAddress,
		htlcLockByHMultiAddress,
		propertyId,
		amountToHtlc,
		getBtcMinerAmount(channelInfo.BtcAmount),
		0,
		&bobHtlcRedeemScript)
	if err != nil {
		log.Println(err)
		return txData, err
	}

	c3bHlockRawData := bean.NeedClientSignTxData{}
	c3bHlockRawData.Hex = hlockTx["hex"].(string)
	c3bHlockRawData.Inputs = hlockTx["inputs"]
	c3bHlockRawData.IsMultisig = true
	c3bHlockRawData.PubKeyA = bobDataJson.PayeeCurrHtlcTempAddressPubKey
	c3bHlockRawData.PubKeyB = aliceChannelPubKey
	return c3bHlockRawData, nil
}

func saveHtlcLockByHForBobAtPayeeSide(tx storm.Node, channelInfo dao.ChannelInfo,
	commitmentTransaction *dao.CommitmentTransaction, signedHLockHex string, user bean.User) (henxTx *dao.HtlcLockTxByH, err error) {
	payeePubKey := channelInfo.PubKeyB
	if user.PeerId == channelInfo.PeerIdA {
		payeePubKey = channelInfo.PubKeyA
	}
	outputBean := make(map[string]interface{})
	outputBean["amount"] = commitmentTransaction.AmountToHtlc
	outputBean["otherSideChannelPubKey"] = payeePubKey

	hlock, err := createHtlcHLockTxObj(tx, user.PeerId, channelInfo, commitmentTransaction.HtlcH, *commitmentTransaction, outputBean, 0, user)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	hlock.Txid = omnicore.GetTxId(signedHLockHex)
	hlock.TxHex = signedHLockHex
	hlock.CreateAt = time.Now()
	hlock.CurrState = dao.TxInfoState_Create
	err = tx.Save(hlock)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	return hlock, err
}

func saveHtRD1a(tx storm.Node, aliceHt1aRDhex string, latestCommitmentTransaction dao.CommitmentTransaction, user bean.User) (rdTransaction *dao.RevocableDeliveryTransaction, err error) {
	ht1a := &dao.HTLCTimeoutTxForAAndExecutionForB{}
	err = tx.Select(
		q.Eq("ChannelId", latestCommitmentTransaction.ChannelId),
		q.Eq("CommitmentTxId", latestCommitmentTransaction.Id),
		q.Eq("Owner", user.PeerId)).
		First(ht1a)
	if err != nil {
		err = errors.New("not found ht1a")
		return nil, err
	}

	channelInfo := &dao.ChannelInfo{}
	err = tx.Select(q.Eq("ChannelId", latestCommitmentTransaction.ChannelId)).First(channelInfo)
	if err != nil {
		err = errors.New("not found channelInfo when save htrd1a")
		return nil, err
	}

	outAddress := channelInfo.AddressA
	if user.PeerId == channelInfo.PeerIdB {
		outAddress = channelInfo.AddressB
	}

	htrd := &dao.RevocableDeliveryTransaction{}
	err = tx.Select(
		q.Eq("ChannelId", latestCommitmentTransaction.ChannelId),
		q.Eq("CommitmentTxId", ht1a.Id),
		q.Eq("Owner", user.PeerId)).
		First(htrd)
	if htrd.Id == 0 {
		htrd, err = createHtlcRDTxObj(user.PeerId, channelInfo, ht1a, outAddress, &user)
		if err != nil {
			log.Println(err)
			return nil, err
		}
		htrd.Txid = omnicore.GetTxId(aliceHt1aRDhex)
		htrd.TxHex = aliceHt1aRDhex
		htrd.SignAt = time.Now()
		htrd.CurrState = dao.TxInfoState_CreateAndSign
		err = tx.Save(htrd)
	}
	return htrd, nil
}


<|start_filename|>omnicore/ParseString_test.go<|end_filename|>
package omnicore

import (
	"fmt"
	"testing"
)

func TestSubstring(t *testing.T) {
	str := "i dont know how to get substring	"
	strRightOfDecimal := str[0 : len(str)-1]
	fmt.Println(len(str))
	fmt.Println(strRightOfDecimal)

}

func TestStrToInt64(t *testing.T) {

	// divisible
	// 0 decimal
	str := "1000"
	number := StrToInt64(str, true)
	fmt.Printf("%v \n", number)

	// divisible
	// < 8 decimal
	str = "1000.0001"
	number = StrToInt64(str, true)
	fmt.Printf("%v \n", number)

	//  < 8 decimal
	str = "1000.000001"
	number = StrToInt64(str, true)
	fmt.Printf("%v \n", number)

	//  = 8 decimal
	str = "1000.00000001"
	number = StrToInt64(str, true)
	fmt.Printf("%v \n", number)

	//  > 8 decimal
	str = "1000.000000001"
	number = StrToInt64(str, true)
	fmt.Printf("%v \n", number)

	// indivisible
	// has decimal
	fmt.Println("Test indivisible")

	str = "1000.0001"
	number = StrToInt64(str, false)
	fmt.Printf("%v \n", number)

	str = "100000000000"
	number = StrToInt64(str, false)
	fmt.Printf("%v \n", number)

	// divisible
	// has decimal
	fmt.Println("Test divisible: 0.0001")
	fmt.Println("Expect: 10000")

	str = "0.0001"
	number = StrToInt64(str, true)
	fmt.Printf("%v \n", number)

	// negtive
	fmt.Println("Test negtive")

	str = "-1000.0001"
	number = StrToInt64(str, false)
	fmt.Printf("%v \n", number)

}

func TestAmountFromValue(t *testing.T) {
	fmt.Printf("%v \n", AmountFromValue("0.006"))
}


<|start_filename|>omnicore/DecodeRawTransaction.go<|end_filename|>
package omnicore

import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/btcsuite/btcd/txscript"

	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/btcjson"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
)

// witnessToHex formats the passed witness stack as a slice of hex-encoded
// strings to be used in a JSON response.
func witnessToHex(witness wire.TxWitness) []string {
	// Ensure nil is returned when there are no entries versus an empty
	// slice so it can properly be omitted as necessary.
	if len(witness) == 0 {
		return nil
	}

	result := make([]string, 0, len(witness))
	for _, wit := range witness {
		result = append(result, hex.EncodeToString(wit))
	}

	return result
}

type RawTxDecodeResult struct {
	Txid     string         `json:"txid"`
	Version  int32          `json:"version"`
	Locktime uint32         `json:"locktime"`
	Vin      []btcjson.Vin  `json:"vin"`
	Vout     []btcjson.Vout `json:"vout"`
}

// createVinList returns a slice of JSON objects for the inputs of the passed
// transaction.
//
// copied from btcd/rpcserver.go
func createVinList(mtx *wire.MsgTx) []btcjson.Vin {
	// Coinbase transactions only have a single txin by definition.
	vinList := make([]btcjson.Vin, len(mtx.TxIn))
	if blockchain.IsCoinBaseTx(mtx) {
		txIn := mtx.TxIn[0]
		vinList[0].Coinbase = hex.EncodeToString(txIn.SignatureScript)
		vinList[0].Sequence = txIn.Sequence
		vinList[0].Witness = witnessToHex(txIn.Witness)
		return vinList
	}

	for i, txIn := range mtx.TxIn {
		// The disassembled string will contain [error] inline
		// if the script doesn't fully parse, so ignore the
		// error here.
		disbuf, _ := txscript.DisasmString(txIn.SignatureScript)

		vinEntry := &vinList[i]
		vinEntry.Txid = txIn.PreviousOutPoint.Hash.String()
		vinEntry.Vout = txIn.PreviousOutPoint.Index
		vinEntry.Sequence = txIn.Sequence
		vinEntry.ScriptSig = &btcjson.ScriptSig{
			Asm: disbuf,
			Hex: hex.EncodeToString(txIn.SignatureScript),
		}

		if mtx.HasWitness() {
			vinEntry.Witness = witnessToHex(txIn.Witness)
		}
	}

	return vinList
}

// createVoutList returns a slice of JSON objects for the outputs of the passed
// transaction.
//
// copied from btcd/rpcserver.go
func createVoutList(mtx *wire.MsgTx, chainParams *chaincfg.Params, filterAddrMap map[string]struct{}) []btcjson.Vout {
	voutList := make([]btcjson.Vout, 0, len(mtx.TxOut))
	for i, v := range mtx.TxOut {
		// The disassembled string will contain [error] inline if the
		// script doesn't fully parse, so ignore the error here.
		disbuf, _ := txscript.DisasmString(v.PkScript)

		// Ignore the error here since an error means the script
		// couldn't parse and there is no additional information about
		// it anyways.
		scriptClass, addrs, reqSigs, _ := txscript.ExtractPkScriptAddrs(
			v.PkScript, chainParams)

		// Encode the addresses while checking if the address passes the
		// filter when needed.
		passesFilter := len(filterAddrMap) == 0
		encodedAddrs := make([]string, len(addrs))
		for j, addr := range addrs {
			encodedAddr := addr.EncodeAddress()
			encodedAddrs[j] = encodedAddr

			// No need to check the map again if the filter already
			// passes.
			if passesFilter {
				continue
			}
			if _, exists := filterAddrMap[encodedAddr]; exists {
				passesFilter = true
			}
		}

		if !passesFilter {
			continue
		}

		var vout btcjson.Vout
		vout.N = uint32(i)
		vout.Value = btcutil.Amount(v.Value).ToBTC()
		vout.ScriptPubKey.Addresses = encodedAddrs
		vout.ScriptPubKey.Asm = disbuf
		vout.ScriptPubKey.Hex = hex.EncodeToString(v.PkScript)
		vout.ScriptPubKey.Type = scriptClass.String()
		vout.ScriptPubKey.ReqSigs = int32(reqSigs)

		voutList = append(voutList, vout)
	}

	return voutList
}

func DecodeRawTransaction(hexadecimal_str string, chainParams *chaincfg.Params) string {
	tx := wire.MsgTx{}
	bytes_arr, _ := hex.DecodeString(hexadecimal_str)

	if err := tx.Deserialize(bytes.NewReader(bytes_arr)); err != nil {
		fmt.Println("DecodeRawTransaction(...): error deserializing tx")
	}

	// Create and return the result.

	txReply := RawTxDecodeResult{
		Txid:     tx.TxHash().String(),
		Version:  tx.Version,
		Locktime: tx.LockTime,
		Vin:      createVinList(&tx),
		Vout:     createVoutList(&tx, chainParams, nil),
	}

	json_reply, _ := json.Marshal(txReply)
	return string(json_reply)
	//return string(txReply)

}

func VerfyOpreturnPayload(opreturn_str string, property_id_expected string, amount_expected string, devisible_expected bool) bool {

	payload, _ := Omni_createpayload_simplesend(property_id_expected, amount_expected, devisible_expected)
	outputs := OmniCore_Encode_ClassC(payload)
	//output_str := string(outputs[:])
	output_hex := hex.EncodeToString(outputs)

	if strings.Compare(opreturn_str, output_hex) == 0 {
		//fmt.Println("succeed in 4) Attach reference/receiver output")
		return true
	} else {
		return false
	}

}


<|start_filename|>service/common_service.go<|end_filename|>
package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/config"
	"github.com/omnilaboratory/obd/conn"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/tool"
	"github.com/shopspring/decimal"
	"log"
	"strings"
	"time"

	"github.com/asdine/storm"
	"github.com/tidwall/gjson"
)

func findUserIsOnline(nodePeerId, userPeerId string) error {
	if tool.CheckIsString(&userPeerId) {
		value, exists := OnlineUserMap[userPeerId]
		if exists && value != nil {
			return nil
		}
		if nodePeerId != P2PLocalNodeId {
			if conn2tracker.GetUserState(nodePeerId, userPeerId) > 0 {
				return nil
			}
		}
	}
	return errors.New(fmt.Sprintf(enum.Tips_user_notExistOrOnline, userPeerId))
}

func checkBtcFundFinish(tx storm.Node, channel dao.ChannelInfo, isFundOmni bool) error {
	if channel.CurrState > bean.ChannelState_WaitFundAsset {
		return nil
	}

	count, err := tx.Select(q.Eq("TemporaryChannelId", channel.TemporaryChannelId), q.Eq("IsFinish", true), q.Eq("Owner", channel.CreateBy)).Count(&dao.MinerFeeRedeemTransaction{})
	if err != nil {
		return err
	}
	//log.Println("listunspent", array)
	if count < config.BtcNeedFundTimes {
		return errors.New(enum.Tips_funding_notEnoughBtcFundingTime)
	}

	return nil
}

func getAddressFromPubKey(pubKey string) (address string, err error) {
	if tool.CheckIsString(&pubKey) == false {
		return "", errors.New(enum.Tips_common_empty + "pubKey")
	}
	address, err = tool.GetAddressFromPubKey(pubKey)
	if err != nil {
		return "", err
	}
	return address, nil
}

func createCommitmentTx(owner string, channelInfo *dao.ChannelInfo, fundingTransaction *dao.FundingTransaction, outputBean commitmentTxOutputBean, user *bean.User) (*dao.CommitmentTransaction, error) {
	commitmentTxInfo := &dao.CommitmentTransaction{}
	commitmentTxInfo.PeerIdA = channelInfo.PeerIdA
	commitmentTxInfo.PeerIdB = channelInfo.PeerIdB
	commitmentTxInfo.ChannelId = channelInfo.ChannelId
	commitmentTxInfo.PropertyId = fundingTransaction.PropertyId
	commitmentTxInfo.Owner = owner

	//input
	commitmentTxInfo.InputTxid = fundingTransaction.FundingTxid
	commitmentTxInfo.InputVout = fundingTransaction.FundingOutputIndex
	commitmentTxInfo.InputAmount = fundingTransaction.AmountA + fundingTransaction.AmountB

	//output to rsmc
	commitmentTxInfo.RSMCTempAddressPubKey = outputBean.RsmcTempPubKey
	multiAddr, err := omnicore.CreateMultiSig(2, []string{commitmentTxInfo.RSMCTempAddressPubKey, outputBean.OppositeSideChannelPubKey})
	if err != nil {
		return nil, err
	}
	commitmentTxInfo.RSMCMultiAddress = gjson.Get(multiAddr, "address").String()
	commitmentTxInfo.RSMCRedeemScript = gjson.Get(multiAddr, "redeemScript").String()
	commitmentTxInfo.RSMCMultiAddressScriptPubKey = gjson.Get(multiAddr, "scriptPubKey").String()

	if tool.CheckIsString(&outputBean.HtlcTempPubKey) {
		commitmentTxInfo.HTLCTempAddressPubKey = outputBean.HtlcTempPubKey
		multiAddr, err := omnicore.CreateMultiSig(2, []string{commitmentTxInfo.HTLCTempAddressPubKey, outputBean.OppositeSideChannelPubKey})
		if err != nil {
			return nil, err
		}
		commitmentTxInfo.HTLCMultiAddress = gjson.Get(multiAddr, "address").String()
		commitmentTxInfo.HTLCRedeemScript = gjson.Get(multiAddr, "redeemScript").String()
		commitmentTxInfo.HTLCMultiAddressScriptPubKey = gjson.Get(multiAddr, "scriptPubKey").String()
	}

	commitmentTxInfo.AmountToRSMC = outputBean.AmountToRsmc
	commitmentTxInfo.AmountToCounterparty = outputBean.AmountToCounterparty
	commitmentTxInfo.AmountToHtlc = outputBean.AmountToHtlc

	commitmentTxInfo.CreateBy = user.PeerId
	commitmentTxInfo.CreateAt = time.Now()
	commitmentTxInfo.LastEditTime = time.Now()

	return commitmentTxInfo, nil
}

func createRDTx(owner string, channelInfo *dao.ChannelInfo, commitmentTxInfo *dao.CommitmentTransaction, toAddress string, user *bean.User) (*dao.RevocableDeliveryTransaction, error) {
	rda := &dao.RevocableDeliveryTransaction{}

	rda.CommitmentTxId = commitmentTxInfo.Id
	rda.PeerIdA = channelInfo.PeerIdA
	rda.PeerIdB = channelInfo.PeerIdB
	rda.ChannelId = channelInfo.ChannelId
	rda.PropertyId = commitmentTxInfo.PropertyId
	rda.Owner = owner

	//input
	rda.InputTxHex = commitmentTxInfo.RSMCTxHex
	rda.InputTxid = commitmentTxInfo.RSMCTxid
	rda.InputVout = 0
	rda.InputAmount = commitmentTxInfo.AmountToRSMC
	//output
	rda.OutputAddress = toAddress
	rda.Sequence = 1000
	rda.Amount = commitmentTxInfo.AmountToRSMC

	rda.CreateBy = user.PeerId
	rda.CreateAt = time.Now()
	rda.LastEditTime = time.Now()

	return rda, nil
}

func createBRTxObj(owner string, channelInfo *dao.ChannelInfo, brType dao.BRType, commitmentTxInfo *dao.CommitmentTransaction, user *bean.User) (*dao.BreachRemedyTransaction, error) {
	breachRemedyTransaction := &dao.BreachRemedyTransaction{}
	breachRemedyTransaction.CommitmentTxId = commitmentTxInfo.Id
	breachRemedyTransaction.PeerIdA = channelInfo.PeerIdA
	breachRemedyTransaction.PeerIdB = channelInfo.PeerIdB
	breachRemedyTransaction.ChannelId = channelInfo.ChannelId
	breachRemedyTransaction.PropertyId = commitmentTxInfo.PropertyId
	breachRemedyTransaction.Owner = owner
	breachRemedyTransaction.Type = brType

	//input
	breachRemedyTransaction.TempPubKey = commitmentTxInfo.RSMCTempAddressPubKey
	breachRemedyTransaction.InputAddress = commitmentTxInfo.RSMCMultiAddress
	breachRemedyTransaction.InputAddressScriptPubKey = commitmentTxInfo.RSMCMultiAddressScriptPubKey
	breachRemedyTransaction.InputRedeemScript = commitmentTxInfo.RSMCRedeemScript
	breachRemedyTransaction.InputTxHex = commitmentTxInfo.RSMCTxHex
	breachRemedyTransaction.InputTxid = commitmentTxInfo.RSMCTxid
	breachRemedyTransaction.InputVout = 0
	breachRemedyTransaction.InputAmount = commitmentTxInfo.AmountToRSMC
	//output
	breachRemedyTransaction.Amount = commitmentTxInfo.AmountToRSMC

	breachRemedyTransaction.CreateBy = user.PeerId
	breachRemedyTransaction.CreateAt = time.Now()
	breachRemedyTransaction.LastEditTime = time.Now()

	return breachRemedyTransaction, nil
}

func checkBtcTxHex(btcFeeTxHexDecode string, channelInfo *dao.ChannelInfo, peerId string) (fundingTxid string, amountA float64, fundingOutputIndex uint32, err error) {
	jsonFundingTxHexDecode := gjson.Parse(btcFeeTxHexDecode)
	fundingTxid = jsonFundingTxHexDecode.Get("txid").String()

	//vin
	if jsonFundingTxHexDecode.Get("vin").IsArray() == false {
		err = errors.New(enum.Tips_funding_noVin)
		log.Println(err)
		return "", 0, 0, err
	}

	vin1 := jsonFundingTxHexDecode.Get("vin").Array()[0]
	asm := vin1.Get("scriptSig").Get("asm").Str
	if len(asm) == 0 {
		return "", 0, 0, errors.New("wrong vin asm")
	}
	split := strings.Split(asm, " ")
	if split[0] == "0" {
		return "", 0, 0, errors.New(enum.Tips_funding_noVin)
	}

	inTxid := vin1.Get("txid").String()
	inputTx := conn2tracker.GetTransactionById(inTxid)
	if err != nil {
		err = errors.New(enum.Tips_funding_wrongBtcHexVin + err.Error())
		log.Println(err)
		return "", 0, 0, err
	}

	jsonInputTxDecode := gjson.Parse(inputTx)
	flag := false
	inputHexDecode, err := omnicore.DecodeBtcRawTransaction(jsonInputTxDecode.Get("hex").String())
	if err != nil {
		err = errors.New(enum.Tips_funding_wrongBtcHexVin + err.Error())
		log.Println(err)
		return "", 0, 0, err
	}

	funderAddress := channelInfo.AddressA
	if peerId == channelInfo.PeerIdB {
		funderAddress = channelInfo.AddressB
	}
	jsonInputHexDecode := gjson.Parse(inputHexDecode)
	if jsonInputHexDecode.Get("vout").IsArray() {
		for _, item := range jsonInputHexDecode.Get("vout").Array() {
			addresses := item.Get("scriptPubKey").Get("addresses").Array()
			for _, subItem := range addresses {
				if subItem.String() == funderAddress {
					flag = true
					break
				}
			}
			if flag {
				break
			}
		}
	}

	if flag == false {
		log.Println(inputHexDecode)
		err = errors.New(enum.Tips_funding_wrongFunderAddressFromBtcHex)
		log.Println(err)
		return "", 0, 0, err
	}

	//vout
	flag = false
	if jsonFundingTxHexDecode.Get("vout").IsArray() == false {
		err = errors.New(enum.Tips_funding_notFoundVout)
		log.Println(err)
		return "", 0, 0, err
	}
	for _, item := range jsonFundingTxHexDecode.Get("vout").Array() {
		addresses := item.Get("scriptPubKey").Get("addresses").Array()
		for _, subItem := range addresses {
			if subItem.String() == channelInfo.ChannelAddress {
				amountA = item.Get("value").Float()
				fundingOutputIndex = uint32(item.Get("n").Int())
				flag = true
				break
			}
		}
		if flag {
			break
		}
	}
	if flag == false {
		log.Println(jsonFundingTxHexDecode)
		err = errors.New(enum.Tips_funding_wrongChannelAddressFromBtcHex)
		log.Println(err)
		return "", 0, 0, err
	}
	return fundingTxid, amountA, fundingOutputIndex, err
}

func checkOmniTxHex(fundingTxHexDecode string, channelInfo *dao.ChannelInfo, user string) (fundingTxid string, amountA float64, propertyId int64, err error) {
	jsonOmniTxHexDecode := gjson.Parse(fundingTxHexDecode)
	fundingTxid = jsonOmniTxHexDecode.Get("txid").String()

	funderAddress := channelInfo.FundingAddress

	sendingAddress := jsonOmniTxHexDecode.Get("sendingaddress").String()
	if sendingAddress != funderAddress {
		err = errors.New(fmt.Sprintf(enum.Tips_funding_wrongFunderAddressFromAssetHex, sendingAddress))
		log.Println(err)
		return "", 0, 0, err
	}
	referenceAddress := jsonOmniTxHexDecode.Get("referenceaddress").String()
	if referenceAddress != channelInfo.ChannelAddress {
		err = errors.New(fmt.Sprintf(enum.Tips_funding_wrongChannelAddressFromAssetHex, referenceAddress, channelInfo.ChannelAddress))
		log.Println(err)
		return "", 0, 0, err
	}

	amountA = jsonOmniTxHexDecode.Get("amount").Float()
	propertyId = jsonOmniTxHexDecode.Get("propertyid").Int()

	return fundingTxid, amountA, propertyId, err
}

//从未广播的交易hash数据中解析出他的输出，以此作为下个交易的输入
func getInputsForNextTxByParseTxHashVout(hex string, toAddress, scriptPubKey, redeemScript string) (inputs []bean.TransactionInputItem, err error) {
	result, err := omnicore.DecodeBtcRawTransaction(hex)
	if err != nil {
		return nil, err
	}
	jsonHex := gjson.Parse(result)
	//log.Println(jsonHex)
	if jsonHex.Get("vout").IsArray() {
		inputs = make([]bean.TransactionInputItem, 0, 0)
		for _, item := range jsonHex.Get("vout").Array() {
			if item.Get("scriptPubKey").Get("addresses").Exists() {
				addresses := item.Get("scriptPubKey").Get("addresses").Array()
				for _, address := range addresses {
					if address.String() == toAddress {
						node := bean.TransactionInputItem{}
						node.Txid = jsonHex.Get("txid").String()
						node.ScriptPubKey = scriptPubKey
						node.RedeemScript = redeemScript
						node.Vout = uint32(item.Get("n").Uint())
						node.Amount = item.Get("value").Float()
						if node.Amount > 0 {
							inputs = append(inputs, node)
						}
					}
				}
			}
		}
		if len(inputs) > 0 {
			return inputs, nil
		}
	}
	return nil, errors.New(enum.Tips_common_failToParseInputsFromUnsendTx)
}

func getLatestCommitmentTxUseDbTx(tx storm.Node, channelId string, owner string) (commitmentTxInfo *dao.CommitmentTransaction, err error) {
	commitmentTxInfo = &dao.CommitmentTransaction{}
	err = tx.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("Owner", owner)).
		OrderBy("CreateAt").Reverse().First(commitmentTxInfo)
	return commitmentTxInfo, err
}

//根据通道id获取通道信息
func getChannelInfoByChannelId(tx storm.Node, channelId string, userPeerId string) (channelInfo *dao.ChannelInfo) {
	channelInfo = &dao.ChannelInfo{}
	err := tx.Select(
		q.Eq("ChannelId", channelId),
		q.Or(
			q.Eq("PeerIdA", userPeerId),
			q.Eq("PeerIdB", userPeerId)),
		q.Or(
			q.Eq("CurrState", bean.ChannelState_CanUse),
			q.Eq("CurrState", bean.ChannelState_LockByTracker),
			q.Eq("CurrState", bean.ChannelState_NewTx))).
		First(channelInfo)
	if err != nil {
		return nil
	}
	return channelInfo
}

func getLockChannelForHtlc(tx storm.Node, channelId string, userPeerId string) (channelInfo *dao.ChannelInfo) {
	channelInfo = &dao.ChannelInfo{}
	_ = tx.Select(
		q.Eq("ChannelId", channelId),
		q.Or(
			q.Eq("PeerIdA", userPeerId),
			q.Eq("PeerIdB", userPeerId)),
		q.Or(
			q.Eq("CurrState", bean.ChannelState_CanUse),
			q.Eq("CurrState", bean.ChannelState_LockByTracker))).
		First(channelInfo)
	return channelInfo
}

//根据通道id获取通道信息
func getFundingTransactionByChannelId(dbTx storm.Node, channelId string, userPeerId string) (fundingTransaction *dao.FundingTransaction) {
	fundingTransaction = &dao.FundingTransaction{}
	err := dbTx.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("CurrState", dao.FundingTransactionState_Accept),
		q.Or(
			q.Eq("PeerIdA", userPeerId),
			q.Eq("PeerIdB", userPeerId))).
		OrderBy("CreateAt").
		Reverse().First(fundingTransaction)
	if err != nil {
		return nil
	}
	return fundingTransaction
}

func saveRdTx(tx storm.Node, channelInfo *dao.ChannelInfo, signedRsmcHex string, signedRdHex string, latestCommitmentTxInfo *dao.CommitmentTransaction, outputAddress string, user *bean.User) (err error) {
	inputs, err := getInputsForNextTxByParseTxHashVout(signedRsmcHex, latestCommitmentTxInfo.RSMCMultiAddress, latestCommitmentTxInfo.RSMCMultiAddressScriptPubKey, latestCommitmentTxInfo.RSMCRedeemScript)
	if err != nil || len(inputs) == 0 {
		log.Println(err)
		return err
	}

	aliceRdTxid := checkHexOutputAddressFromOmniDecode(signedRdHex, outputAddress)
	if aliceRdTxid == "" {
		return errors.New(enum.Tips_common_wrongAddressOfRD)
	}
	rdTransaction, err := createRDTx(user.PeerId, channelInfo, latestCommitmentTxInfo, outputAddress, user)
	if err != nil {
		log.Println(err)
		return err
	}
	rdTransaction.RDType = 0
	rdTransaction.TxHex = signedRdHex
	rdTransaction.Txid = aliceRdTxid
	rdTransaction.CurrState = dao.TxInfoState_CreateAndSign
	rdTransaction.SignAt = time.Now()
	err = tx.Save(rdTransaction)
	if err != nil {
		log.Println(err)
		return err
	}
	return nil
}

func saveHTD1bTx(tx storm.Node, signedHtlcHex string, signedHtd1bHex string, latestCommitmentTxInfo dao.CommitmentTransaction, outputAddress string, user *bean.User) (err error) {
	inputs, err := getInputsForNextTxByParseTxHashVout(signedHtlcHex, latestCommitmentTxInfo.HTLCMultiAddress, latestCommitmentTxInfo.HTLCMultiAddressScriptPubKey, latestCommitmentTxInfo.HTLCRedeemScript)
	if err != nil || len(inputs) == 0 {
		log.Println(err)
		return err
	}

	owner := latestCommitmentTxInfo.PeerIdA
	if user.PeerId == latestCommitmentTxInfo.PeerIdA {
		owner = latestCommitmentTxInfo.PeerIdB
	}

	htlcTimeOut := latestCommitmentTxInfo.HtlcCltvExpiry
	htlcTimeoutDeliveryTx := &dao.HTLCTimeoutDeliveryTxB{}
	htlcTimeoutDeliveryTx.ChannelId = latestCommitmentTxInfo.ChannelId
	htlcTimeoutDeliveryTx.CommitmentTxId = latestCommitmentTxInfo.Id
	htlcTimeoutDeliveryTx.PropertyId = latestCommitmentTxInfo.PropertyId
	htlcTimeoutDeliveryTx.OutputAddress = outputAddress
	htlcTimeoutDeliveryTx.InputTxid = latestCommitmentTxInfo.HTLCTxid
	htlcTimeoutDeliveryTx.InputHex = latestCommitmentTxInfo.HtlcTxHex
	htlcTimeoutDeliveryTx.OutAmount = latestCommitmentTxInfo.AmountToHtlc
	htlcTimeoutDeliveryTx.Owner = owner
	htlcTimeoutDeliveryTx.CurrState = dao.TxInfoState_CreateAndSign
	htlcTimeoutDeliveryTx.CreateBy = user.PeerId
	htlcTimeoutDeliveryTx.Timeout = htlcTimeOut
	htlcTimeoutDeliveryTx.CreateAt = time.Now()

	htlcTimeoutDeliveryTx.Txid = omnicore.GetTxId(signedHtd1bHex)
	htlcTimeoutDeliveryTx.TxHex = signedHtd1bHex
	err = tx.Save(htlcTimeoutDeliveryTx)
	if err != nil {
		log.Println(err)
		return err
	}
	return nil
}

func createMultiSig(pubkey1 string, pubkey2 string) (multiAddress, redeemScript, scriptPubKey string, err error) {
	aliceRsmcMultiAddr, err := omnicore.CreateMultiSig(2, []string{pubkey1, pubkey2})
	if err != nil {
		return "", "", "", err
	}
	multiAddress = gjson.Get(aliceRsmcMultiAddr, "address").String()
	redeemScript = gjson.Get(aliceRsmcMultiAddr, "redeemScript").String()
	scriptPubKey = gjson.Get(aliceRsmcMultiAddr, "scriptPubKey").String()
	return multiAddress, redeemScript, scriptPubKey, nil
}

func createCommitmentTxHex(dbTx storm.Node, isSender bool, reqData *bean.RequestCreateCommitmentTx, channelInfo *dao.ChannelInfo, lastCommitmentTx *dao.CommitmentTransaction, currUser bean.User) (commitmentTxInfo *dao.CommitmentTransaction, rawTx dao.CommitmentTxRawTx, err error) {
	//1、转账给bob的交易：输入：通道其中一个input，输出：给bob
	//2、转账后的余额的交易：输入：通道总的一个input,输出：一个多签地址，这个钱又需要后续的RD才能赎回
	// create Cna tx
	fundingTransaction := getFundingTransactionByChannelId(dbTx, channelInfo.ChannelId, currUser.PeerId)
	if fundingTransaction == nil {
		err = errors.New(enum.Tips_funding_notFoundFundAssetTx)
		return nil, rawTx, err
	}

	var outputBean = commitmentTxOutputBean{}
	outputBean.RsmcTempPubKey = reqData.CurrTempAddressPubKey
	if currUser.PeerId == channelInfo.PeerIdA {
		//default alice transfer to bob ,then alice minus money
		outputBean.AmountToRsmc, _ = decimal.NewFromFloat(fundingTransaction.AmountA).Sub(decimal.NewFromFloat(reqData.Amount)).Round(8).Float64()
		outputBean.AmountToCounterparty, _ = decimal.NewFromFloat(fundingTransaction.AmountB).Add(decimal.NewFromFloat(reqData.Amount)).Round(8).Float64()
		outputBean.OppositeSideChannelAddress = channelInfo.AddressB
		outputBean.OppositeSideChannelPubKey = channelInfo.PubKeyB
	} else {
		outputBean.AmountToRsmc, _ = decimal.NewFromFloat(fundingTransaction.AmountB).Add(decimal.NewFromFloat(reqData.Amount)).Round(8).Float64()
		outputBean.AmountToCounterparty, _ = decimal.NewFromFloat(fundingTransaction.AmountA).Sub(decimal.NewFromFloat(reqData.Amount)).Round(8).Float64()
		outputBean.OppositeSideChannelAddress = channelInfo.AddressA
		outputBean.OppositeSideChannelPubKey = channelInfo.PubKeyA
	}

	if lastCommitmentTx != nil && lastCommitmentTx.Id > 0 {
		if isSender {
			outputBean.AmountToRsmc, _ = decimal.NewFromFloat(lastCommitmentTx.AmountToRSMC).Sub(decimal.NewFromFloat(reqData.Amount)).Round(8).Float64()
			outputBean.AmountToCounterparty, _ = decimal.NewFromFloat(lastCommitmentTx.AmountToCounterparty).Add(decimal.NewFromFloat(reqData.Amount)).Round(8).Float64()
		} else {
			outputBean.AmountToRsmc, _ = decimal.NewFromFloat(lastCommitmentTx.AmountToRSMC).Add(decimal.NewFromFloat(reqData.Amount)).Round(8).Float64()
			outputBean.AmountToCounterparty, _ = decimal.NewFromFloat(lastCommitmentTx.AmountToCounterparty).Sub(decimal.NewFromFloat(reqData.Amount)).Round(8).Float64()
		}
	}

	if lastCommitmentTx.TxType == dao.CommitmentTransactionType_Htlc {
		if lastCommitmentTx.CurrState == dao.TxInfoState_Htlc_GetH {
			if lastCommitmentTx.HtlcSender == currUser.PeerId {
				outputBean.AmountToRsmc, _ = decimal.NewFromFloat(lastCommitmentTx.AmountToRSMC).Add(decimal.NewFromFloat(lastCommitmentTx.AmountToHtlc)).Round(8).Float64()
			} else {
				outputBean.AmountToCounterparty, _ = decimal.NewFromFloat(lastCommitmentTx.AmountToCounterparty).Add(decimal.NewFromFloat(lastCommitmentTx.AmountToHtlc)).Round(8).Float64()
			}
			//	TxInfoState_Htlc_GetR State
		} else {
			if lastCommitmentTx.HtlcSender == currUser.PeerId {
				outputBean.AmountToCounterparty, _ = decimal.NewFromFloat(lastCommitmentTx.AmountToCounterparty).Add(decimal.NewFromFloat(lastCommitmentTx.AmountToHtlc)).Round(8).Float64()
			} else {
				outputBean.AmountToRsmc, _ = decimal.NewFromFloat(lastCommitmentTx.AmountToRSMC).Add(decimal.NewFromFloat(lastCommitmentTx.AmountToHtlc)).Round(8).Float64()
			}
		}
	}
	commitmentTxInfo, err = createCommitmentTx(currUser.PeerId, channelInfo, fundingTransaction, outputBean, &currUser)
	if err != nil {
		log.Println(err)
		return nil, rawTx, err
	}

	listUnspent, err := GetAddressListUnspent(dbTx, *channelInfo)
	if err != nil {
		return nil, rawTx, err
	}

	commitmentTxInfo.TxType = dao.CommitmentTransactionType_Rsmc
	commitmentTxInfo.RSMCTempAddressIndex = reqData.CurrTempAddressIndex
	rawTx = dao.CommitmentTxRawTx{}
	usedTxidTemp := ""
	if commitmentTxInfo.AmountToRSMC > 0 {
		rsmcTxData, usedTxid, err := omnicore.OmniCreateRawTransactionUseSingleInput(
			listUnspent,
			channelInfo.ChannelAddress,
			commitmentTxInfo.RSMCMultiAddress,
			fundingTransaction.PropertyId,
			commitmentTxInfo.AmountToRSMC,
			0,
			0, &channelInfo.ChannelAddressRedeemScript, "")
		if err != nil {
			log.Println(err)
			return nil, rawTx, err
		}

		usedTxidTemp = usedTxid
		commitmentTxInfo.RsmcInputTxid = usedTxid
		commitmentTxInfo.RSMCTxHex = rsmcTxData["hex"].(string)

		signHexData := bean.NeedClientSignTxData{}
		signHexData.Hex = commitmentTxInfo.RSMCTxHex
		signHexData.Inputs = rsmcTxData["inputs"]
		signHexData.IsMultisig = true
		signHexData.PubKeyA = channelInfo.PubKeyA
		signHexData.PubKeyB = channelInfo.PubKeyB
		rawTx.RsmcRawTxData = signHexData
	}

	//create to Counterparty tx
	if commitmentTxInfo.AmountToCounterparty > 0 {
		toBobTxData, err := omnicore.OmniCreateRawTransactionUseRestInput(
			int(commitmentTxInfo.TxType),
			listUnspent,
			channelInfo.ChannelAddress,
			usedTxidTemp,
			outputBean.OppositeSideChannelAddress,
			fundingTransaction.FunderAddress,
			fundingTransaction.PropertyId,
			commitmentTxInfo.AmountToCounterparty,
			getBtcMinerAmount(channelInfo.BtcAmount),
			&channelInfo.ChannelAddressRedeemScript)
		if err != nil {
			log.Println(err)
			return nil, rawTx, err
		}
		commitmentTxInfo.ToCounterpartyTxHex = toBobTxData["hex"].(string)

		signHexData := bean.NeedClientSignTxData{}
		signHexData.Hex = commitmentTxInfo.ToCounterpartyTxHex
		signHexData.Inputs = toBobTxData["inputs"]
		signHexData.IsMultisig = true
		signHexData.PubKeyA = channelInfo.PubKeyA
		signHexData.PubKeyB = channelInfo.PubKeyB
		rawTx.ToCounterpartyRawTxData = signHexData
	}
	commitmentTxInfo.LastHash = ""
	commitmentTxInfo.CurrHash = ""
	if lastCommitmentTx != nil && lastCommitmentTx.Id > 0 {
		commitmentTxInfo.LastCommitmentTxId = lastCommitmentTx.Id
		commitmentTxInfo.LastHash = lastCommitmentTx.CurrHash
	}
	commitmentTxInfo.CurrState = dao.TxInfoState_Create
	err = dbTx.Save(commitmentTxInfo)
	if err != nil {
		log.Println(err)
		return nil, rawTx, err
	}

	rawTx.CommitmentTxId = commitmentTxInfo.Id
	_ = dbTx.Save(rawTx)

	bytes, err := json.Marshal(commitmentTxInfo)
	msgHash := tool.SignMsgWithSha256(bytes)
	commitmentTxInfo.CurrHash = msgHash
	err = dbTx.Update(commitmentTxInfo)
	if err != nil {
		log.Println(err)
		return nil, rawTx, err
	}
	return commitmentTxInfo, rawTx, nil
}

func GetBtcMinerFundMiniAmount() float64 {
	out, _ := decimal.NewFromFloat(omnicore.GetMinerFee(10)).Add(decimal.NewFromFloat(2 * tool.GetOmniDustBtc())).Mul(decimal.NewFromFloat(4.0)).Round(8).Float64()
	return out
}

func getBtcMinerAmount(total float64) float64 {
	return tool.GetBtcMinerAmount(total)
}

func checkChannelOmniAssetAmount(channelInfo dao.ChannelInfo) (bool, error) {
	balance := conn2tracker.GetOmniBalance(channelInfo.ChannelAddress, int(channelInfo.PropertyId))
	if balance == channelInfo.Amount {
		return true, nil
	}
	return false, nil
}

func GetAddressListUnspent(tx storm.Node, channelInfo dao.ChannelInfo) (listUnspentResult string, err error) {
	listUnspentArr := []dao.ChannelAddressListUnspent{}
	tx.Select(q.Eq("ChannelId", channelInfo.ChannelId)).Find(&listUnspentArr)
	if len(listUnspentArr) < 4 {
		btcRequestArr := []dao.FundingBtcRequest{}
		_ = tx.Select(q.Eq("TemporaryChannelId", channelInfo.TemporaryChannelId), q.Eq("IsFinish", true)).Find(&btcRequestArr)
		if len(btcRequestArr) != 3 {
			return "", errors.New("error btc fund")
		}
		for _, item := range btcRequestArr {
			outputFromHex := getOutputFromHex(item.TxHash, channelInfo.ChannelAddress)
			outputFromHex.ChannelId = channelInfo.ChannelId
			tx.Save(outputFromHex)
		}
		omniRequestArr := []dao.FundingTransaction{}
		_ = tx.Select(q.Eq("TemporaryChannelId", channelInfo.TemporaryChannelId)).Find(&omniRequestArr)
		if len(omniRequestArr) != 1 {
			return "", errors.New("error omni fund")
		}
		for _, item := range omniRequestArr {
			outputFromHex := getOutputFromHex(item.FundingTxHex, channelInfo.ChannelAddress)
			outputFromHex.ChannelId = channelInfo.ChannelId
			tx.Save(outputFromHex)
		}
		tx.Select(q.Eq("ChannelId", channelInfo.ChannelId)).Find(&listUnspentArr)
	}
	marshal, _ := json.Marshal(&listUnspentArr)
	return string(marshal), nil
}

func getOutputFromHex(hex string, toAddress string) *dao.ChannelAddressListUnspent {
	result, err := omnicore.DecodeBtcRawTransaction(hex)
	if err != nil {
		return nil
	}
	jsonHex := gjson.Parse(result)
	if jsonHex.Get("vout").IsArray() {
		for _, item := range jsonHex.Get("vout").Array() {
			if item.Get("scriptPubKey").Get("addresses").Exists() {
				addresses := item.Get("scriptPubKey").Get("addresses").Array()
				for _, address := range addresses {
					if address.String() == toAddress {
						if item.Get("value").Float() > 0 {
							node := &dao.ChannelAddressListUnspent{}
							node.Txid = jsonHex.Get("txid").String()
							node.ScriptPubKey = item.Get("scriptPubKey").Get("hex").Str
							node.Vout = uint32(item.Get("n").Uint())
							node.Amount = item.Get("value").Float()
							return node
						}
					}
				}
			}
		}
	}
	return nil
}

func verifyCompleteSignHex(inputs interface{}, signedHex string) error {
	var items []bean.RawTxInputItem

	var inputArr []interface{}
	switch inputs.(type) {
	case []interface{}:
		inputArr = inputs.([]interface{})
	case []map[string]interface{}:
		for _, temp := range inputs.([]map[string]interface{}) {
			inputArr = append(inputArr, temp)
		}
	}
	for _, temp := range inputArr {
		item := temp.(map[string]interface{})
		inputItem := bean.RawTxInputItem{}
		inputItem.ScriptPubKey = item["scriptPubKey"].(string)
		inputItem.RedeemScript = item["redeemScript"].(string)
		items = append(items, inputItem)
	}
	if omnicore.VerifySignatureHex(items, signedHex) != nil {
		return errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "signed_hex"))
	}
	return nil
}


<|start_filename|>tracker/bean/enums.go<|end_filename|>
package bean

import (
	"github.com/omnilaboratory/obd/bean/enum"
)

func CheckExist(msgType enum.MsgType) bool {
	switch msgType {
	case enum.MsgType_Error_0:
		return true
	case enum.MsgType_Tracker_Connect_301:
		return true
	case enum.MsgType_Tracker_HeartBeat_302:
		return true
	case enum.MsgType_Tracker_NodeLogin_303:
		return true
	case enum.MsgType_Tracker_UserLogin_304:
		return true
	case enum.MsgType_Tracker_UserLogout_305:
		return true
	case enum.MsgType_Tracker_UpdateChannelInfo_350:
		return true
	case enum.MsgType_Tracker_GetHtlcPath_351:
		return true
	case enum.MsgType_Tracker_UpdateHtlcTxState_352:
		return true
	case enum.MsgType_Tracker_UpdateUserInfo_353:
		return true
	}
	return false
}


<|start_filename|>service/schedule.go<|end_filename|>
package service

import (
	"github.com/asdine/storm"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/config"
	"github.com/omnilaboratory/obd/conn"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/tool"
	"github.com/tidwall/gjson"
	"io/ioutil"
	"log"
	"strings"
	"time"
)

type scheduleManager struct{}

var ScheduleService = scheduleManager{}

func (service *scheduleManager) StartSchedule() {
	go func() {
		ticker8m := time.NewTicker(8 * time.Minute)
		defer ticker8m.Stop()

		for {
			select {
			case t := <-ticker8m.C:
				log.Println("timer 8m", t)
				go sendRdTx()
				go checkBR()
			}
		}
	}()
}

//检查通道地址的金额是否变动了，根据交易的txid，广播br
func checkBR() {
	log.Println("checkBR")
	_dir := config.DataDirectory + "/" + config.ChainNodeType
	files, _ := ioutil.ReadDir(_dir)
	dbNames := make([]string, 0)
	userPeerIds := make([]string, 0)
	for _, f := range files {
		if strings.HasPrefix(f.Name(), "user_") && strings.HasSuffix(f.Name(), ".db") {
			peerId := strings.TrimPrefix(f.Name(), "user_")
			peerId = strings.TrimSuffix(peerId, ".db")
			value, exists := OnlineUserMap[peerId]
			if exists && value != nil {
				userPeerIds = append(userPeerIds, peerId)
			} else {
				dbNames = append(dbNames, f.Name())
			}
		}
	}

	for _, peerId := range userPeerIds {
		user, _ := OnlineUserMap[peerId]
		if user != nil {
			checkRsmcAndSendBR(user.Db)
		}
	}

	for _, dbName := range dbNames {
		db, err := storm.Open(_dir + "/" + dbName)
		if err == nil {
			checkRsmcAndSendBR(db)
			_ = db.Close()
		}
	}
}

func checkRsmcAndSendBR(db storm.Node) {
	var channelInfos []dao.ChannelInfo
	err := db.All(&channelInfos)
	if err == nil {
		for _, channelInfo := range channelInfos {
			if len(channelInfo.ChannelId) > 0 {
				if channelInfo.CurrState == bean.ChannelState_CanUse || channelInfo.CurrState == bean.ChannelState_HtlcTx {
					result := conn2tracker.OmniGetBalancesForAddress(channelInfo.ChannelAddress, int(channelInfo.PropertyId))
					if result == "" {
						continue
					}
					balance := gjson.Get(result, "balance").Float()

					if balance < channelInfo.Amount {
						transactionsStr, err := conn2tracker.OmniListTransactions(channelInfo.ChannelAddress)
						if transactionsStr == "" {
							continue
						}
						transactions := gjson.Parse(transactionsStr).Array()
						for _, item := range transactions {
							txid := item.Get("txid").Str
							if tool.CheckIsString(&txid) == false {
								continue
							}
							rsmcBreachRemedy := &dao.BreachRemedyTransaction{}
							_ = db.Select(q.Eq("CurrState", dao.TxInfoState_CreateAndSign), q.Eq("InputTxid", txid)).First(rsmcBreachRemedy)
							if rsmcBreachRemedy.Id > 0 {
								txid, err = conn2tracker.SendRawTransaction(rsmcBreachRemedy.BrTxHex)
								if err == nil {
									log.Println("timer send rsmcBr BreachRemedyTransaction id:", rsmcBreachRemedy.Id, txid)
									rsmcBreachRemedy.CurrState = dao.TxInfoState_SendHex
									rsmcBreachRemedy.SendAt = time.Now()
									_ = db.Update(rsmcBreachRemedy)
								}

								// htlc htlcbr
								htlcBreachRemedy := &dao.BreachRemedyTransaction{}
								_ = db.Select(
									q.Eq("Type", dao.BRType_Htlc),
									q.Eq("CurrState", dao.TxInfoState_CreateAndSign),
									q.Eq("ChannelId", rsmcBreachRemedy.ChannelId),
									q.Eq("CommitmentTxId", rsmcBreachRemedy.CommitmentTxId)).First(htlcBreachRemedy)
								if htlcBreachRemedy.Id > 0 {
									txid, err = conn2tracker.SendRawTransaction(htlcBreachRemedy.BrTxHex)
									if err == nil {
										log.Println("timer send htlcBr BreachRemedyTransaction id:", htlcBreachRemedy.Id, txid)
										htlcBreachRemedy.CurrState = dao.TxInfoState_SendHex
										htlcBreachRemedy.SendAt = time.Now()
										_ = db.Update(htlcBreachRemedy)
									}
								}
							} else {
								// htlc payer方的htbr
								sentRsmcBreachRemedy := &dao.BreachRemedyTransaction{}
								_ = db.Select(q.Eq("CurrState", dao.TxInfoState_SendHex), q.Eq("InputTxid", txid)).First(sentRsmcBreachRemedy)
								if sentRsmcBreachRemedy.Id > 0 {
									htBreachRemedy := &dao.BreachRemedyTransaction{}
									_ = db.Select(
										q.Eq("Type", dao.BRType_Ht1a),
										q.Eq("CurrState", dao.TxInfoState_CreateAndSign),
										q.Eq("ChannelId", sentRsmcBreachRemedy.ChannelId),
										q.Eq("CommitmentTxId", sentRsmcBreachRemedy.CommitmentTxId)).First(htBreachRemedy)
									if htBreachRemedy.Id > 0 {
										txid, err = conn2tracker.SendRawTransaction(htBreachRemedy.BrTxHex)
										if err == nil {
											log.Println("timer send htBr BreachRemedyTransaction id: ", htBreachRemedy.Id, txid)
											htBreachRemedy.CurrState = dao.TxInfoState_SendHex
											htBreachRemedy.SendAt = time.Now()
											_ = db.Update(htBreachRemedy)
										}
									}
									// 或者 htlc payee方的hebr
									heBreachRemedy := &dao.BreachRemedyTransaction{}
									_ = db.Select(
										q.Eq("Type", dao.BRType_HE1b),
										q.Eq("CurrState", dao.TxInfoState_CreateAndSign),
										q.Eq("ChannelId", sentRsmcBreachRemedy.ChannelId),
										q.Eq("CommitmentTxId", sentRsmcBreachRemedy.CommitmentTxId)).First(heBreachRemedy)
									if heBreachRemedy.Id > 0 {
										txid, err = conn2tracker.SendRawTransaction(heBreachRemedy.BrTxHex)
										if err != nil {
											log.Println("timer send heBr BreachRemedyTransaction id: ", heBreachRemedy.Id, txid)
											heBreachRemedy.CurrState = dao.TxInfoState_SendHex
											heBreachRemedy.SendAt = time.Now()
											_ = db.Update(heBreachRemedy)
										}
									}
								}
							}
						}
						log.Println(transactionsStr)
						channelInfo.CurrState = bean.ChannelState_Close
						channelInfo.CloseAt = time.Now()
						_ = db.Update(&channelInfo)
						sendChannelStateToTracker(channelInfo, dao.CommitmentTransaction{})
					}
				}
			}
		}
	}
}


<|start_filename|>conn/tracker_http_test.go<|end_filename|>
package conn2tracker

import (
	"log"
	"testing"
)

func TestTestMemPoolAccept(t *testing.T) {
	hex := ""
	hex = "0200000002c5c7eda485497b0836886cff8128becb5b98411faa7b79135c55be1668709104020000006b483045022100a55c4417d58e1b10cf090a6c12f685628a6a02326976f416c17613ed33cfc59a0220663aba3cab3a6f93796cde025afe9516295630aae600742cc9f9c3aed78aba24012103f07e518b9d2d3758ff504598cf484c65b612c27a8c755ce53663398db97addddffffffffdbc91d57b3cac1df8f6f25ed8f005d6d3ec09bfe86900b03089f6b51b2cd1edd010000006a47304402207ad7fb830773522b8b2bc636c4e20e27eb2aa5b0d98a323588d9b1379dfa629502206691e2d9fc7a4fbdecd8f071467853ae01caed7fc563444a801c79b9f432c555012103f07e518b9d2d3758ff504598cf484c65b612c27a8c755ce53663398db97addddffffffff0318c69a3b000000001976a9144c76521934cefc4f21f8373426747ba7f89c282488ac0000000000000000166a146f6d6e690000000080000004000000174876e800220200000000000017a9146645eeee46fbc3eb5740222de384122075c17a358700000000"
	//transaction := omnicore.DecodeRawTransaction(hex, &chaincfg.RegressionNetParams)

	transaction, err := OmniDecodeTransaction(hex)
	log.Println(err)
	log.Println(transaction)
	accept := TestMemPoolAccept(hex)
	log.Println(accept)
	//transaction, err := SendRawTransaction(hex)
	//log.Println(err)
	//log.Println(transaction)
}
func Test1(t *testing.T) {
	//log.Println(GetUserP2pNodeId("5773cc7b3b2fb80453ba82663b71992a91ecc8eb4b6b76fa6a60e42a6c913fa0"))
	address, err := GetBalanceByAddress("ms6kvv4RXqiQE53HbZ7NhaPmZpngb4XRiY")
	log.Println(address)
	log.Println(err)
}


<|start_filename|>lightclient/p2p_util.go<|end_filename|>
package lightclient

import (
	"bufio"
	"context"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/libp2p/go-libp2p"
	"github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/peerstore"
	discovery "github.com/libp2p/go-libp2p-discovery"
	dht "github.com/libp2p/go-libp2p-kad-dht"
	swarm "github.com/libp2p/go-libp2p-swarm"
	"github.com/multiformats/go-multiaddr"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/config"
	"github.com/omnilaboratory/obd/service"
	"github.com/omnilaboratory/obd/tool"
	"log"
	"math/rand"
	"strings"
	"sync"
)

type P2PChannel struct {
	IsLocalChannel bool
	Address        string
	stream         network.Stream
	rw             *bufio.ReadWriter
}

const obdRendezvousString = "obd meet at tracker"
const protocolIdForBetweenObd = "obd/betweenObd/1.0.1"
const protocolIdForScanObd = "obd/forScanObd/1.0.1"

var hostNode host.Host
var kademliaDHT *dht.IpfsDHT
var relayNode string

var localServerDest string
var P2PLocalNodeId string
var privateKey crypto.PrivKey
var P2pChannelMap map[string]*P2PChannel

func generatePrivateKey() (crypto.PrivKey, error) {
	if privateKey == nil {
		nodeId := int64(binary.BigEndian.Uint64([]byte(tool.GetObdNodeId())))
		r := rand.New(rand.NewSource(nodeId))
		prvKey, _, err := crypto.GenerateECDSAKeyPair(r)
		if err != nil {
			log.Println(err)
			return nil, err
		}
		privateKey = prvKey
	}
	return privateKey, nil
}

func StartP2PNode() (err error) {

	log.Println("start to p2p node")
	prvKey, err := generatePrivateKey()
	if err != nil {
		return err
	}

	// 0.0.0.0 will listen on any interface device.
	sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", config.P2P_port))

	// libp2p.New constructs a new libp2p Host.
	// Other options can be added here.
	hostNode, err = libp2p.New(
		ctx,
		libp2p.ListenAddrs(sourceMultiAddr),
		libp2p.EnableRelay(),
		libp2p.Identity(prvKey),
	)
	if err != nil {
		log.Println(err)
		return err
	}
	P2pChannelMap = make(map[string]*P2PChannel)
	P2PLocalNodeId = hostNode.ID().Pretty()
	service.P2PLocalNodeId = P2PLocalNodeId

	localServerDest = fmt.Sprintf("/ip4/%s/tcp/%v/p2p/%s", config.P2P_hostIp, config.P2P_port, hostNode.ID().Pretty())
	bean.CurrObdNodeInfo.P2pAddress = localServerDest
	log.Println("local p2p address", localServerDest)

	//把自己也作为终点放进去，阻止自己连接自己
	P2pChannelMap[P2PLocalNodeId] = &P2PChannel{
		IsLocalChannel: true,
		Address:        localServerDest,
	}
	hostNode.SetStreamHandler(protocolIdForScanObd, handleTrackerScanStream)
	hostNode.SetStreamHandler(protocolIdForBetweenObd, handleStream)
	hostNode.SetStreamHandler(bean.ProtocolIdForLockChannel, handleLockChannelStream)
	hostNode.SetStreamHandler(bean.ProtocolIdForUnlockChannel, handleUnlockChannelStream)

	kademliaDHT, err = dht.New(ctx, hostNode)
	if err != nil {
		log.Println(err)
		return err
	}

	err = kademliaDHT.Bootstrap(ctx)
	if err != nil {
		log.Println(err)
		return err
	}

	var wg sync.WaitGroup
	for _, peerAddr := range config.BootstrapPeers {
		peerInfo, _ := peer.AddrInfoFromP2pAddr(peerAddr)
		wg.Add(1)

		go func() {
			defer wg.Done()
			err = hostNode.Connect(ctx, *peerInfo)

			if err != nil {
				log.Println(err, peerInfo)
			} else {
				log.Println("connected to bootstrap node ", *peerInfo)
				if len(relayNode) == 0 {
					relayNode = peerInfo.ID.Pretty()
				}
			}
		}()
	}
	wg.Wait()

	routingDiscovery = discovery.NewRoutingDiscovery(kademliaDHT)
	discovery.Advertise(ctx, routingDiscovery, obdRendezvousString)

	return nil
}

var routingDiscovery *discovery.RoutingDiscovery
var ctx = context.Background()

func ScanAndConnNode(nodeId string) error {
	peerChan, err := routingDiscovery.FindPeers(context.Background(), obdRendezvousString)
	if err != nil {
		return err
	}
	for node := range peerChan {
		if node.ID == hostNode.ID() {
			continue
		}
		if node.ID.Pretty() == nodeId {
			return connSomeNode(node)
		}
	}
	return errors.New("find no node")
}

func disConnP2PNode(dest string) error {

	if dest == hostNode.ID().Pretty() {
		return errors.New("can not disconnect self")
	}

	if P2pChannelMap[dest] == nil {
		return errors.New("Remote peer not be connecting")
	}

	msgChan := P2pChannelMap[dest]
	err := msgChan.stream.Close()
	if err == nil {
		delete(P2pChannelMap, dest)
	}
	return err
}

func connSomeNode(node peer.AddrInfo) error {
	if P2pChannelMap[node.ID.Pretty()] != nil {
		log.Println("Remote peer has been connected")
		return nil
	}

	relayAddr, err := multiaddr.NewMultiaddr("/p2p/" + relayNode + "/p2p-circuit/p2p/" + node.ID.Pretty())
	if err != nil {
		log.Println(err)
		return err
	}
	hostNode.Network().(*swarm.Swarm).Backoff().Clear(node.ID)
	peerRelayInfo := peer.AddrInfo{
		ID:    node.ID,
		Addrs: []multiaddr.Multiaddr{relayAddr},
	}

	if err := hostNode.Connect(ctx, peerRelayInfo); err != nil {
		log.Println(err)
		return err
	} else {
		log.Println("Connection established with RELAY node:", relayAddr)
	}

	hostNode.Peerstore().AddAddrs(node.ID, node.Addrs, peerstore.PermanentAddrTTL)

	stream, err := hostNode.NewStream(ctx, node.ID, protocolIdForBetweenObd)
	if err != nil {
		log.Println(err)
		return err
	}

	rw := addP2PChannel(stream)
	go readData(stream, rw)
	return nil
}

func connP2PNode(dest string) (string, error) {
	if tool.CheckIsString(&dest) == false {
		log.Println("wrong dest address")
		return "", errors.New("wrong dest address")
	}

	if strings.Contains(dest, P2PLocalNodeId) {
		return "", errors.New("do not need connect self")
	}

	_, err := multiaddr.NewMultiaddr(dest)
	if err != nil {
		log.Println(err)
		return "", err
	}

	destMaddr, err := multiaddr.NewMultiaddr(dest)
	if err != nil {
		log.Println(err)
		return "", err
	}

	destHostPeerInfo, err := peer.AddrInfoFromP2pAddr(destMaddr)
	if err != nil {
		log.Println(err)
		return "", err
	}

	//split := strings.Split(dest, "/")
	//p2PNodeId := split[len(split)-1]
	//findID, err := peer.Decode(p2PNodeId)
	//destHostPeerInfo, err := kademliaDHT.FindPeer(ctx, findID)
	//if err != nil {
	//	return "", err
	//}

	if destHostPeerInfo.ID == hostNode.ID() {
		return "", errors.New("wrong dest address")
	}
	err = connSomeNode(*destHostPeerInfo)
	return localServerDest, err
}

func handleStream(s network.Stream) {
	if s != nil {
		if P2pChannelMap[s.Conn().RemotePeer().Pretty()] == nil {
			log.Println("Got a new stream!", s.Conn().RemotePeer().Pretty())
			rw := addP2PChannel(s)
			go readData(s, rw)
		}
	}
}

var trackerNodeIdMap = make(map[string]bool)

func handleTrackerScanStream(stream network.Stream) {
	if stream != nil {
		log.Println("request to scan channel and online user info from tracker", stream.Conn().RemotePeer().Pretty())

		users := make(map[string]string)
		for _, item := range GlobalWsClientManager.OnlineClientMap {
			if item.User != nil {
				users[item.User.PeerId] = item.User.P2PLocalAddress
			}
		}
		flag := false
		info := make(map[string]string)
		info["obdP2pNodeId"] = P2PLocalNodeId
		if len(users) > 0 {
			marshal, _ := json.Marshal(users)
			info["userInfo"] = string(marshal)
			flag = true
		}

		nodes := getChannelInfos()
		if len(nodes) > 0 {
			marshal, _ := json.Marshal(nodes)
			info["channelInfo"] = string(marshal)
			flag = true
		}

		//log.Println(info)
		if flag {
			marshal, _ := json.Marshal(info)
			msg := string(marshal) + "~"
			rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
			_, err := rw.WriteString(msg)
			if err == nil {
				_ = rw.Flush()
			}
		}
		trackerNodeIdMap[stream.Conn().RemotePeer().Pretty()] = true
		_ = stream.Close()
	}
}
func readData(s network.Stream, rw *bufio.ReadWriter) {
	for {
		str, err := rw.ReadString('~')
		if err != nil {
			log.Println(s.Conn().RemotePeer().Pretty(), "offline")
			delete(P2pChannelMap, s.Conn().RemotePeer().Pretty())
			return
		}
		if str == "" {
			return
		}
		if str != "" {
			log.Println("readData", s.Conn())
			str = strings.TrimSuffix(str, "~")
			//log.Println(str)
			reqData := &bean.RequestMessage{}
			err := json.Unmarshal([]byte(str), reqData)
			if err == nil {
				err = getDataFromP2PSomeone(*reqData)
				if err != nil {
					//msg := err.Error() + "~"
					//_, _ = rw.WriteString(msg)
					//_ = rw.Flush()
				}
			}
		}
	}
}

func addP2PChannel(stream network.Stream) *bufio.ReadWriter {
	rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
	node := &P2PChannel{
		Address: stream.Conn().RemoteMultiaddr().String() + "/" + stream.Conn().RemotePeer().String(),
		stream:  stream,
		rw:      rw,
	}
	P2pChannelMap[stream.Conn().RemotePeer().Pretty()] = node
	return rw
}

func sendP2PMsg(remoteP2PPeerId string, msg string) error {
	if tool.CheckIsString(&remoteP2PPeerId) == false {
		return errors.New("empty remoteP2PPeerId")
	}
	if remoteP2PPeerId == P2PLocalNodeId {
		return errors.New("remoteP2PPeerId is yourself,can not send msg to yourself")
	}

	channel := P2pChannelMap[remoteP2PPeerId]
	if channel != nil {
		msg = msg + "~"
		_, _ = channel.rw.WriteString(msg)
		_ = channel.rw.Flush()
	} else {
		log.Println("remoteP2PPeerId " + remoteP2PPeerId + " not connect")
		return errors.New("remoteP2PPeerId " + remoteP2PPeerId + " not connect")
	}
	return nil
}

func sendInfoOnUserStateChange(userId string) {
	for key := range trackerNodeIdMap {
		findID, err := peer.Decode(key)
		if err == nil {
			findPeer, err := kademliaDHT.FindPeer(ctx, findID)
			if err == nil {
				stream, err := hostNode.NewStream(ctx, findPeer.ID, bean.ProtocolIdForUserState)
				if err == nil {
					rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
					_, _ = rw.WriteString(hostNode.ID().Pretty() + "_" + userId + "_" + localServerDest + "~")
					err = rw.Flush()
					log.Println(err)
				}
			}
		}
	}
}

func sendChannelInfoToIndirectTracker(msg string) {
	//log.Println("sendChannelInfoToIndirectTracker", msg)
	for key := range trackerNodeIdMap {
		findID, err := peer.Decode(key)
		if err == nil {
			findPeer, err := kademliaDHT.FindPeer(ctx, findID)
			if err == nil {
				stream, err := hostNode.NewStream(ctx, findPeer.ID, bean.ProtocolIdForChannelInfoChange)
				if err == nil {
					rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
					_, _ = rw.WriteString(msg + "~")
					err = rw.Flush()
					log.Println(err)
				}
			}
		}
	}
}

func handleLockChannelStream(stream network.Stream) {
	rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
	str, err := rw.ReadString('~')
	if err != nil || str == "" {
		return
	}

	str = strings.TrimSuffix(str, "~")
	request := &bean.TrackerLockChannelRequest{}
	_ = json.Unmarshal([]byte(str), request)
	err = lockChannel(request.UserId, request.ChannelId)
	result := "1"
	if err != nil {
		result = "0"
	}
	//request.UserId
	_, _ = rw.WriteString(result + "~")
	_ = rw.Flush()
}

func handleUnlockChannelStream(stream network.Stream) {
	rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
	str, err := rw.ReadString('~')
	if err != nil || str == "" {
		return
	}

	str = strings.TrimSuffix(str, "~")
	request := &bean.TrackerLockChannelRequest{}
	_ = json.Unmarshal([]byte(str), request)
	err = unlockChannel(request.UserId, request.ChannelId)
	result := "1"
	if err != nil {
		result = "0"
	}
	//request.UserId
	_, _ = rw.WriteString(result + "~")
	_ = rw.Flush()
}


<|start_filename|>dao/pojo_htlc.go<|end_filename|>
package dao

import (
	"github.com/omnilaboratory/obd/bean"
	"time"
)

type InvoiceInfo struct {
	Id       int                     `storm:"id,increment" json:"id" `
	Detail   bean.HtlcRequestInvoice `json:"detail"`
	Invoice  string                  `json:"invoice"`
	CreateAt time.Time               `json:"create_at"`
}

type HtlcHAndRImage struct {
	Id       int       `storm:"id,increment" json:"id" `
	H        string    `json:"h"`
	Index    int       `json:"index"`
	R        string    `json:"r"`
	CreateAt time.Time `json:"create_at"`
}

type AddHtlcRequestInfo struct {
	Id                               int         `storm:"id,increment" json:"id" `
	ChannelId                        string      `json:"channel_id"`
	RecipientUserPeerId              string      `json:"recipient_user_peer_id"`
	PropertyId                       int64       `json:"property_id"`
	Amount                           float64     `json:"amount"`
	Memo                             string      `json:"memo"`
	H                                string      `json:"h"`
	RoutingPacket                    string      `json:"routing_packet"`
	LastTempAddressPrivateKey        string      `json:"last_temp_address_private_key"`  //	支付方的上一个RSMC委托交易用到的临时地址的私钥 存储在bob这边的请求
	CurrRsmcTempAddressPubKey        string      `json:"curr_rsmc_temp_address_pub_key"` //	创建Cnx中的toRsmc的部分使用的临时地址的公钥
	CurrHtlcTempAddressPubKey        string      `json:"curr_htlc_temp_address_pub_key"` //	创建Cnx中的toHtlc的部分使用的临时地址的公钥
	CurrHtlcTempAddressForHt1aIndex  int         `json:"curr_htlc_temp_address_for_ht1a_index"`
	CurrHtlcTempAddressForHt1aPubKey string      `json:"curr_htlc_temp_address_for_ht1a_pub_key"` //	创建Ht1a中生成ht1a的输出的Rmsc的临时地址的公钥
	CurrState                        NormalState `json:"curr_state"`
	CreateBy                         string      `json:"create_by"`
	CreateAt                         time.Time   `json:"create_at"`
	FinishAt                         time.Time   `json:"finish_at"`
}

//HT1a 锁住发起方的交易资金：锁住的意思是：把资金放到一个临时多签帐号（alice1&bob）
//HE1b 等获取到R后，锁住接收方的交易资金：锁住的意思是：把资金放到一个临时多签帐号（alice&bob6）
type HTLCTimeoutTxForAAndExecutionForB struct {
	Id                           int         `storm:"id,increment" json:"id" `
	ChannelId                    string      `json:"channel_id"`
	CommitmentTxId               int         `json:"commitment_tx_id"`
	PropertyId                   int64       `json:"property_id"`
	InputTxid                    string      `json:"input_txid"`   // input txid  from commitTx aliceTempHtlc&bob multtaddr, so need  sign of aliceTempHtlc and bob
	InputAmount                  float64     `json:"input_amount"` // input amount
	InputHex                     string      `json:"input_hex"`
	Timeout                      int         `json:"timeout"` // if 3days 432=3*24*6
	RSMCTempAddressIndex         int         `json:"rsmc_temp_address_index"`
	RSMCTempAddressPubKey        string      `json:"rsmc_temp_address_pub_key"`
	RSMCMultiAddress             string      `json:"rsmc_multi_address"`
	RSMCRedeemScript             string      `json:"rsmc_redeem_script"`
	RSMCMultiAddressScriptPubKey string      `json:"rsmc_multi_address_script_pub_key"`
	RSMCOutAmount                float64     `json:"rsmc_out_amount"`
	RSMCTxHex                    string      `json:"rsmc_tx_hex"`
	RSMCTxid                     string      `json:"rsmc_txid"`
	CurrState                    TxInfoState `json:"curr_state"`
	Owner                        string      `json:"owner"`
	CreateBy                     string      `json:"create_by"`
	CreateAt                     time.Time   `json:"create_at"`
	SignAt                       time.Time   `json:"sign_at"`
	SendAt                       time.Time   `json:"send_at"`
}

//HTD1b 锁住发起方的交易资金：如果bob广播了，如果过了三天，如果R没有获取到，alice可以通过广播拿回资金
type HTLCTimeoutDeliveryTxB struct {
	Id             int         `storm:"id,increment" json:"id" `
	ChannelId      string      `json:"channel_id"`
	CommitmentTxId int         `json:"commitment_tx_id"`
	PropertyId     int64       `json:"property_id"`
	InputTxid      string      `json:"input_txid"`
	InputHex       string      `json:"input_hex"`
	Timeout        int         `json:"timeout"`
	OutputAddress  string      `json:"output_address"` //output Sender Alice(if alice is sender) or Bob(if bob is sender)
	OutAmount      float64     `json:"out_amount"`
	TxHex          string      `json:"tx_hex"`
	Txid           string      `json:"txid"`
	Owner          string      `json:"owner"`
	CurrState      TxInfoState `json:"curr_state"`
	CreateAt       time.Time   `json:"create_at"`
	SendAt         time.Time   `json:"send_at"`
	CreateBy       string      `json:"create_by"`
}

//HED1a when get H , alice 得到H（公钥），生成三签地址，锁住给中间节点的钱，当得到R（私钥）的时候，完成三签地址的签名，生成最终支付交易
type HtlcLockTxByH struct {
	Id                 int         `storm:"id,increment" json:"id" `
	ChannelId          string      `json:"channel_id"`
	PropertyId         int64       `json:"property_id"`
	CommitmentTxId     int         `json:"commitment_tx_id"`
	InputHex           string      `json:"input_hex"`
	InputTxid          string      `json:"input_txid"` // input txid  from commitTx aliceTempHtlc&bob multtaddr, so need  sign of aliceTempHtlc and bob
	HtlcH              string      `json:"htlc_h"`     // H(公钥，双签地址之一)
	PayeeChannelPubKey string      `json:"payee_channel_pub_key"`
	OutputAddress      string      `json:"output_address"` // 双签地址 锁定支付资金
	RedeemScript       string      `json:"redeem_script"`  // 双签地址对应的赎回脚本
	ScriptPubKey       string      `json:"script_pub_key"`
	OutAmount          float64     `json:"out_amount"`
	Timeout            int         `json:"timeout"`
	TxHex              string      `json:"tx_hex"`
	Txid               string      `json:"txid"`
	CurrState          TxInfoState `json:"curr_state"`
	Owner              string      `json:"owner"`
	CreateAt           time.Time   `json:"create_at"`
	SendAt             time.Time   `json:"send_at"`
	CreateBy           string      `json:"create_by"`
}

//HED1a when get R 如果bob返回了正确的R，就可以完成签名，标识这次的htlc可以成功了
type HTLCExecutionDeliveryOfR struct {
	Id             int         `storm:"id,increment" json:"id" `
	ChannelId      string      `json:"channel_id"`
	CommitmentTxId int         `json:"commitment_tx_id"`
	HLockTxId      int         `json:"hlock_tx_id"`
	InputHex       string      `json:"input_hex"`
	InputTxid      string      `json:"input_txid"`   // input txid  from commitTx aliceTempHtlc&bob multtaddr, so need  sign of aliceTempHtlc and bob
	InputAmount    float64     `json:"input_amount"` // input amount
	HtlcR          string      `json:"htlc_r"`
	OutputAddress  string      `json:"output_address"` //to Bob
	OutAmount      float64     `json:"out_amount"`
	TxHex          string      `json:"tx_hex"`
	Txid           string      `json:"txid"`
	CurrState      TxInfoState `json:"curr_state"`
	Owner          string      `json:"owner"`
	CreateAt       time.Time   `json:"create_at"`
	SendAt         time.Time   `json:"send_at"`
	CreateBy       string      `json:"create_by"`
}

type NormalState int

const (
	NS_Create NormalState = 10
	NS_Finish NormalState = 20
	NS_Refuse NormalState = 30
)


<|start_filename|>proxy/pb/wallet.pb.go<|end_filename|>
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: wallet.proto

package pb

import (
	context "context"
	fmt "fmt"
	proto "github.com/golang/protobuf/proto"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
	math "math"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

type LoginRequest struct {
	Mnemonic             string   `protobuf:"bytes,1,opt,name=mnemonic,proto3" json:"mnemonic,omitempty"`
	LoginToken           string   `protobuf:"bytes,2,opt,name=login_token,json=loginToken,proto3" json:"login_token,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *LoginRequest) Reset()         { *m = LoginRequest{} }
func (m *LoginRequest) String() string { return proto.CompactTextString(m) }
func (*LoginRequest) ProtoMessage()    {}
func (*LoginRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{0}
}

func (m *LoginRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_LoginRequest.Unmarshal(m, b)
}
func (m *LoginRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_LoginRequest.Marshal(b, m, deterministic)
}
func (m *LoginRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_LoginRequest.Merge(m, src)
}
func (m *LoginRequest) XXX_Size() int {
	return xxx_messageInfo_LoginRequest.Size(m)
}
func (m *LoginRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_LoginRequest.DiscardUnknown(m)
}

var xxx_messageInfo_LoginRequest proto.InternalMessageInfo

func (m *LoginRequest) GetMnemonic() string {
	if m != nil {
		return m.Mnemonic
	}
	return ""
}

func (m *LoginRequest) GetLoginToken() string {
	if m != nil {
		return m.LoginToken
	}
	return ""
}

type LoginResponse struct {
	UserPeerId           string   `protobuf:"bytes,1,opt,name=user_peerId,json=userPeerId,proto3" json:"user_peerId,omitempty"`
	NodePeerId           string   `protobuf:"bytes,2,opt,name=node_peerId,json=nodePeerId,proto3" json:"node_peerId,omitempty"`
	NodeAddress          string   `protobuf:"bytes,3,opt,name=node_address,json=nodeAddress,proto3" json:"node_address,omitempty"`
	HtlcFeeRate          float64  `protobuf:"fixed64,4,opt,name=htlc_fee_rate,json=htlcFeeRate,proto3" json:"htlc_fee_rate,omitempty"`
	HtlcMaxFee           float64  `protobuf:"fixed64,5,opt,name=htlc_max_fee,json=htlcMaxFee,proto3" json:"htlc_max_fee,omitempty"`
	ChainNodeType        string   `protobuf:"bytes,6,opt,name=chain_node_type,json=chainNodeType,proto3" json:"chain_node_type,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *LoginResponse) Reset()         { *m = LoginResponse{} }
func (m *LoginResponse) String() string { return proto.CompactTextString(m) }
func (*LoginResponse) ProtoMessage()    {}
func (*LoginResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{1}
}

func (m *LoginResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_LoginResponse.Unmarshal(m, b)
}
func (m *LoginResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_LoginResponse.Marshal(b, m, deterministic)
}
func (m *LoginResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_LoginResponse.Merge(m, src)
}
func (m *LoginResponse) XXX_Size() int {
	return xxx_messageInfo_LoginResponse.Size(m)
}
func (m *LoginResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_LoginResponse.DiscardUnknown(m)
}

var xxx_messageInfo_LoginResponse proto.InternalMessageInfo

func (m *LoginResponse) GetUserPeerId() string {
	if m != nil {
		return m.UserPeerId
	}
	return ""
}

func (m *LoginResponse) GetNodePeerId() string {
	if m != nil {
		return m.NodePeerId
	}
	return ""
}

func (m *LoginResponse) GetNodeAddress() string {
	if m != nil {
		return m.NodeAddress
	}
	return ""
}

func (m *LoginResponse) GetHtlcFeeRate() float64 {
	if m != nil {
		return m.HtlcFeeRate
	}
	return 0
}

func (m *LoginResponse) GetHtlcMaxFee() float64 {
	if m != nil {
		return m.HtlcMaxFee
	}
	return 0
}

func (m *LoginResponse) GetChainNodeType() string {
	if m != nil {
		return m.ChainNodeType
	}
	return ""
}

type ChangePasswordRequest struct {
	CurrentPassword      string   `protobuf:"bytes,1,opt,name=current_password,json=currentPassword,proto3" json:"current_password,omitempty"`
	NewPassword          string   `protobuf:"bytes,2,opt,name=new_password,json=newPassword,proto3" json:"new_password,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ChangePasswordRequest) Reset()         { *m = ChangePasswordRequest{} }
func (m *ChangePasswordRequest) String() string { return proto.CompactTextString(m) }
func (*ChangePasswordRequest) ProtoMessage()    {}
func (*ChangePasswordRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{2}
}

func (m *ChangePasswordRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ChangePasswordRequest.Unmarshal(m, b)
}
func (m *ChangePasswordRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ChangePasswordRequest.Marshal(b, m, deterministic)
}
func (m *ChangePasswordRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ChangePasswordRequest.Merge(m, src)
}
func (m *ChangePasswordRequest) XXX_Size() int {
	return xxx_messageInfo_ChangePasswordRequest.Size(m)
}
func (m *ChangePasswordRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ChangePasswordRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ChangePasswordRequest proto.InternalMessageInfo

func (m *ChangePasswordRequest) GetCurrentPassword() string {
	if m != nil {
		return m.CurrentPassword
	}
	return ""
}

func (m *ChangePasswordRequest) GetNewPassword() string {
	if m != nil {
		return m.NewPassword
	}
	return ""
}

type ChangePasswordResponse struct {
	Result               string   `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ChangePasswordResponse) Reset()         { *m = ChangePasswordResponse{} }
func (m *ChangePasswordResponse) String() string { return proto.CompactTextString(m) }
func (*ChangePasswordResponse) ProtoMessage()    {}
func (*ChangePasswordResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{3}
}

func (m *ChangePasswordResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ChangePasswordResponse.Unmarshal(m, b)
}
func (m *ChangePasswordResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ChangePasswordResponse.Marshal(b, m, deterministic)
}
func (m *ChangePasswordResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ChangePasswordResponse.Merge(m, src)
}
func (m *ChangePasswordResponse) XXX_Size() int {
	return xxx_messageInfo_ChangePasswordResponse.Size(m)
}
func (m *ChangePasswordResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_ChangePasswordResponse.DiscardUnknown(m)
}

var xxx_messageInfo_ChangePasswordResponse proto.InternalMessageInfo

func (m *ChangePasswordResponse) GetResult() string {
	if m != nil {
		return m.Result
	}
	return ""
}

type LogoutRequest struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *LogoutRequest) Reset()         { *m = LogoutRequest{} }
func (m *LogoutRequest) String() string { return proto.CompactTextString(m) }
func (*LogoutRequest) ProtoMessage()    {}
func (*LogoutRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{4}
}

func (m *LogoutRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_LogoutRequest.Unmarshal(m, b)
}
func (m *LogoutRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_LogoutRequest.Marshal(b, m, deterministic)
}
func (m *LogoutRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_LogoutRequest.Merge(m, src)
}
func (m *LogoutRequest) XXX_Size() int {
	return xxx_messageInfo_LogoutRequest.Size(m)
}
func (m *LogoutRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_LogoutRequest.DiscardUnknown(m)
}

var xxx_messageInfo_LogoutRequest proto.InternalMessageInfo

type LogoutResponse struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *LogoutResponse) Reset()         { *m = LogoutResponse{} }
func (m *LogoutResponse) String() string { return proto.CompactTextString(m) }
func (*LogoutResponse) ProtoMessage()    {}
func (*LogoutResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{5}
}

func (m *LogoutResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_LogoutResponse.Unmarshal(m, b)
}
func (m *LogoutResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_LogoutResponse.Marshal(b, m, deterministic)
}
func (m *LogoutResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_LogoutResponse.Merge(m, src)
}
func (m *LogoutResponse) XXX_Size() int {
	return xxx_messageInfo_LogoutResponse.Size(m)
}
func (m *LogoutResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_LogoutResponse.DiscardUnknown(m)
}

var xxx_messageInfo_LogoutResponse proto.InternalMessageInfo

type GenSeedRequest struct {
	AezeedPassphrase     []byte   `protobuf:"bytes,1,opt,name=aezeed_passphrase,json=aezeedPassphrase,proto3" json:"aezeed_passphrase,omitempty"`
	SeedEntropy          []byte   `protobuf:"bytes,2,opt,name=seed_entropy,json=seedEntropy,proto3" json:"seed_entropy,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *GenSeedRequest) Reset()         { *m = GenSeedRequest{} }
func (m *GenSeedRequest) String() string { return proto.CompactTextString(m) }
func (*GenSeedRequest) ProtoMessage()    {}
func (*GenSeedRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{6}
}

func (m *GenSeedRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_GenSeedRequest.Unmarshal(m, b)
}
func (m *GenSeedRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_GenSeedRequest.Marshal(b, m, deterministic)
}
func (m *GenSeedRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_GenSeedRequest.Merge(m, src)
}
func (m *GenSeedRequest) XXX_Size() int {
	return xxx_messageInfo_GenSeedRequest.Size(m)
}
func (m *GenSeedRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_GenSeedRequest.DiscardUnknown(m)
}

var xxx_messageInfo_GenSeedRequest proto.InternalMessageInfo

func (m *GenSeedRequest) GetAezeedPassphrase() []byte {
	if m != nil {
		return m.AezeedPassphrase
	}
	return nil
}

func (m *GenSeedRequest) GetSeedEntropy() []byte {
	if m != nil {
		return m.SeedEntropy
	}
	return nil
}

type GenSeedResponse struct {
	CipherSeedMnemonic   string   `protobuf:"bytes,1,opt,name=cipher_seed_mnemonic,json=cipherSeedMnemonic,proto3" json:"cipher_seed_mnemonic,omitempty"`
	EncipheredSeed       string   `protobuf:"bytes,2,opt,name=enciphered_seed,json=encipheredSeed,proto3" json:"enciphered_seed,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *GenSeedResponse) Reset()         { *m = GenSeedResponse{} }
func (m *GenSeedResponse) String() string { return proto.CompactTextString(m) }
func (*GenSeedResponse) ProtoMessage()    {}
func (*GenSeedResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{7}
}

func (m *GenSeedResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_GenSeedResponse.Unmarshal(m, b)
}
func (m *GenSeedResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_GenSeedResponse.Marshal(b, m, deterministic)
}
func (m *GenSeedResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_GenSeedResponse.Merge(m, src)
}
func (m *GenSeedResponse) XXX_Size() int {
	return xxx_messageInfo_GenSeedResponse.Size(m)
}
func (m *GenSeedResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_GenSeedResponse.DiscardUnknown(m)
}

var xxx_messageInfo_GenSeedResponse proto.InternalMessageInfo

func (m *GenSeedResponse) GetCipherSeedMnemonic() string {
	if m != nil {
		return m.CipherSeedMnemonic
	}
	return ""
}

func (m *GenSeedResponse) GetEncipheredSeed() string {
	if m != nil {
		return m.EncipheredSeed
	}
	return ""
}

type EstimateFeeRequest struct {
	ConfTarget           int32    `protobuf:"varint,1,opt,name=conf_target,json=confTarget,proto3" json:"conf_target,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *EstimateFeeRequest) Reset()         { *m = EstimateFeeRequest{} }
func (m *EstimateFeeRequest) String() string { return proto.CompactTextString(m) }
func (*EstimateFeeRequest) ProtoMessage()    {}
func (*EstimateFeeRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{8}
}

func (m *EstimateFeeRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_EstimateFeeRequest.Unmarshal(m, b)
}
func (m *EstimateFeeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_EstimateFeeRequest.Marshal(b, m, deterministic)
}
func (m *EstimateFeeRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_EstimateFeeRequest.Merge(m, src)
}
func (m *EstimateFeeRequest) XXX_Size() int {
	return xxx_messageInfo_EstimateFeeRequest.Size(m)
}
func (m *EstimateFeeRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_EstimateFeeRequest.DiscardUnknown(m)
}

var xxx_messageInfo_EstimateFeeRequest proto.InternalMessageInfo

func (m *EstimateFeeRequest) GetConfTarget() int32 {
	if m != nil {
		return m.ConfTarget
	}
	return 0
}

type EstimateFeeResponse struct {
	SatPerKw             int64    `protobuf:"varint,1,opt,name=sat_per_kw,json=satPerKw,proto3" json:"sat_per_kw,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *EstimateFeeResponse) Reset()         { *m = EstimateFeeResponse{} }
func (m *EstimateFeeResponse) String() string { return proto.CompactTextString(m) }
func (*EstimateFeeResponse) ProtoMessage()    {}
func (*EstimateFeeResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{9}
}

func (m *EstimateFeeResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_EstimateFeeResponse.Unmarshal(m, b)
}
func (m *EstimateFeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_EstimateFeeResponse.Marshal(b, m, deterministic)
}
func (m *EstimateFeeResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_EstimateFeeResponse.Merge(m, src)
}
func (m *EstimateFeeResponse) XXX_Size() int {
	return xxx_messageInfo_EstimateFeeResponse.Size(m)
}
func (m *EstimateFeeResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_EstimateFeeResponse.DiscardUnknown(m)
}

var xxx_messageInfo_EstimateFeeResponse proto.InternalMessageInfo

func (m *EstimateFeeResponse) GetSatPerKw() int64 {
	if m != nil {
		return m.SatPerKw
	}
	return 0
}

type AddrRequest struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *AddrRequest) Reset()         { *m = AddrRequest{} }
func (m *AddrRequest) String() string { return proto.CompactTextString(m) }
func (*AddrRequest) ProtoMessage()    {}
func (*AddrRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{10}
}

func (m *AddrRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_AddrRequest.Unmarshal(m, b)
}
func (m *AddrRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_AddrRequest.Marshal(b, m, deterministic)
}
func (m *AddrRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_AddrRequest.Merge(m, src)
}
func (m *AddrRequest) XXX_Size() int {
	return xxx_messageInfo_AddrRequest.Size(m)
}
func (m *AddrRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_AddrRequest.DiscardUnknown(m)
}

var xxx_messageInfo_AddrRequest proto.InternalMessageInfo

type AddrResponse struct {
	//
	//The address encoded using a bech32 format.
	Index                int64    `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"`
	Addr                 string   `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"`
	PubKey               string   `protobuf:"bytes,3,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"`
	Wif                  string   `protobuf:"bytes,4,opt,name=wif,proto3" json:"wif,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *AddrResponse) Reset()         { *m = AddrResponse{} }
func (m *AddrResponse) String() string { return proto.CompactTextString(m) }
func (*AddrResponse) ProtoMessage()    {}
func (*AddrResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{11}
}

func (m *AddrResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_AddrResponse.Unmarshal(m, b)
}
func (m *AddrResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_AddrResponse.Marshal(b, m, deterministic)
}
func (m *AddrResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_AddrResponse.Merge(m, src)
}
func (m *AddrResponse) XXX_Size() int {
	return xxx_messageInfo_AddrResponse.Size(m)
}
func (m *AddrResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_AddrResponse.DiscardUnknown(m)
}

var xxx_messageInfo_AddrResponse proto.InternalMessageInfo

func (m *AddrResponse) GetIndex() int64 {
	if m != nil {
		return m.Index
	}
	return 0
}

func (m *AddrResponse) GetAddr() string {
	if m != nil {
		return m.Addr
	}
	return ""
}

func (m *AddrResponse) GetPubKey() string {
	if m != nil {
		return m.PubKey
	}
	return ""
}

func (m *AddrResponse) GetWif() string {
	if m != nil {
		return m.Wif
	}
	return ""
}

type NewAddressRequest struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *NewAddressRequest) Reset()         { *m = NewAddressRequest{} }
func (m *NewAddressRequest) String() string { return proto.CompactTextString(m) }
func (*NewAddressRequest) ProtoMessage()    {}
func (*NewAddressRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{12}
}

func (m *NewAddressRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_NewAddressRequest.Unmarshal(m, b)
}
func (m *NewAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_NewAddressRequest.Marshal(b, m, deterministic)
}
func (m *NewAddressRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_NewAddressRequest.Merge(m, src)
}
func (m *NewAddressRequest) XXX_Size() int {
	return xxx_messageInfo_NewAddressRequest.Size(m)
}
func (m *NewAddressRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_NewAddressRequest.DiscardUnknown(m)
}

var xxx_messageInfo_NewAddressRequest proto.InternalMessageInfo

type NewAddressResponse struct {
	//
	//The address encoded using a bech32 format.
	Index                int64    `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"`
	Addr                 string   `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"`
	PubKey               string   `protobuf:"bytes,3,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"`
	Wif                  string   `protobuf:"bytes,4,opt,name=wif,proto3" json:"wif,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *NewAddressResponse) Reset()         { *m = NewAddressResponse{} }
func (m *NewAddressResponse) String() string { return proto.CompactTextString(m) }
func (*NewAddressResponse) ProtoMessage()    {}
func (*NewAddressResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{13}
}

func (m *NewAddressResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_NewAddressResponse.Unmarshal(m, b)
}
func (m *NewAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_NewAddressResponse.Marshal(b, m, deterministic)
}
func (m *NewAddressResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_NewAddressResponse.Merge(m, src)
}
func (m *NewAddressResponse) XXX_Size() int {
	return xxx_messageInfo_NewAddressResponse.Size(m)
}
func (m *NewAddressResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_NewAddressResponse.DiscardUnknown(m)
}

var xxx_messageInfo_NewAddressResponse proto.InternalMessageInfo

func (m *NewAddressResponse) GetIndex() int64 {
	if m != nil {
		return m.Index
	}
	return 0
}

func (m *NewAddressResponse) GetAddr() string {
	if m != nil {
		return m.Addr
	}
	return ""
}

func (m *NewAddressResponse) GetPubKey() string {
	if m != nil {
		return m.PubKey
	}
	return ""
}

func (m *NewAddressResponse) GetWif() string {
	if m != nil {
		return m.Wif
	}
	return ""
}

type GetInfoRequest struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *GetInfoRequest) Reset()         { *m = GetInfoRequest{} }
func (m *GetInfoRequest) String() string { return proto.CompactTextString(m) }
func (*GetInfoRequest) ProtoMessage()    {}
func (*GetInfoRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{14}
}

func (m *GetInfoRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_GetInfoRequest.Unmarshal(m, b)
}
func (m *GetInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_GetInfoRequest.Marshal(b, m, deterministic)
}
func (m *GetInfoRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_GetInfoRequest.Merge(m, src)
}
func (m *GetInfoRequest) XXX_Size() int {
	return xxx_messageInfo_GetInfoRequest.Size(m)
}
func (m *GetInfoRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_GetInfoRequest.DiscardUnknown(m)
}

var xxx_messageInfo_GetInfoRequest proto.InternalMessageInfo

type GetInfoResponse struct {
	UserPeerId           string   `protobuf:"bytes,1,opt,name=user_peerId,json=userPeerId,proto3" json:"user_peerId,omitempty"`
	NodePeerId           string   `protobuf:"bytes,2,opt,name=node_peerId,json=nodePeerId,proto3" json:"node_peerId,omitempty"`
	NodeAddress          string   `protobuf:"bytes,3,opt,name=node_address,json=nodeAddress,proto3" json:"node_address,omitempty"`
	HtlcFeeRate          float64  `protobuf:"fixed64,4,opt,name=htlc_fee_rate,json=htlcFeeRate,proto3" json:"htlc_fee_rate,omitempty"`
	HtlcMaxFee           float64  `protobuf:"fixed64,5,opt,name=htlc_max_fee,json=htlcMaxFee,proto3" json:"htlc_max_fee,omitempty"`
	ChainNodeType        string   `protobuf:"bytes,6,opt,name=chain_node_type,json=chainNodeType,proto3" json:"chain_node_type,omitempty"`
	IsAdmin              bool     `protobuf:"varint,7,opt,name=is_admin,json=isAdmin,proto3" json:"is_admin,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *GetInfoResponse) Reset()         { *m = GetInfoResponse{} }
func (m *GetInfoResponse) String() string { return proto.CompactTextString(m) }
func (*GetInfoResponse) ProtoMessage()    {}
func (*GetInfoResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{15}
}

func (m *GetInfoResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_GetInfoResponse.Unmarshal(m, b)
}
func (m *GetInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_GetInfoResponse.Marshal(b, m, deterministic)
}
func (m *GetInfoResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_GetInfoResponse.Merge(m, src)
}
func (m *GetInfoResponse) XXX_Size() int {
	return xxx_messageInfo_GetInfoResponse.Size(m)
}
func (m *GetInfoResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_GetInfoResponse.DiscardUnknown(m)
}

var xxx_messageInfo_GetInfoResponse proto.InternalMessageInfo

func (m *GetInfoResponse) GetUserPeerId() string {
	if m != nil {
		return m.UserPeerId
	}
	return ""
}

func (m *GetInfoResponse) GetNodePeerId() string {
	if m != nil {
		return m.NodePeerId
	}
	return ""
}

func (m *GetInfoResponse) GetNodeAddress() string {
	if m != nil {
		return m.NodeAddress
	}
	return ""
}

func (m *GetInfoResponse) GetHtlcFeeRate() float64 {
	if m != nil {
		return m.HtlcFeeRate
	}
	return 0
}

func (m *GetInfoResponse) GetHtlcMaxFee() float64 {
	if m != nil {
		return m.HtlcMaxFee
	}
	return 0
}

func (m *GetInfoResponse) GetChainNodeType() string {
	if m != nil {
		return m.ChainNodeType
	}
	return ""
}

func (m *GetInfoResponse) GetIsAdmin() bool {
	if m != nil {
		return m.IsAdmin
	}
	return false
}

type Peer struct {
	// The identity pubkey of the peer
	PubKey string `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"`
	// Network address of the peer; eg `127.0.0.1:10011`
	Address              string   `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *Peer) Reset()         { *m = Peer{} }
func (m *Peer) String() string { return proto.CompactTextString(m) }
func (*Peer) ProtoMessage()    {}
func (*Peer) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{16}
}

func (m *Peer) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Peer.Unmarshal(m, b)
}
func (m *Peer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Peer.Marshal(b, m, deterministic)
}
func (m *Peer) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Peer.Merge(m, src)
}
func (m *Peer) XXX_Size() int {
	return xxx_messageInfo_Peer.Size(m)
}
func (m *Peer) XXX_DiscardUnknown() {
	xxx_messageInfo_Peer.DiscardUnknown(m)
}

var xxx_messageInfo_Peer proto.InternalMessageInfo

func (m *Peer) GetPubKey() string {
	if m != nil {
		return m.PubKey
	}
	return ""
}

func (m *Peer) GetAddress() string {
	if m != nil {
		return m.Address
	}
	return ""
}

type ListPeersRequest struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ListPeersRequest) Reset()         { *m = ListPeersRequest{} }
func (m *ListPeersRequest) String() string { return proto.CompactTextString(m) }
func (*ListPeersRequest) ProtoMessage()    {}
func (*ListPeersRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{17}
}

func (m *ListPeersRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ListPeersRequest.Unmarshal(m, b)
}
func (m *ListPeersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ListPeersRequest.Marshal(b, m, deterministic)
}
func (m *ListPeersRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ListPeersRequest.Merge(m, src)
}
func (m *ListPeersRequest) XXX_Size() int {
	return xxx_messageInfo_ListPeersRequest.Size(m)
}
func (m *ListPeersRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ListPeersRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ListPeersRequest proto.InternalMessageInfo

type ListPeersResponse struct {
	// The list of currently connected peers
	Peers                []*Peer  `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ListPeersResponse) Reset()         { *m = ListPeersResponse{} }
func (m *ListPeersResponse) String() string { return proto.CompactTextString(m) }
func (*ListPeersResponse) ProtoMessage()    {}
func (*ListPeersResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{18}
}

func (m *ListPeersResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ListPeersResponse.Unmarshal(m, b)
}
func (m *ListPeersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ListPeersResponse.Marshal(b, m, deterministic)
}
func (m *ListPeersResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ListPeersResponse.Merge(m, src)
}
func (m *ListPeersResponse) XXX_Size() int {
	return xxx_messageInfo_ListPeersResponse.Size(m)
}
func (m *ListPeersResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_ListPeersResponse.DiscardUnknown(m)
}

var xxx_messageInfo_ListPeersResponse proto.InternalMessageInfo

func (m *ListPeersResponse) GetPeers() []*Peer {
	if m != nil {
		return m.Peers
	}
	return nil
}

type GetAddressInfoRequest struct {
	Addr                 string   `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *GetAddressInfoRequest) Reset()         { *m = GetAddressInfoRequest{} }
func (m *GetAddressInfoRequest) String() string { return proto.CompactTextString(m) }
func (*GetAddressInfoRequest) ProtoMessage()    {}
func (*GetAddressInfoRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_b88fd140af4deb6f, []int{19}
}

func (m *GetAddressInfoRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_GetAddressInfoRequest.Unmarshal(m, b)
}
func (m *GetAddressInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_GetAddressInfoRequest.Marshal(b, m, deterministic)
}
func (m *GetAddressInfoRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_GetAddressInfoRequest.Merge(m, src)
}
func (m *GetAddressInfoRequest) XXX_Size() int {
	return xxx_messageInfo_GetAddressInfoRequest.Size(m)
}
func (m *GetAddressInfoRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_GetAddressInfoRequest.DiscardUnknown(m)
}

var xxx_messageInfo_GetAddressInfoRequest proto.InternalMessageInfo

func (m *GetAddressInfoRequest) GetAddr() string {
	if m != nil {
		return m.Addr
	}
	return ""
}

func init() {
	proto.RegisterType((*LoginRequest)(nil), "proxy.LoginRequest")
	proto.RegisterType((*LoginResponse)(nil), "proxy.LoginResponse")
	proto.RegisterType((*ChangePasswordRequest)(nil), "proxy.ChangePasswordRequest")
	proto.RegisterType((*ChangePasswordResponse)(nil), "proxy.ChangePasswordResponse")
	proto.RegisterType((*LogoutRequest)(nil), "proxy.LogoutRequest")
	proto.RegisterType((*LogoutResponse)(nil), "proxy.LogoutResponse")
	proto.RegisterType((*GenSeedRequest)(nil), "proxy.GenSeedRequest")
	proto.RegisterType((*GenSeedResponse)(nil), "proxy.GenSeedResponse")
	proto.RegisterType((*EstimateFeeRequest)(nil), "proxy.EstimateFeeRequest")
	proto.RegisterType((*EstimateFeeResponse)(nil), "proxy.EstimateFeeResponse")
	proto.RegisterType((*AddrRequest)(nil), "proxy.AddrRequest")
	proto.RegisterType((*AddrResponse)(nil), "proxy.AddrResponse")
	proto.RegisterType((*NewAddressRequest)(nil), "proxy.NewAddressRequest")
	proto.RegisterType((*NewAddressResponse)(nil), "proxy.NewAddressResponse")
	proto.RegisterType((*GetInfoRequest)(nil), "proxy.GetInfoRequest")
	proto.RegisterType((*GetInfoResponse)(nil), "proxy.GetInfoResponse")
	proto.RegisterType((*Peer)(nil), "proxy.Peer")
	proto.RegisterType((*ListPeersRequest)(nil), "proxy.ListPeersRequest")
	proto.RegisterType((*ListPeersResponse)(nil), "proxy.ListPeersResponse")
	proto.RegisterType((*GetAddressInfoRequest)(nil), "proxy.GetAddressInfoRequest")
}

func init() {
	proto.RegisterFile("wallet.proto", fileDescriptor_b88fd140af4deb6f)
}

var fileDescriptor_b88fd140af4deb6f = []byte{
	// 846 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x56, 0x4b, 0x6f, 0xdb, 0x46,
	0x10, 0x06, 0x6d, 0xbd, 0x3c, 0x92, 0x2d, 0x79, 0xfd, 0x08, 0x4d, 0xa4, 0x88, 0xb2, 0x87, 0xd6,
	0x45, 0x00, 0x23, 0xb0, 0x91, 0xa2, 0xbd, 0x14, 0x70, 0xd3, 0x24, 0x08, 0xfc, 0x80, 0xc1, 0x1a,
	0x28, 0xd0, 0x0b, 0xbb, 0x16, 0x47, 0x16, 0x61, 0x69, 0xc9, 0xee, 0xae, 0x20, 0xa9, 0x3f, 0xb7,
	0xff, 0xa2, 0xa7, 0x16, 0xbb, 0x1c, 0x52, 0x94, 0xac, 0x1e, 0x7b, 0xc9, 0x4d, 0xfb, 0xcd, 0xf7,
	0xcd, 0xcc, 0xce, 0xcc, 0x0e, 0x05, 0x9d, 0x99, 0x18, 0x8f, 0xd1, 0x9c, 0x65, 0x2a, 0x35, 0x29,
	0xab, 0x67, 0x2a, 0x9d, 0x2f, 0xf8, 0x15, 0x74, 0xae, 0xd3, 0xc7, 0x44, 0x86, 0xf8, 0xc7, 0x14,
	0xb5, 0x61, 0x01, 0xb4, 0x26, 0x12, 0x27, 0xa9, 0x4c, 0x06, 0xbe, 0xd7, 0xf7, 0x4e, 0x77, 0xc2,
	0xf2, 0xcc, 0x5e, 0x41, 0x7b, 0x6c, 0xb9, 0x91, 0x49, 0x9f, 0x50, 0xfa, 0x5b, 0xce, 0x0c, 0x0e,
	0xba, 0xb7, 0x08, 0xff, 0xcb, 0x83, 0x5d, 0xf2, 0xa6, 0xb3, 0x54, 0x6a, 0xb4, 0x92, 0xa9, 0x46,
	0x15, 0x65, 0x88, 0xea, 0x73, 0x4c, 0x1e, 0xc1, 0x42, 0x77, 0x0e, 0xb1, 0x04, 0x99, 0xc6, 0x58,
	0x10, 0xc8, 0xa7, 0x85, 0x88, 0xf0, 0x1a, 0x3a, 0x8e, 0x20, 0xe2, 0x58, 0xa1, 0xd6, 0xfe, 0xb6,
	0x63, 0x38, 0xd1, 0x65, 0x0e, 0x31, 0x0e, 0xbb, 0x23, 0x33, 0x1e, 0x44, 0x43, 0xc4, 0x48, 0x09,
	0x83, 0x7e, 0xad, 0xef, 0x9d, 0x7a, 0x61, 0xdb, 0x82, 0x1f, 0x11, 0x43, 0x61, 0x90, 0xf5, 0xa1,
	0xe3, 0x38, 0x13, 0x31, 0xb7, 0x3c, 0xbf, 0xee, 0x28, 0x60, 0xb1, 0x1b, 0x31, 0xff, 0x88, 0xc8,
	0xbe, 0x86, 0xee, 0x60, 0x24, 0x12, 0x19, 0xb9, 0x70, 0x66, 0x91, 0xa1, 0xdf, 0x70, 0xb1, 0x76,
	0x1d, 0x7c, 0x9b, 0xc6, 0x78, 0xbf, 0xc8, 0x90, 0x23, 0x1c, 0xbd, 0x1f, 0x09, 0xf9, 0x88, 0x77,
	0x42, 0xeb, 0x59, 0xaa, 0xe2, 0xa2, 0x74, 0xdf, 0x42, 0x6f, 0x30, 0x55, 0x0a, 0xa5, 0x89, 0x32,
	0x32, 0xd1, 0x85, 0xbb, 0x84, 0x17, 0x0a, 0x77, 0x29, 0x9c, 0x2d, 0x69, 0x5b, 0x74, 0x29, 0x9c,
	0x15, 0x14, 0xfe, 0x16, 0x8e, 0xd7, 0xc3, 0x50, 0x4d, 0x8f, 0xa1, 0xa1, 0x50, 0x4f, 0xc7, 0x86,
	0xbc, 0xd3, 0x89, 0x77, 0x5d, 0xf1, 0xd3, 0xa9, 0xa1, 0x84, 0x78, 0x0f, 0xf6, 0x0a, 0x20, 0x97,
	0xf2, 0xdf, 0x61, 0xef, 0x13, 0xca, 0x5f, 0x10, 0xcb, 0xa4, 0xdf, 0xc0, 0xbe, 0xc0, 0x3f, 0x11,
	0x63, 0x97, 0x4c, 0x36, 0x52, 0x42, 0xa3, 0xf3, 0xdb, 0x09, 0x7b, 0xb9, 0xe1, 0xae, 0xc4, 0x6d,
	0xda, 0xda, 0x52, 0x51, 0x1a, 0x95, 0x66, 0x0b, 0x97, 0x76, 0x27, 0x6c, 0x5b, 0xec, 0x43, 0x0e,
	0xf1, 0x31, 0x74, 0xcb, 0x08, 0x94, 0xef, 0x5b, 0x38, 0x1c, 0x24, 0xd9, 0x08, 0x55, 0xe4, 0xc4,
	0x6b, 0xe3, 0xc5, 0x72, 0x9b, 0x55, 0xdc, 0x14, 0x83, 0xf6, 0x0d, 0x74, 0x51, 0xe6, 0x38, 0xc6,
	0x4e, 0x45, 0x15, 0xda, 0x5b, 0xc2, 0x56, 0xc0, 0xdf, 0x01, 0xfb, 0xa0, 0x4d, 0x32, 0x11, 0x06,
	0x6d, 0xa3, 0xe9, 0x4e, 0xaf, 0xa0, 0x3d, 0x48, 0xe5, 0x30, 0x32, 0x42, 0x3d, 0x62, 0x5e, 0xa5,
	0x7a, 0x08, 0x16, 0xba, 0x77, 0x08, 0xbf, 0x80, 0x83, 0x15, 0x19, 0x25, 0xfa, 0x12, 0x40, 0x0b,
	0x13, 0x65, 0xa8, 0xa2, 0xa7, 0x99, 0x93, 0x6d, 0x87, 0x2d, 0x2d, 0xcc, 0x1d, 0xaa, 0xab, 0x19,
	0xdf, 0x85, 0xb6, 0x1d, 0xb8, 0xa2, 0xb8, 0x03, 0xe8, 0xe4, 0x47, 0x12, 0x1f, 0x42, 0x3d, 0x91,
	0x31, 0xce, 0x49, 0x97, 0x1f, 0x18, 0x83, 0x9a, 0x1d, 0x5c, 0x4a, 0xdf, 0xfd, 0x66, 0x2f, 0xa0,
	0x99, 0x4d, 0x1f, 0xa2, 0x27, 0x5c, 0xd0, 0x30, 0x37, 0xb2, 0xe9, 0xc3, 0x15, 0x2e, 0x58, 0x0f,
	0xb6, 0x67, 0xc9, 0xd0, 0x4d, 0xef, 0x4e, 0x68, 0x7f, 0xf2, 0x03, 0xd8, 0xbf, 0xc5, 0x19, 0xcd,
	0x79, 0x11, 0x39, 0x01, 0x56, 0x05, 0xff, 0xcf, 0xf8, 0x3d, 0x3b, 0x2f, 0xe6, 0xb3, 0x1c, 0xa6,
	0x45, 0xf0, 0x7f, 0x3c, 0xdb, 0x60, 0x82, 0xbe, 0xd8, 0x47, 0xce, 0x4e, 0xa0, 0x95, 0xe8, 0x48,
	0xc4, 0x93, 0x44, 0xfa, 0xcd, 0xbe, 0x77, 0xda, 0x0a, 0x9b, 0x89, 0xbe, 0xb4, 0x47, 0xfe, 0x03,
	0xd4, 0x6c, 0xd6, 0xd5, 0x32, 0x7a, 0x2b, 0x65, 0xf4, 0xa1, 0x59, 0xdc, 0x23, 0xbf, 0x69, 0x71,
	0xe4, 0x0c, 0x7a, 0xd7, 0x89, 0x36, 0x56, 0x5e, 0x76, 0xf3, 0x3b, 0xd8, 0xaf, 0x60, 0x54, 0xd1,
	0xd7, 0x50, 0xb7, 0xb5, 0xd2, 0xbe, 0xd7, 0xdf, 0x3e, 0x6d, 0x9f, 0xb7, 0xcf, 0xdc, 0xb2, 0x3e,
	0xb3, 0xa4, 0x30, 0xb7, 0xf0, 0x37, 0x70, 0xf4, 0x09, 0x0d, 0x55, 0xa7, 0xd2, 0xa1, 0xb2, 0xe5,
	0xde, 0xb2, 0xe5, 0xe7, 0x7f, 0xd7, 0xa0, 0xf1, 0xab, 0xdb, 0xfe, 0xec, 0x47, 0xd8, 0x29, 0xe3,
	0xb1, 0x17, 0xe4, 0x78, 0x3d, 0xab, 0xc0, 0x7f, 0x6e, 0xa0, 0xd4, 0xbe, 0x87, 0x26, 0x3d, 0x70,
	0x76, 0x44, 0xa4, 0xd5, 0x95, 0x12, 0x1c, 0xaf, 0xc3, 0xa4, 0x3c, 0x87, 0xba, 0xfb, 0x38, 0xb0,
	0x83, 0xc2, 0x79, 0xe5, 0xc3, 0x13, 0x1c, 0xae, 0x82, 0xa4, 0xb9, 0x81, 0xbd, 0xd5, 0x2d, 0xc8,
	0x5e, 0x12, 0x6f, 0xe3, 0x0e, 0x0e, 0xbe, 0xfa, 0x0f, 0x2b, 0xb9, 0x7b, 0x07, 0x8d, 0x7c, 0x23,
	0xb2, 0x4a, 0xb8, 0xe5, 0xc6, 0x0c, 0x8e, 0xd6, 0x50, 0x92, 0xfd, 0x0c, 0xed, 0xca, 0xbe, 0x60,
	0x27, 0xc4, 0x7a, 0xbe, 0x7a, 0x82, 0x60, 0x93, 0xa9, 0x5a, 0x39, 0xf7, 0x72, 0x2a, 0x95, 0xab,
	0x3e, 0xae, 0x4a, 0xe5, 0x56, 0x1f, 0xd8, 0x05, 0xb4, 0x6e, 0x71, 0xee, 0x9a, 0xcd, 0x18, 0x71,
	0x2a, 0xbb, 0x28, 0x38, 0x58, 0xc1, 0x48, 0x74, 0x09, 0xb0, 0x5c, 0x13, 0xac, 0x68, 0xe8, 0xb3,
	0x75, 0x12, 0x9c, 0x6c, 0xb0, 0x90, 0x8b, 0xf7, 0xee, 0xf9, 0x57, 0x66, 0xac, 0xac, 0xfe, 0xc6,
	0xd1, 0xdb, 0x98, 0xc7, 0x4f, 0xb5, 0xdf, 0xb6, 0xb2, 0x87, 0x87, 0x86, 0xfb, 0xd7, 0x71, 0xf1,
	0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0b, 0x78, 0xe6, 0x79, 0x85, 0x08, 0x00, 0x00,
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// WalletClient is the client API for Wallet service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type WalletClient interface {
	ListPeers(ctx context.Context, in *ListPeersRequest, opts ...grpc.CallOption) (*ListPeersResponse, error)
	GenSeed(ctx context.Context, in *GenSeedRequest, opts ...grpc.CallOption) (*GenSeedResponse, error)
	Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error)
	ChangePassword(ctx context.Context, in *ChangePasswordRequest, opts ...grpc.CallOption) (*ChangePasswordResponse, error)
	Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error)
	EstimateFee(ctx context.Context, in *EstimateFeeRequest, opts ...grpc.CallOption) (*EstimateFeeResponse, error)
	GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error)
	//
	//NextAddr returns the next unused address within the wallet.
	NextAddr(ctx context.Context, in *AddrRequest, opts ...grpc.CallOption) (*AddrResponse, error)
	NewAddress(ctx context.Context, in *NewAddressRequest, opts ...grpc.CallOption) (*NewAddressResponse, error)
	GetAddressInfo(ctx context.Context, in *GetAddressInfoRequest, opts ...grpc.CallOption) (*AddrResponse, error)
}

type walletClient struct {
	cc grpc.ClientConnInterface
}

func NewWalletClient(cc grpc.ClientConnInterface) WalletClient {
	return &walletClient{cc}
}

func (c *walletClient) ListPeers(ctx context.Context, in *ListPeersRequest, opts ...grpc.CallOption) (*ListPeersResponse, error) {
	out := new(ListPeersResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/ListPeers", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) GenSeed(ctx context.Context, in *GenSeedRequest, opts ...grpc.CallOption) (*GenSeedResponse, error) {
	out := new(GenSeedResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/GenSeed", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) {
	out := new(LoginResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/Login", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) ChangePassword(ctx context.Context, in *ChangePasswordRequest, opts ...grpc.CallOption) (*ChangePasswordResponse, error) {
	out := new(ChangePasswordResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/ChangePassword", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error) {
	out := new(LogoutResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/Logout", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) EstimateFee(ctx context.Context, in *EstimateFeeRequest, opts ...grpc.CallOption) (*EstimateFeeResponse, error) {
	out := new(EstimateFeeResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/EstimateFee", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error) {
	out := new(GetInfoResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/GetInfo", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) NextAddr(ctx context.Context, in *AddrRequest, opts ...grpc.CallOption) (*AddrResponse, error) {
	out := new(AddrResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/NextAddr", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) NewAddress(ctx context.Context, in *NewAddressRequest, opts ...grpc.CallOption) (*NewAddressResponse, error) {
	out := new(NewAddressResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/NewAddress", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *walletClient) GetAddressInfo(ctx context.Context, in *GetAddressInfoRequest, opts ...grpc.CallOption) (*AddrResponse, error) {
	out := new(AddrResponse)
	err := c.cc.Invoke(ctx, "/proxy.Wallet/GetAddressInfo", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// WalletServer is the server API for Wallet service.
type WalletServer interface {
	ListPeers(context.Context, *ListPeersRequest) (*ListPeersResponse, error)
	GenSeed(context.Context, *GenSeedRequest) (*GenSeedResponse, error)
	Login(context.Context, *LoginRequest) (*LoginResponse, error)
	ChangePassword(context.Context, *ChangePasswordRequest) (*ChangePasswordResponse, error)
	Logout(context.Context, *LogoutRequest) (*LogoutResponse, error)
	EstimateFee(context.Context, *EstimateFeeRequest) (*EstimateFeeResponse, error)
	GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error)
	//
	//NextAddr returns the next unused address within the wallet.
	NextAddr(context.Context, *AddrRequest) (*AddrResponse, error)
	NewAddress(context.Context, *NewAddressRequest) (*NewAddressResponse, error)
	GetAddressInfo(context.Context, *GetAddressInfoRequest) (*AddrResponse, error)
}

// UnimplementedWalletServer can be embedded to have forward compatible implementations.
type UnimplementedWalletServer struct {
}

func (*UnimplementedWalletServer) ListPeers(ctx context.Context, req *ListPeersRequest) (*ListPeersResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ListPeers not implemented")
}
func (*UnimplementedWalletServer) GenSeed(ctx context.Context, req *GenSeedRequest) (*GenSeedResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method GenSeed not implemented")
}
func (*UnimplementedWalletServer) Login(ctx context.Context, req *LoginRequest) (*LoginResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
}
func (*UnimplementedWalletServer) ChangePassword(ctx context.Context, req *ChangePasswordRequest) (*ChangePasswordResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ChangePassword not implemented")
}
func (*UnimplementedWalletServer) Logout(ctx context.Context, req *LogoutRequest) (*LogoutResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method Logout not implemented")
}
func (*UnimplementedWalletServer) EstimateFee(ctx context.Context, req *EstimateFeeRequest) (*EstimateFeeResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method EstimateFee not implemented")
}
func (*UnimplementedWalletServer) GetInfo(ctx context.Context, req *GetInfoRequest) (*GetInfoResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method GetInfo not implemented")
}
func (*UnimplementedWalletServer) NextAddr(ctx context.Context, req *AddrRequest) (*AddrResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method NextAddr not implemented")
}
func (*UnimplementedWalletServer) NewAddress(ctx context.Context, req *NewAddressRequest) (*NewAddressResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method NewAddress not implemented")
}
func (*UnimplementedWalletServer) GetAddressInfo(ctx context.Context, req *GetAddressInfoRequest) (*AddrResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method GetAddressInfo not implemented")
}

func RegisterWalletServer(s *grpc.Server, srv WalletServer) {
	s.RegisterService(&_Wallet_serviceDesc, srv)
}

func _Wallet_ListPeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ListPeersRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).ListPeers(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/ListPeers",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).ListPeers(ctx, req.(*ListPeersRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_GenSeed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(GenSeedRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).GenSeed(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/GenSeed",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).GenSeed(ctx, req.(*GenSeedRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(LoginRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).Login(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/Login",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).Login(ctx, req.(*LoginRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_ChangePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ChangePasswordRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).ChangePassword(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/ChangePassword",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).ChangePassword(ctx, req.(*ChangePasswordRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_Logout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(LogoutRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).Logout(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/Logout",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).Logout(ctx, req.(*LogoutRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_EstimateFee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(EstimateFeeRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).EstimateFee(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/EstimateFee",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).EstimateFee(ctx, req.(*EstimateFeeRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_GetInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(GetInfoRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).GetInfo(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/GetInfo",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).GetInfo(ctx, req.(*GetInfoRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_NextAddr_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(AddrRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).NextAddr(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/NextAddr",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).NextAddr(ctx, req.(*AddrRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_NewAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(NewAddressRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).NewAddress(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/NewAddress",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).NewAddress(ctx, req.(*NewAddressRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Wallet_GetAddressInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(GetAddressInfoRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(WalletServer).GetAddressInfo(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Wallet/GetAddressInfo",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(WalletServer).GetAddressInfo(ctx, req.(*GetAddressInfoRequest))
	}
	return interceptor(ctx, in, info, handler)
}

var _Wallet_serviceDesc = grpc.ServiceDesc{
	ServiceName: "proxy.Wallet",
	HandlerType: (*WalletServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "ListPeers",
			Handler:    _Wallet_ListPeers_Handler,
		},
		{
			MethodName: "GenSeed",
			Handler:    _Wallet_GenSeed_Handler,
		},
		{
			MethodName: "Login",
			Handler:    _Wallet_Login_Handler,
		},
		{
			MethodName: "ChangePassword",
			Handler:    _Wallet_ChangePassword_Handler,
		},
		{
			MethodName: "Logout",
			Handler:    _Wallet_Logout_Handler,
		},
		{
			MethodName: "EstimateFee",
			Handler:    _Wallet_EstimateFee_Handler,
		},
		{
			MethodName: "GetInfo",
			Handler:    _Wallet_GetInfo_Handler,
		},
		{
			MethodName: "NextAddr",
			Handler:    _Wallet_NextAddr_Handler,
		},
		{
			MethodName: "NewAddress",
			Handler:    _Wallet_NewAddress_Handler,
		},
		{
			MethodName: "GetAddressInfo",
			Handler:    _Wallet_GetAddressInfo_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "wallet.proto",
}


<|start_filename|>bean/json_date.go<|end_filename|>
package bean

import (
	"fmt"
	"time"
)

//
type JsonDate time.Time

// set time formate
const (
	timeFormat = "2006-01-02"
)

// JsonDate deserialize
func (t *JsonDate) UnmarshalJSON(data []byte) (err error) {
	if len(data) != 12 {
		return
	}
	newTime, err := time.ParseInLocation("\""+timeFormat+"\"", string(data), time.Local)
	*t = JsonDate(newTime)
	return
}

// JsonDate序列化
func (t JsonDate) MarshalJSON() ([]byte, error) {
	timeStr := fmt.Sprintf("\"%s\"", time.Time(t).Format(timeFormat))
	return []byte(timeStr), nil
}

// string方法
func (t JsonDate) String() string {
	return time.Time(t).Format(timeFormat)
}


<|start_filename|>tracker/service/rpc_service.go<|end_filename|>
package service

import (
	"github.com/gin-gonic/gin"
	"github.com/omnilaboratory/obd/tool"
	"github.com/omnilaboratory/obd/tracker/bean"
	"github.com/omnilaboratory/obd/tracker/config"
	"github.com/omnilaboratory/obd/tracker/rpc"
	"github.com/tidwall/gjson"
	"net/http"
	"strconv"
	"sync"
	"time"
)

type rpcManager struct {
	mu sync.Mutex
}

var RpcService rpcManager

func (manager *rpcManager) GetOmniBalance(context *gin.Context) {
	reqData := &bean.GetOmniBalanceRequest{}
	reqData.Address = context.Query("address")
	if tool.CheckIsString(&reqData.Address) == false {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error Address",
		})
		return
	}
	reqData.PropertyId, _ = strconv.Atoi(context.Query("propertyId"))
	if reqData.PropertyId == 0 {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error propertyId",
		})
		return
	}

	getbalance, err := rpc.NewClient().OmniGetbalance(reqData.Address, reqData.PropertyId)
	balance := 0.0
	if err == nil {
		balance = gjson.Get(getbalance, "balance").Float()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "OmniGetbalance",
		"data": balance,
	})
}
func (manager *rpcManager) GetBalanceByAddress(context *gin.Context) {
	address := context.Query("address")
	var result string
	var msg string
	if tool.CheckIsAddress(address) == false {
		msg = "wrong address"
	}
	getbalance, err := rpc.NewClient().GetBalanceByAddress(address)
	if err != nil {
		msg = err.Error()
	}
	f, flag := getbalance.Float64()
	if flag == false {
		msg = "wrong balance"
	}
	result = tool.FloatToString(f, 8)
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) ImportAddress(context *gin.Context) {
	address := context.Query("address")
	if tool.CheckIsAddress(address) == false {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error Address",
		})
		return
	}

	_, _ = rpc.NewClient().ValidateAddress(address)
	context.JSON(http.StatusOK, gin.H{
		"msg": "OmniGetbalance",
	})
}

type cacheListReceivedByAddressInfo struct {
	SpanTime time.Time
	Result   string
}

var cacheListReceivedByAddress map[string]cacheListReceivedByAddressInfo

func (manager *rpcManager) ListReceivedByAddress(context *gin.Context) {
	address := context.Query("address")
	if tool.CheckIsString(&address) == false {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error Address",
		})
		return
	}

	if cacheListReceivedByAddress == nil {
		cacheListReceivedByAddress = make(map[string]cacheListReceivedByAddressInfo)
	}
	cacheInfo := cacheListReceivedByAddress[address]
	if cacheInfo.SpanTime.IsZero() == false {
		if time.Now().Sub(cacheInfo.SpanTime).Minutes() > 2 {
			if cacheInfo.Result != "" {
				cacheInfo.Result = ""
			}
		}
	}
	if cacheInfo.Result == "" {
		temp, err := rpc.NewClient().ListReceivedByAddress(address)
		if err != nil {
			context.JSON(http.StatusInternalServerError, gin.H{
				"msg": err.Error(),
			})
			return
		}
		cacheInfo.Result = temp
		cacheInfo.SpanTime = time.Now()
		cacheListReceivedByAddress[address] = cacheInfo
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "OmniGetbalance",
		"data": cacheInfo.Result,
	})
}
func (manager *rpcManager) ListUnspent(context *gin.Context) {
	address := context.Query("address")
	if tool.CheckIsString(&address) == false {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error Address",
		})
		return
	}
	result, err := rpc.NewClient().ListUnspent(address)
	if err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "ListUnspent",
		"data": result,
	})
}
func (manager *rpcManager) OmniGetAllBalancesForAddress(context *gin.Context) {
	address := context.Query("address")
	if tool.CheckIsString(&address) == false {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error Address",
		})
		return
	}
	result, err := rpc.NewClient().OmniGetAllBalancesForAddress(address)
	if err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "OmniGetAllBalancesForAddress",
		"data": result,
	})
}
func (manager *rpcManager) OmniGetBalancesForAddress(context *gin.Context) {
	address := context.Query("address")
	propertyId, _ := strconv.Atoi(context.Query("propertyId"))
	if tool.CheckIsString(&address) == false {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error Address",
		})
		return
	}
	result, err := rpc.NewClient().OmniGetbalance(address, propertyId)
	if err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "OmniGetAllBalancesForAddress",
		"data": result,
	})
}
func (manager *rpcManager) TestMemPoolAccept(context *gin.Context) {
	hex := context.Query("hex")
	result, err := rpc.NewClient().TestMemPoolAccept(hex)
	if err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "TestMemPoolAccept",
		"data": result,
	})
}
func (manager *rpcManager) SendRawTransaction(context *gin.Context) {
	hex := context.Query("hex")
	result, err := rpc.NewClient().SendRawTransaction(hex)
	msg := ""
	if err != nil {
		result = ""
		msg = err.Error()
	}

	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}
func (manager *rpcManager) OmniDecodeTransaction(context *gin.Context) {
	hex := context.Query("hex")
	result, err := rpc.NewClient().OmniDecodeTransaction(hex)
	msg := ""
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) OmniListTransactions(context *gin.Context) {
	address := context.Query("address")
	result, err := rpc.NewClient().OmniListTransactions(address, 100, 0)
	msg := ""
	if err != nil {
		result = ""
		msg = err.Error()
	}
	if result == "[]" {
		result = ""
		msg = "no tx"
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) GetNewAddress(context *gin.Context) {
	label := context.Query("label")
	result, err := rpc.NewClient().GetNewAddress(label)
	msg := ""
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) OmniSend(context *gin.Context) {
	fromAddress := context.Query("fromAddress")
	msg := ""
	if tool.CheckIsAddress(fromAddress) == false {
		msg = "wrong fromAddress"
	}

	toAddress := context.Query("toAddress")
	if tool.CheckIsAddress(toAddress) == false {
		msg = "wrong toAddress"
	}

	propertyIdStr := context.Query("propertyId")

	propertyId, err := strconv.Atoi(propertyIdStr)
	if err != nil {
		msg = "wrong propertyId"
	}
	amountStr := context.Query("amount")
	amount, err := strconv.ParseFloat(amountStr, 64)
	if err != nil {
		msg = "wrong amount"
	}

	result, err := rpc.NewClient().OmniSend(fromAddress, toAddress, propertyId, amount)
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) OmniListProperties(context *gin.Context) {
	result, err := rpc.NewClient().OmniListProperties()
	msg := ""
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) OmniSendIssuanceFixed(context *gin.Context) {
	fromAddress := context.Query("fromAddress")
	msg := ""
	if tool.CheckIsAddress(fromAddress) == false {
		msg = "wrong fromAddress"
	}

	ecosystem, err := strconv.Atoi(context.Query("ecosystem"))
	if err != nil {
		msg = "wrong ecosystem"
	}
	divisibleType, err := strconv.Atoi(context.Query("divisibleType"))
	if err != nil {
		msg = "wrong divisibleType"
	}
	name := context.Query("name")
	data := context.Query("data")

	amount, err := strconv.ParseFloat(context.Query("amount"), 64)
	if err != nil {
		msg = "wrong amount"
	}

	result, err := rpc.NewClient().OmniSendIssuanceFixed(fromAddress, ecosystem, divisibleType, name, data, amount)
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}
func (manager *rpcManager) OmniSendIssuanceManaged(context *gin.Context) {
	fromAddress := context.Query("fromAddress")
	msg := ""
	if tool.CheckIsAddress(fromAddress) == false {
		msg = "wrong fromAddress"
	}

	ecosystem, err := strconv.Atoi(context.Query("ecosystem"))
	if err != nil {
		msg = "wrong ecosystem"
	}
	divisibleType, err := strconv.Atoi(context.Query("divisibleType"))
	if err != nil {
		msg = "wrong divisibleType"
	}
	name := context.Query("name")
	data := context.Query("data")

	result, err := rpc.NewClient().OmniSendIssuanceManaged(fromAddress, ecosystem, divisibleType, name, data)
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) OmniSendGrant(context *gin.Context) {
	fromAddress := context.Query("fromAddress")
	msg := ""
	if tool.CheckIsAddress(fromAddress) == false {
		msg = "wrong fromAddress"
	}

	propertyId, err := strconv.Atoi(context.Query("propertyId"))
	if err != nil {
		msg = "wrong propertyId"
	}
	amount, err := strconv.ParseFloat(context.Query("amount"), 64)
	if err != nil {
		msg = "wrong amount"
	}
	memo := context.Query("data")

	result, err := rpc.NewClient().OmniSendGrant(fromAddress, int64(propertyId), amount, memo)
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) OmniSendRevoke(context *gin.Context) {
	fromAddress := context.Query("fromAddress")
	msg := ""
	if tool.CheckIsAddress(fromAddress) == false {
		msg = "wrong fromAddress"
	}

	propertyId, err := strconv.Atoi(context.Query("propertyId"))
	if err != nil {
		msg = "wrong propertyId"
	}
	amount, err := strconv.ParseFloat(context.Query("amount"), 64)
	if err != nil {
		msg = "wrong amount"
	}
	memo := context.Query("data")

	result, err := rpc.NewClient().OmniSendRevoke(fromAddress, int64(propertyId), amount, memo)
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}
func (manager *rpcManager) BtcSignRawTransactionFromJson(context *gin.Context) {
	data := context.Query("data")
	result, err := rpc.NewClient().BtcSignRawTransactionFromJson(data)
	msg := ""
	if err != nil {
		result = ""
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) GetTransactionById(context *gin.Context) {
	txid := context.Query("txid")
	if tool.CheckIsString(&txid) == false {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error txid",
		})
		return
	}
	result, err := rpc.NewClient().GetTransactionById(txid)
	if err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "GetTransactionById",
		"data": result,
	})
}
func (manager *rpcManager) OmniGettransaction(context *gin.Context) {
	txid := context.Query("txid")
	var err error
	var msg string
	var result string
	if tool.CheckIsString(&txid) == false {
		msg = "error txid"
	}
	result, err = rpc.NewClient().OmniGettransaction(txid)
	if err != nil {
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}
func (manager *rpcManager) OmniGetProperty(context *gin.Context) {
	propertyId := context.Query("propertyId")
	id, err := strconv.Atoi(propertyId)
	result := ""
	msg := ""
	if err != nil {
		msg = err.Error()
	}

	result, err = rpc.NewClient().OmniGetProperty(int64(id))
	if err != nil {
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

var smartFeeSpanTime time.Time
var cacheFeeRate float64

func (manager *rpcManager) EstimateSmartFee(context *gin.Context) {
	if smartFeeSpanTime.IsZero() == false {
		if time.Now().Sub(smartFeeSpanTime).Minutes() > 10 {
			cacheFeeRate = 0
		}
	}
	confTarget := 10
	if context.Query("confTarget") != "" {
		confTarget, _ = strconv.Atoi(context.Query("confTarget"))
	}

	if cacheFeeRate == 0 {
		fee := rpc.NewClient().EstimateSmartFee(confTarget)
		cacheFeeRate = fee
		smartFeeSpanTime = time.Now()
	}

	context.JSON(http.StatusOK, gin.H{
		"msg":  "EstimateSmartFee",
		"data": cacheFeeRate,
	})
}
func (manager *rpcManager) CreateRawTransaction(context *gin.Context) {

	data := make(map[string]interface{})
	err := context.BindJSON(&data)
	if err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": "error data",
		})
		return
	}
	inputItems := data["inputs"].([]interface{})
	inputs := make([]map[string]interface{}, 0)
	for _, node := range inputItems {
		item := node.(map[string]interface{})
		inputs = append(inputs, item)
	}

	outputs := data["outputs"].(map[string]interface{})
	result, err := rpc.NewClient().CreateRawTransaction(inputs, outputs)
	if err != nil {
		context.JSON(http.StatusInternalServerError, gin.H{
			"msg": err.Error(),
		})
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "CreateRawTransaction",
		"data": result,
	})
}

var blockSpanTime time.Time
var cacheBlockCount int

func (manager *rpcManager) GetBlockCount(context *gin.Context) {
	if blockSpanTime.IsZero() == false {
		if time.Now().Sub(blockSpanTime).Minutes() > 2 {
			cacheBlockCount = 0
		}
	}
	if cacheBlockCount == 0 {
		blockCount, _ := rpc.NewClient().GetBlockCount()
		cacheBlockCount = blockCount
		blockSpanTime = time.Now()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  "blockCount",
		"data": cacheBlockCount,
	})
}

func (manager *rpcManager) GetMiningInfo(context *gin.Context) {
	result, err := rpc.NewClient().GetMiningInfo()
	msg := ""
	if err != nil {
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) GetNetworkInfo(context *gin.Context) {
	result, err := rpc.NewClient().GetNetworkInfo()
	msg := ""
	if err != nil {
		msg = err.Error()
	}
	context.JSON(http.StatusOK, gin.H{
		"msg":  msg,
		"data": result,
	})
}

func (manager *rpcManager) GetChainNodeType(context *gin.Context) {

	context.JSON(http.StatusOK, gin.H{
		"msg":               "",
		"chainNodeType":     cfg.ChainNode_Type,
		"trackerP2pAddress": cfg.P2pLocalAddress,
	})
}


<|start_filename|>bean/channel_id_test.go<|end_filename|>
package bean

import (
	"github.com/omnilaboratory/obd/bean/chainhash"
	"log"
	"testing"
)

func TestNewChanIDFromOutPoint(t *testing.T) {

	hash, _ := chainhash.NewHashFromStr("4c0e8d55056c5bd3cb4404acfcfb6e3b51127fb9131d9260892ef207c8ab4380")
	op := &OutPoint{
		Hash:  *hash,
		Index: 0,
	}
	log.Println(*hash)
	point := ChannelIdService.NewChanIDFromOutPoint(op)
	log.Println(string(point[:]))
}


<|start_filename|>lightclient/connect_tracker.go<|end_filename|>
package lightclient

import (
	"encoding/json"
	"github.com/asdine/storm"
	"github.com/asdine/storm/q"
	"github.com/gorilla/websocket"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/config"
	"github.com/omnilaboratory/obd/conn"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/service"
	"github.com/omnilaboratory/obd/tool"
	trackerBean "github.com/omnilaboratory/obd/tracker/bean"
	"github.com/tidwall/gjson"
	"io/ioutil"
	"log"
	"net/url"
	"reflect"
	"strings"
	"time"
)

var conn *websocket.Conn
var ticker3m *time.Ticker
var isReset = true

func ConnectToTracker() (err error) {

	u := url.URL{Scheme: "ws", Host: config.TrackerHost, Path: "/ws"}
	log.Printf("begin to connect to tracker: %s", u.String())

	conn, _, err = websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		log.Println("fail to dial tracker:", err)
		return err
	}

	chainNodeType, trackerP2pAddress, err := conn2tracker.GetChainNodeType()
	if err != nil {
		return err
	}
	config.ChainNodeType = chainNodeType
	config.BootstrapPeers, _ = config.StringsToAddrs(strings.Split(trackerP2pAddress, ","))

	err = StartP2PNode()
	if err != nil {
		return err
	}

	if service.TrackerChan == nil {
		service.TrackerChan = make(chan []byte)
	}

	if isReset {
		go readDataFromWs()
	}

	if ticker3m == nil {
		startSchedule()
	}
	return nil
}

func readDataFromWs() {
	isReset = false
	ticker := time.NewTicker(time.Minute * 2)
	defer ticker.Stop()

	defer func(ticker *time.Ticker) {
		if r := recover(); r != nil {
			log.Println("tracker goroutine recover")
			ticker.Stop()
			conn = nil
			isReset = true
		}
	}(ticker)
	defer conn.Close()

	// read message
	go func() {
		for {
			if conn == nil {
				isReset = true
				return
			}

			_, message, err := conn.ReadMessage()
			if err != nil {
				isReset = true
				log.Println("socket to tracker get err:", err)
				conn = nil
				return
			}

			//log.Println("get data from tracker", string(message))
			replyMessage := bean.ReplyMessage{}
			err = json.Unmarshal(message, &replyMessage)
			if err == nil {
				switch replyMessage.Type {
				case enum.MsgType_Tracker_GetHtlcPath_351:
					v := reflect.ValueOf(replyMessage.Result)
					requestMessage := bean.RequestMessage{}
					requestMessage.Type = replyMessage.Type
					requestMessage.Data = ""
					if v.Kind() == reflect.Map {
						dataMap := replyMessage.Result.(map[string]interface{})
						requestMessage.RecipientUserPeerId = dataMap["senderPeerId"].(string)
						requestMessage.Data = dataMap["h"].(string) + "_" + dataMap["path"].(string) + "_" + tool.FloatToString(dataMap["amount"].(float64), 8)
						//requestMessage.Data = dataMap["h"].(string) + "_" + dataMap["path"].(string)
					}
					htlcTrackerDealModule(requestMessage)
				case enum.MsgType_Tracker_Connect_301:
					config.ChainNodeType = replyMessage.Result.(string)
					go SynData()
				}
			}
		}
	}()

	// heartbeat and check whether
	for {
		select {
		case t := <-ticker.C:
			if conn != nil {
				info := make(map[string]interface{})
				info["type"] = enum.MsgType_Tracker_HeartBeat_302
				info["data"] = t.String()
				bytes, err := json.Marshal(info)
				err = conn.WriteMessage(websocket.TextMessage, bytes)
				if err != nil {
					log.Println("HeartBeat:", err)
					isReset = true
					log.Println("socket to tracker get err:", err)
					conn = nil
					return
				}
			} else {
				return
			}
		}
	}
}

func SynData() {
	log.Println("synData to tracker")
	updateP2pAddressLogin()
	sycUserInfos()
	sycChannelInfos()
}

func updateP2pAddressLogin() {
	info := make(map[string]interface{})
	info["type"] = enum.MsgType_Tracker_NodeLogin_303
	nodeLoginInfo := &bean.ObdNodeLoginRequest{}
	nodeLoginInfo.NodeId = tool.GetObdNodeId()
	nodeLoginInfo.P2PAddress = localServerDest
	info["data"] = nodeLoginInfo
	bytes, err := json.Marshal(info)
	if err != nil {
		log.Println(err)
	} else {
		sendMsgToTracker(bytes)
	}
}

func sycUserInfos() {

	nodes := make([]bean.ObdNodeUserLoginRequest, 0)
	for userId, _ := range GlobalWsClientManager.OnlineClientMap {
		user := bean.ObdNodeUserLoginRequest{}
		user.UserId = userId
		nodes = append(nodes, user)
	}
	if len(nodes) > 0 {
		log.Println("syn UserInfo data to tracker", nodes)
		info := make(map[string]interface{})
		info["type"] = enum.MsgType_Tracker_UpdateUserInfo_353
		info["data"] = nodes
		bytes, err := json.Marshal(&info)
		if err == nil {
			sendMsgToTracker(bytes)
		}
	}
}

//同步通道信息
func sycChannelInfos() {
	nodes := getChannelInfos()
	if len(nodes) > 0 {
		info := make(map[string]interface{})
		info["type"] = enum.MsgType_Tracker_UpdateChannelInfo_350
		info["data"] = nodes
		bytes, err := json.Marshal(info)
		if err == nil {
			sendMsgToTracker(bytes)
		}
	}
}

func getChannelInfos() []bean.ChannelInfoRequest {
	_dir := config.DataDirectory + "/" + config.ChainNodeType
	files, _ := ioutil.ReadDir(_dir)

	dbNames := make([]string, 0)
	userPeerIds := make([]string, 0)
	for _, f := range files {
		if strings.HasPrefix(f.Name(), "user_") && strings.HasSuffix(f.Name(), ".db") {
			peerId := strings.TrimPrefix(f.Name(), "user_")
			peerId = strings.TrimSuffix(peerId, ".db")
			value, exists := GlobalWsClientManager.OnlineClientMap[peerId]
			if exists && value != nil {
				userPeerIds = append(userPeerIds, peerId)
			} else {
				dbNames = append(dbNames, f.Name())
			}
		}
	}

	nodes := make([]bean.ChannelInfoRequest, 0)

	for _, peerId := range userPeerIds {
		client, _ := GlobalWsClientManager.OnlineClientMap[peerId]
		if client != nil {
			nodes = checkChannel(peerId, client.User.Db, nodes)
		}
	}

	for _, dbName := range dbNames {
		db, err := storm.Open(_dir + "/" + dbName)
		if err == nil {
			userId := strings.TrimLeft(dbName, "user_")
			userId = strings.TrimRight(userId, ".db")
			nodes = checkChannel(userId, db, nodes)
			_ = db.Close()
		}
	}
	return nodes
}

func lockChannel(userId, channelId string) (err error) {
	var userDb *storm.DB
	value, exists := GlobalWsClientManager.OnlineClientMap[userId]
	if exists && value.User.Db != nil {
		userDb = value.User.Db
	} else {
		_dir := "dbdata" + config.ChainNodeType
		userDb, err = storm.Open(_dir + "/" + "user_" + userId + ".db")
	}
	var channelInfo dao.ChannelInfo
	if userDb != nil {
		err = userDb.Select(
			q.Eq("IsPrivate", false),
			q.Eq("CurrState", bean.ChannelState_CanUse),
			q.Eq("ChannelId", channelId)).First(&channelInfo)
		if err == nil {
			return userDb.UpdateField(&channelInfo, "CurrState", bean.ChannelState_LockByTracker)
		}
	}
	return nil
}

func unlockChannel(userId, channelId string) (err error) {
	var userDb *storm.DB
	value, exists := GlobalWsClientManager.OnlineClientMap[userId]
	dbIsOnOpen := false
	if exists && value.User.Db != nil {
		userDb = value.User.Db
		dbIsOnOpen = true
	} else {
		_dir := "dbdata" + config.ChainNodeType
		userDb, err = storm.Open(_dir + "/" + "user_" + userId + ".db")
	}
	var channelInfo dao.ChannelInfo
	if userDb != nil {
		err = userDb.Select(
			q.Or(q.Eq("CurrState", bean.ChannelState_LockByTracker),
				q.Eq("CurrState", bean.ChannelState_CanUse)),
			q.Eq("ChannelId", channelId)).First(&channelInfo)
		if err == nil {
			if channelInfo.CurrState != bean.ChannelState_CanUse {
				err = userDb.UpdateField(&channelInfo, "CurrState", bean.ChannelState_CanUse)
			}
		}
		if dbIsOnOpen == false {
			_ = userDb.Close()
		}
	}
	return err
}

func checkChannel(userId string, db storm.Node, nodes []bean.ChannelInfoRequest) []bean.ChannelInfoRequest {
	var channelInfos []dao.ChannelInfo
	err := db.Select(
		q.Eq("IsPrivate", false),
		q.Or(
			q.Eq("CurrState", bean.ChannelState_CanUse),
			q.Eq("CurrState", bean.ChannelState_Close),
			q.Eq("CurrState", bean.ChannelState_HtlcTx))).Find(&channelInfos)
	if err == nil {
		for _, channelInfo := range channelInfos {
			commitmentTransaction := dao.CommitmentTransaction{}
			err = db.Select(q.Eq("ChannelId", channelInfo.ChannelId)).OrderBy("CreateAt").Reverse().First(&commitmentTransaction)
			request := bean.ChannelInfoRequest{}
			request.ChannelId = channelInfo.ChannelId
			request.PropertyId = channelInfo.PropertyId
			request.PeerIdA = channelInfo.PeerIdA
			request.PeerIdB = channelInfo.PeerIdB
			request.CurrState = channelInfo.CurrState
			if commitmentTransaction.Id > 0 {
				request.AmountA = commitmentTransaction.AmountToRSMC
				request.AmountB = commitmentTransaction.AmountToCounterparty
				request.IsAlice = false
				if commitmentTransaction.Owner == channelInfo.PeerIdA {
					request.IsAlice = true
					request.AmountA = commitmentTransaction.AmountToRSMC
					request.AmountB = commitmentTransaction.AmountToCounterparty
				} else {
					request.AmountA = commitmentTransaction.AmountToCounterparty
					request.AmountB = commitmentTransaction.AmountToRSMC
				}
			} else {
				request.AmountA = channelInfo.Amount
				request.AmountB = 0
				request.IsAlice = false
				if channelInfo.FunderPeerId == userId {
					request.IsAlice = true
				}
			}
			nodes = append(nodes, request)
		}
	}
	return nodes
}

func sendMsgToTracker(msg []byte) {
	//log.Println("send to tracker", string(msg))
	if conn == nil {
		isReset = true
		err := ConnectToTracker()
		if err != nil {
			log.Println(err)
			return
		}
	}
	err := conn.WriteMessage(websocket.TextMessage, msg)
	if err != nil {
		log.Println("write:", err)
		return
	}
}

func startSchedule() {
	go func() {
		for {
			select {
			case msg := <-service.TrackerChan:
				sendMsgToTracker(msg)
				msgType := gjson.Parse(string(msg)).Get("type").Int()
				if msgType == 350 {
					message := &trackerBean.RequestMessage{}
					err := json.Unmarshal(msg, message)
					if err == nil {
						marshal, err := json.Marshal(message.Data)
						if err == nil {
							sendChannelInfoToIndirectTracker(string(marshal))
						}
					}
				}
			}
		}
	}()

	go func() {
		ticker3m = time.NewTicker(1 * time.Minute)
		defer ticker3m.Stop()
		for {
			select {
			case t := <-ticker3m.C:
				if conn == nil {
					log.Println("reconnect tracker ", t)
					_ = ConnectToTracker()
				}
			}
		}
	}()
}


<|start_filename|>bean/message_rsmc.go<|end_filename|>
package bean

//消息 -100351(alice to obd) Alice发给obd (commitment_tx) 申请转账
type RequestCreateCommitmentTx struct {
	ChannelId                 string  `json:"channel_id"` //the global channel id.
	Amount                    float64 `json:"amount"`     //amount of the payment
	LastTempAddressPrivateKey string  `json:"last_temp_address_private_key"`
	CurrTempAddressIndex      int     `json:"curr_temp_address_index"`
	CurrTempAddressPubKey     string  `json:"curr_temp_address_pub_key"`
	typeLengthValue
}

// 返回值 -100351的返回值 (obd to alice) obd推给Alice (需要Alice签名的数据)
type NeedAliceSignRsmcDataForC2a struct {
	ChannelId           string               `json:"channel_id"` //the global channel id.
	RsmcRawData         NeedClientSignTxData `json:"rsmc_raw_data"`
	CounterpartyRawData NeedClientSignTxData `json:"counterparty_raw_data"`
}

//消息 -100360(alice to obd) alice发给obd (Alice签名C2a的结果)
type AliceSignedRsmcDataForC2a struct {
	ChannelId             string `json:"channel_id"`
	RsmcSignedHex         string `json:"rsmc_signed_hex"`
	CounterpartySignedHex string `json:"counterparty_signed_hex"`
	typeLengthValue
}

//返回值 -100360(alice to obd) alice发给obd (Alice签名C2a的结果)
type AliceSignedRsmcDataForC2aResult struct {
	ChannelId             string  `json:"channel_id"` //the global channel id.
	CommitmentTxHash      string  `json:"commitment_tx_hash"`
	Amount                float64 `json:"amount"`   //amount of the payment
	AmountA               float64 `json:"amount_a"` //amount of the payment
	AmountB               float64 `json:"amount_b"` //amount of the payment
	CurrTempAddressPubKey string  `json:"curr_temp_address_pub_key"`
}

// 消息 p2p 351 p2p (obd of alice to obd of bob) 发送给bob的obd的数据 alice请求rsmc转账
type AliceRequestToCreateCommitmentTxOfP2p struct {
	AliceSignedRsmcDataForC2aResult
	LastTempAddressPrivateKey string               `json:"last_temp_address_private_key"`
	RsmcRawData               NeedClientSignTxData `json:"rsmc_raw_data"`
	CounterpartyRawData       NeedClientSignTxData `json:"counterparty_raw_data"`
	PayerNodeAddress          string               `json:"payer_node_address"`
	PayerPeerId               string               `json:"payer_peer_id"`
	typeLengthValue
}

// 返回值 -110351  (obd to bob) obd推给bob  bob所在的obd发送给bob的需要bob签名的数据：C2a的rsmc和toB
type PayerRequestCommitmentTxToBobClient struct {
	AliceRequestToCreateCommitmentTxOfP2p
	MsgHash string `json:"msg_hash"`
}

// p2p消息 -100352 (bob to obd) (commitment_tx_signed)  bob完成对C2a rsmc和toB的签名，并对这次rsmc转账签收
type PayeeSendSignCommitmentTx struct {
	ChannelId                 string `json:"channel_id"`
	MsgHash                   string `json:"msg_hash"`
	C2aRsmcSignedHex          string `json:"c2a_rsmc_signed_hex"`
	C2aCounterpartySignedHex  string `json:"c2a_counterparty_signed_hex"`
	LastTempAddressPrivateKey string `json:"last_temp_address_private_key"` // bob2's private key
	CurrTempAddressIndex      int    `json:"curr_temp_address_index"`
	CurrTempAddressPubKey     string `json:"curr_temp_address_pub_key"` // bob3 or alice3
	Approval                  bool   `json:"approval"`                  // true agree false disagree
	typeLengthValue
}

// 返回值 -100352 (obd to bob) 推送给bob，需要bob对C2b的交易进行签名
type NeedBobSignRawDataForC2b struct {
	ChannelId              string                    `json:"channel_id"` //the global channel id.
	C2bRsmcRawData         NeedClientSignTxData      `json:"c2b_rsmc_raw_data"`
	C2bCounterpartyRawData NeedClientSignTxData      `json:"c2b_counterparty_raw_data"`
	C2aRdRawData           NeedClientSignTxData      `json:"c2a_rd_raw_data"`
	C2aBrRawData           NeedClientSignRawBRTxData `json:"c2a_br_raw_data"`
}

// 消息 100361 （bob to obd） bob对C2b的签名结果
type BobSignedRsmcDataForC2b struct {
	ChannelId                string `json:"channel_id"` //the global channel id.
	C2bRsmcSignedHex         string `json:"c2b_rsmc_signed_hex"`
	C2bCounterpartySignedHex string `json:"c2b_counterparty_signed_hex"`
	C2aRdSignedHex           string `json:"c2a_rd_signed_hex"`
	C2aBrSignedHex           string `json:"c2a_br_signed_hex"`
	C2aBrId                  int64  `json:"c2a_br_id"`
	typeLengthValue
}

// 消息 100361 （bob to obd） bob对C2b的签名结果
type BobSignedRsmcDataForC2bResult struct {
	ChannelId        string `json:"channel_id"` //the global channel id.
	CommitmentTxHash string `json:"commitment_tx_hash"`
	Approval         bool   `json:"approval"`
}

//p2p消息 -100361 -> 352 (obd of bob to obd of alice) bob的obd把c2b的相关信息通过p2p推送过alice的obd
type PayeeSignCommitmentTxOfP2p struct {
	BobSignedRsmcDataForC2bResult
	C2bRsmcTxData                NeedClientSignTxData `json:"c2b_rsmc_tx_data"`
	C2bCounterpartyTxData        NeedClientSignTxData `json:"c2b_counterparty_tx_data"`
	LastTempAddressPrivateKey    string               `json:"last_temp_address_private_key"`
	CurrTempAddressPubKey        string               `json:"curr_temp_address_pub_key"`
	C2aSignedRsmcHex             string               `json:"c2a_signed_rsmc_hex"`
	C2aSignedToCounterpartyTxHex string               `json:"c2a_signed_to_counterparty_tx_hex"`
	C2aRdTxData                  NeedClientSignTxData `json:"c2a_rd_tx_data"`
	typeLengthValue
}

// 返回值 110352（obd to Alice）352给Alice的返回值 obd推送给alice，为c2b的Rsmc和toBob，以及c2a的Rd签名
type NeedAliceSignRsmcTxForC2b struct {
	ChannelId                  string               `json:"channel_id"` //the global channel id.
	C2bRsmcPartialData         NeedClientSignTxData `json:"c2b_rsmc_partial_data"`
	C2bCounterpartyPartialData NeedClientSignTxData `json:"c2b_counterparty_partial_data"`
	C2aRdPartialData           NeedClientSignTxData `json:"c2a_rd_partial_data"`
	PayeeNodeAddress           string               `json:"payee_node_address"`
	PayeePeerId                string               `json:"payee_peer_id"`
}

// 消息 100362（alice to obd） Alice完成对C2b的相关信息签名
type AliceSignedRsmcTxForC2b struct {
	ChannelId                string `json:"channel_id"` //the global channel id.
	C2bRsmcSignedHex         string `json:"c2b_rsmc_signed_hex"`
	C2bCounterpartySignedHex string `json:"c2b_counterparty_signed_hex"`
	C2aRdSignedHex           string `json:"c2a_rd_signed_hex"`
	typeLengthValue
}

// 返回值 100362的返回值（obd to Alice） obd推送给alice，为c2b的Rd和BR签名
type NeedAliceSignRdTxForC2b struct {
	ChannelId    string                    `json:"channel_id"` //the global channel id.
	C2bRdRawData NeedClientSignTxData      `json:"c2b_rd_raw_data"`
	C2bBrRawData NeedClientSignRawBRTxData `json:"c2b_br_raw_data"`
}

// 消息 100363（alice to obd） Alice完成对C2b的Rd和BR的相关信息签名
type AliceSignedRdTxForC2b struct {
	ChannelId      string `json:"channel_id"`
	C2bRdSignedHex string `json:"c2b_rd_signed_hex"`
	C2bBrSignedHex string `json:"c2b_br_signed_hex"`
	C2bBrId        int64  `json:"c2b_br_id"`
	typeLengthValue
}

// p2p 消息 353（obd of alice to obd of bob） Alice完成c2b的Rd和Br的签名，把签名结果发给bob所在的obd
type AliceSignedC2bTxDataP2p struct {
	ChannelId                string               `json:"channel_id"`
	C2aCommitmentTxHash      string               `json:"c2a_commitment_tx_hash"`
	C2bRsmcSignedHex         string               `json:"c2b_rsmc_signed_hex"`
	C2bCounterpartySignedHex string               `json:"c2b_counterparty_signed_hex"`
	C2bRdPartialData         NeedClientSignTxData `json:"c2b_rd_partial_data"`
}

// 返回值 110353（obd to bob） 353给bob的返回值 把需要签名的rd交易推给bob
type NeedBobSignRdTxForC2b struct {
	ChannelId        string               `json:"channel_id"`
	C2bRdPartialData NeedClientSignTxData `json:"c2b_rd_partial_data"`
}

// 消息 100364（to obd） bob签名rd完成后的结果
type BobSignedRdTxForC2b struct {
	ChannelId      string `json:"channel_id"`
	C2bRdSignedHex string `json:"c2b_rd_signed_hex"`
	typeLengthValue
}


<|start_filename|>tracker/config/cfg.go<|end_filename|>
package cfg

import (
	"flag"
	ma "github.com/multiformats/go-multiaddr"
	"log"
	"strings"
	"testing"
	"time"

	"github.com/go-ini/ini"
)

type addrList []ma.Multiaddr

func StringsToAddrs(addrStrings []string) (maddrs []ma.Multiaddr, err error) {
	for _, addrString := range addrStrings {
		addr, err := ma.NewMultiaddr(addrString)
		if err != nil {
			return maddrs, err
		}
		maddrs = append(maddrs, addr)
	}
	return
}

var (
	//Cfg               *ini.File
	configPath        = flag.String("trackerConfigPath", "tracker/config/conf.ini", "Config file path")
	ReadTimeout       = 60 * time.Second
	WriteTimeout      = 60 * time.Second
	TrackerServerPort = 60060

	HtlcFeeRate = 0.0001

	P2P_hostIp      = "127.0.0.1"
	P2P_sourcePort  = 60801
	BootstrapPeers  addrList
	P2pLocalAddress = ""

	ChainNode_Type = "test"
	ChainNode_Host = "172.16.17.32:18332"
	ChainNode_User = "omniwallet"
	ChainNode_Pass = "<PASSWORD>?"
)

func init() {
	testing.Init()
	flag.Parse()
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	Cfg, err := ini.Load(*configPath)
	if err != nil {
		if strings.Contains(err.Error(), "open tracker/config/conf.ini") {
			Cfg, err = ini.Load("config/conf.ini")
			if err != nil {
				log.Println(err)
				return
			}
		}
	}

	section, err := Cfg.GetSection("server")
	if err != nil {
		log.Println(err)
		return
	}
	TrackerServerPort = section.Key("port").MustInt(60060)

	htlcNode, err := Cfg.GetSection("htlc")
	if err != nil {
		log.Println(err)
		return
	}
	HtlcFeeRate = htlcNode.Key("feeRate").MustFloat64(0.0001)

	p2pNode, err := Cfg.GetSection("p2p")
	if err != nil {
		log.Println(err)
		return
	}

	P2P_hostIp = p2pNode.Key("localHostIp").MustString("127.0.0.1")
	P2P_sourcePort = p2pNode.Key("sourcePort").MustInt(60801)
	bootstrapPeers := p2pNode.Key("bootstrapPeers").MustString("")
	BootstrapPeers, _ = StringsToAddrs(strings.Split(bootstrapPeers, ","))

	chainNode, err := Cfg.GetSection("chainNode")
	if err != nil {
		log.Println(err)
		return
	}
	ChainNode_Host = chainNode.Key("host").String()
	ChainNode_User = chainNode.Key("user").String()
	ChainNode_Pass = chainNode.Key("pass").String()
	if len(ChainNode_Host) == 0 {
		log.Println("empty omnicore host")
		return
	}
	if len(ChainNode_User) == 0 {
		log.Println("empty omnicore account")
		return
	}
	if len(ChainNode_Pass) == 0 {
		log.Println("empty omnicore password")
		return
	}
}


<|start_filename|>admin/htlc_h.go<|end_filename|>
package admin

import (
	"encoding/json"
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/service"
	"log"
	"strings"
	"time"
)

func HtlcCreateInvoice(msg *bean.RequestMessage, user *bean.User) (err error) {
	wallet, _ := service.HDWalletService.CreateNewAddress(user)
	requestData := &bean.HtlcRequestInvoice{}
	err = json.Unmarshal([]byte(msg.Data), requestData)
	if err != nil {
		log.Println(err.Error())
		return err
	}
	requestData.H = wallet.PubKey
	marshal, _ := json.Marshal(requestData)
	msg.Data = string(marshal)
	invoiceImage := dao.HtlcHAndRImage{H: wallet.PubKey, Index: wallet.Index, R: wallet.Wif, CreateAt: time.Now()}
	_ = user.Db.Save(&invoiceImage)
	return nil
}

func HtlcFindPathByInvoice(invoice string) {

}

func HtlcBeforeAliceAddHtlcAtAliceSide(msg *bean.RequestMessage, user *bean.User) (err error) {
	needSignData := &bean.CreateHtlcTxForC3a{}
	err = json.Unmarshal([]byte(msg.Data), needSignData)
	if err != nil {
		return err
	}

	channelIds := strings.Split(needSignData.RoutingPacket, ",")
	var channelInfo *dao.ChannelInfo
	for _, channelId := range channelIds {
		temp := getLockChannelForHtlc(channelId, user)
		if temp != nil {
			if temp.PeerIdA == msg.RecipientUserPeerId || temp.PeerIdB == msg.RecipientUserPeerId {
				channelInfo = temp
				break
			}
		}
	}
	if channelInfo == nil {
		return errors.New("not found the channel")
	}

	commitmentTransaction := getLatestCommitmentTx(channelInfo.ChannelId, *user)
	if commitmentTransaction.Id > 0 {
		latestTempAddressInfo, _ := service.HDWalletService.GetAddressByIndex(user, uint32(commitmentTransaction.RSMCTempAddressIndex))
		needSignData.LastTempAddressPrivateKey = latestTempAddressInfo.Wif
	}

	address, _ := service.HDWalletService.CreateNewAddress(user)
	needSignData.CurrRsmcTempAddressIndex = address.Index
	needSignData.CurrRsmcTempAddressPubKey = address.PubKey

	address, _ = service.HDWalletService.CreateNewAddress(user)
	needSignData.CurrHtlcTempAddressIndex = address.Index
	needSignData.CurrHtlcTempAddressPubKey = address.PubKey

	address, _ = service.HDWalletService.CreateNewAddress(user)
	needSignData.CurrHtlcTempAddressForHt1aIndex = address.Index
	needSignData.CurrHtlcTempAddressForHt1aPubKey = address.PubKey
	marshal, _ := json.Marshal(needSignData)
	msg.Data = string(marshal)

	return nil
}

func HtlcAliceSignC3aAtAliceSide(data interface{}, user *bean.User) (signedData *bean.AliceSignedHtlcDataForC3a, err error) {
	needSignData := data.(bean.NeedAliceSignCreateHtlcTxForC3a)

	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}

	signedData = &bean.AliceSignedHtlcDataForC3a{}
	signedData.ChannelId = needSignData.ChannelId

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aRsmcRawData.Hex, convertBean(needSignData.C3aRsmcRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C3aRsmcPartialSignedHex = hex

	if len(needSignData.C3aCounterpartyRawData.Hex) > 0 {
		_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aCounterpartyRawData.Hex, convertBean(needSignData.C3aCounterpartyRawData.Inputs), channelWalletInfo.Wif)
		if err != nil {
			return nil, err
		}
		signedData.C3aCounterpartyPartialSignedHex = hex
	}

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcRawData.Hex, convertBean(needSignData.C3aHtlcRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C3aHtlcPartialSignedHex = hex

	return signedData, nil
}

func HtlcBobSignAddHtlcRequestAtBobSide_40(needSignData bean.CreateHtlcTxForC3aToBob, user *bean.User) (signedData bean.BobSignedC3a, err error) {
	signedData = bean.BobSignedC3a{PayerCommitmentTxHash: needSignData.PayerCommitmentTxHash}

	address, _ := service.HDWalletService.CreateNewAddress(user)
	signedData.CurrRsmcTempAddressIndex = address.Index
	signedData.CurrRsmcTempAddressPubKey = address.PubKey

	address, _ = service.HDWalletService.CreateNewAddress(user)
	signedData.CurrHtlcTempAddressIndex = address.Index
	signedData.CurrHtlcTempAddressPubKey = address.PubKey

	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return signedData, err
	}

	commitmentTransaction := getLatestCommitmentTx(needSignData.ChannelId, *user)
	if commitmentTransaction.Id > 0 {
		latestTempAddressInfo, err := service.HDWalletService.GetAddressByIndex(user, uint32(commitmentTransaction.RSMCTempAddressIndex))
		if err != nil {
			return signedData, err
		}
		signedData.LastTempAddressPrivateKey = latestTempAddressInfo.Wif
	}

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aRsmcPartialSignedData.Hex, convertBean(needSignData.C3aRsmcPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aCompleteSignedRsmcHex = hex

	if len(needSignData.C3aCounterpartyPartialSignedData.Hex) > 0 {
		_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aCounterpartyPartialSignedData.Hex, convertBean(needSignData.C3aCounterpartyPartialSignedData.Inputs), channelWalletInfo.Wif)
		if err != nil {
			return signedData, err
		}
		signedData.C3aCompleteSignedCounterpartyHex = hex
	}

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcPartialSignedData.Hex, convertBean(needSignData.C3aHtlcPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aCompleteSignedHtlcHex = hex

	return signedData, nil
}

func HtlcBobSignC3b(needSignData *bean.NeedBobSignHtlcTxOfC3b, user *bean.User) (signedData *bean.BobSignedHtlcTxOfC3b, err error) {

	signedData = &bean.BobSignedHtlcTxOfC3b{ChannelId: needSignData.ChannelId}

	channelWalletInfo, _ := getChannelWalletInfo(needSignData.ChannelId, user)
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aRsmcRdRawData.Hex, convertBean(needSignData.C3aRsmcRdRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aRsmcRdPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aRsmcBrRawData.Hex, convertBean(needSignData.C3aRsmcBrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aRsmcBrPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcHtRawData.Hex, convertBean(needSignData.C3aHtlcHtRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aHtlcHtPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcHlockRawData.Hex, convertBean(needSignData.C3aHtlcHlockRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aHtlcHlockPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcBrRawData.Hex, convertBean(needSignData.C3aHtlcBrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aHtlcBrPartialSignedHex = hex

	if len(needSignData.C3bRsmcRawData.Hex) > 0 {
		_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bRsmcRawData.Hex, convertBean(needSignData.C3bRsmcRawData.Inputs), channelWalletInfo.Wif)
		if err != nil {
			return signedData, err
		}
		signedData.C3bRsmcPartialSignedHex = hex
	}

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bCounterpartyRawData.Hex, convertBean(needSignData.C3bCounterpartyRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bCounterpartyPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcRawData.Hex, convertBean(needSignData.C3bHtlcRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bHtlcPartialSignedHex = hex
	return signedData, nil
}

func HtlcAliceSignC3b(dataHex interface{}, user *bean.User) (signedData *bean.AliceSignedHtlcTxOfC3bResult, err error) {
	needSignData := dataHex.(bean.NeedAliceSignHtlcTxOfC3b)
	signedData = &bean.AliceSignedHtlcTxOfC3bResult{ChannelId: needSignData.ChannelId}
	currCommitmentTx := getCurrCommitmentTx(needSignData.ChannelId, *user)
	wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(currCommitmentTx.RSMCTempAddressIndex))

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aRsmcRdPartialSignedData.Hex, convertBean(needSignData.C3aRsmcRdPartialSignedData.Inputs), wallet.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aRsmcRdCompleteSignedHex = hex

	wallet, _ = service.HDWalletService.GetAddressByIndex(user, uint32(currCommitmentTx.HTLCTempAddressIndex))
	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcHtPartialSignedData.Hex, convertBean(needSignData.C3aHtlcHtPartialSignedData.Inputs), wallet.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aHtlcHtCompleteSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcHlockPartialSignedData.Hex, convertBean(needSignData.C3aHtlcHlockPartialSignedData.Inputs), wallet.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aHtlcHlockCompleteSignedHex = hex

	channelWalletInfo, _ := getChannelWalletInfo(needSignData.ChannelId, user)
	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bRsmcPartialSignedData.Hex, convertBean(needSignData.C3bRsmcPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bRsmcCompleteSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcPartialSignedData.Hex, convertBean(needSignData.C3bHtlcPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bHtlcCompleteSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bCounterpartyPartialSignedData.Hex, convertBean(needSignData.C3bCounterpartyPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bCounterpartyCompleteSignedHex = hex

	return signedData, nil
}

func HtlcAliceSignedC3bSubTxAtAliceSide(dataHex interface{}, user *bean.User) (signedData *bean.AliceSignedHtlcSubTxOfC3b, err error) {
	needSignData := dataHex.(bean.NeedAliceSignHtlcSubTxOfC3b)

	signedData = &bean.AliceSignedHtlcSubTxOfC3b{ChannelId: needSignData.ChannelId}

	currCommitmentTx := getCurrCommitmentTx(needSignData.ChannelId, *user)

	htlcRequestInfo := &dao.AddHtlcRequestInfo{}
	_ = user.Db.Select(
		q.Eq("ChannelId", needSignData.ChannelId),
		q.Eq("H", currCommitmentTx.HtlcH),
		q.Eq("RoutingPacket", currCommitmentTx.HtlcRoutingPacket)).First(htlcRequestInfo)

	if htlcRequestInfo.Id > 0 {
		wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(htlcRequestInfo.CurrHtlcTempAddressForHt1aIndex))
		_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcHtrdRawData.Hex, convertBean(needSignData.C3aHtlcHtrdRawData.Inputs), wallet.Wif)
		if err != nil {
			return nil, err
		}
		signedData.C3aHtlcHtrdPartialSignedHex = hex
	}

	channelWalletInfo, _ := getChannelWalletInfo(needSignData.ChannelId, user)
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bRsmcRdRawData.Hex, convertBean(needSignData.C3bRsmcRdRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C3bRsmcRdPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bRsmcBrRawData.Hex, convertBean(needSignData.C3bRsmcBrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C3bRsmcBrPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcHtdRawData.Hex, convertBean(needSignData.C3bHtlcHtdRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C3bHtlcHtdPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcHlockRawData.Hex, convertBean(needSignData.C3bHtlcHlockRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C3bHtlcHlockPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcBrRawData.Hex, convertBean(needSignData.C3bHtlcBrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData.C3bHtlcBrPartialSignedHex = hex

	return signedData, nil
}

func HtlcBobSignedC3bSubTxAtBobSide(dataHex interface{}, user *bean.User) (signedData *bean.BobSignedHtlcSubTxOfC3b, err error) {
	needSignData := dataHex.(bean.NeedBobSignHtlcSubTxOfC3b)

	signedData = &bean.BobSignedHtlcSubTxOfC3b{ChannelId: needSignData.ChannelId}
	newAddress, _ := service.HDWalletService.CreateNewAddress(user)
	signedData.CurrHtlcTempAddressForHeIndex = newAddress.Index
	signedData.CurrHtlcTempAddressForHePubKey = newAddress.PubKey

	currCommitmentTx := getCurrCommitmentTx(needSignData.ChannelId, *user)
	wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(currCommitmentTx.RSMCTempAddressIndex))
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bRsmcRdPartialData.Hex, convertBean(needSignData.C3bRsmcRdPartialData.Inputs), wallet.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bRsmcRdCompleteSignedHex = hex

	wallet, _ = service.HDWalletService.GetAddressByIndex(user, uint32(currCommitmentTx.HTLCTempAddressIndex))
	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcHtdPartialData.Hex, convertBean(needSignData.C3bHtlcHtdPartialData.Inputs), wallet.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bHtlcHtdCompleteSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcHlockPartialData.Hex, convertBean(needSignData.C3bHtlcHlockPartialData.Inputs), wallet.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bHtlcHlockCompleteSignedHex = hex

	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}
	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcHtrdPartialData.Hex, convertBean(needSignData.C3aHtlcHtrdPartialData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aHtlcHtrdCompleteSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcHtbrRawData.Hex, convertBean(needSignData.C3aHtlcHtbrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aHtlcHtbrPartialSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3aHtlcHedRawData.Hex, convertBean(needSignData.C3aHtlcHedRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3aHtlcHedPartialSignedHex = hex

	return signedData, nil
}

func HtlcBobSignHtRdAtBobSide(dataHex interface{}, user *bean.User) (signedData *bean.BobSignedHtlcHeTxOfC3b, err error) {
	needSignData := dataHex.(bean.NeedBobSignHtlcHeTxOfC3b)

	signedData = &bean.BobSignedHtlcHeTxOfC3b{ChannelId: needSignData.ChannelId}
	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcHlockHeRawData.Hex, convertBean(needSignData.C3bHtlcHlockHeRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bHtlcHlockHePartialSignedHex = hex

	return signedData, nil
}


<|start_filename|>proxy/pb/rsmc.pb.go<|end_filename|>
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: rsmc.proto

package pb

import (
	context "context"
	fmt "fmt"
	proto "github.com/golang/protobuf/proto"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
	math "math"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

type RsmcPaymentRequest struct {
	ChannelId            string             `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	Amount               float64            `protobuf:"fixed64,2,opt,name=amount,proto3" json:"amount,omitempty"`
	RecipientInfo        *RecipientNodeInfo `protobuf:"bytes,3,opt,name=recipientInfo,proto3" json:"recipientInfo,omitempty"`
	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
	XXX_unrecognized     []byte             `json:"-"`
	XXX_sizecache        int32              `json:"-"`
}

func (m *RsmcPaymentRequest) Reset()         { *m = RsmcPaymentRequest{} }
func (m *RsmcPaymentRequest) String() string { return proto.CompactTextString(m) }
func (*RsmcPaymentRequest) ProtoMessage()    {}
func (*RsmcPaymentRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_fecbc7e287e63a67, []int{0}
}

func (m *RsmcPaymentRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_RsmcPaymentRequest.Unmarshal(m, b)
}
func (m *RsmcPaymentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_RsmcPaymentRequest.Marshal(b, m, deterministic)
}
func (m *RsmcPaymentRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_RsmcPaymentRequest.Merge(m, src)
}
func (m *RsmcPaymentRequest) XXX_Size() int {
	return xxx_messageInfo_RsmcPaymentRequest.Size(m)
}
func (m *RsmcPaymentRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_RsmcPaymentRequest.DiscardUnknown(m)
}

var xxx_messageInfo_RsmcPaymentRequest proto.InternalMessageInfo

func (m *RsmcPaymentRequest) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

func (m *RsmcPaymentRequest) GetAmount() float64 {
	if m != nil {
		return m.Amount
	}
	return 0
}

func (m *RsmcPaymentRequest) GetRecipientInfo() *RecipientNodeInfo {
	if m != nil {
		return m.RecipientInfo
	}
	return nil
}

type RsmcPaymentResponse struct {
	ChannelId            string   `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
	AmountA              float64  `protobuf:"fixed64,2,opt,name=amount_a,json=amountA,proto3" json:"amount_a,omitempty"`
	AmountB              float64  `protobuf:"fixed64,3,opt,name=amount_b,json=amountB,proto3" json:"amount_b,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *RsmcPaymentResponse) Reset()         { *m = RsmcPaymentResponse{} }
func (m *RsmcPaymentResponse) String() string { return proto.CompactTextString(m) }
func (*RsmcPaymentResponse) ProtoMessage()    {}
func (*RsmcPaymentResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_fecbc7e287e63a67, []int{1}
}

func (m *RsmcPaymentResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_RsmcPaymentResponse.Unmarshal(m, b)
}
func (m *RsmcPaymentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_RsmcPaymentResponse.Marshal(b, m, deterministic)
}
func (m *RsmcPaymentResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_RsmcPaymentResponse.Merge(m, src)
}
func (m *RsmcPaymentResponse) XXX_Size() int {
	return xxx_messageInfo_RsmcPaymentResponse.Size(m)
}
func (m *RsmcPaymentResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_RsmcPaymentResponse.DiscardUnknown(m)
}

var xxx_messageInfo_RsmcPaymentResponse proto.InternalMessageInfo

func (m *RsmcPaymentResponse) GetChannelId() string {
	if m != nil {
		return m.ChannelId
	}
	return ""
}

func (m *RsmcPaymentResponse) GetAmountA() float64 {
	if m != nil {
		return m.AmountA
	}
	return 0
}

func (m *RsmcPaymentResponse) GetAmountB() float64 {
	if m != nil {
		return m.AmountB
	}
	return 0
}

func init() {
	proto.RegisterType((*RsmcPaymentRequest)(nil), "proxy.RsmcPaymentRequest")
	proto.RegisterType((*RsmcPaymentResponse)(nil), "proxy.RsmcPaymentResponse")
}

func init() {
	proto.RegisterFile("rsmc.proto", fileDescriptor_fecbc7e287e63a67)
}

var fileDescriptor_fecbc7e287e63a67 = []byte{
	// 231 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0x2a, 0xce, 0x4d,
	0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2d, 0x28, 0xca, 0xaf, 0xa8, 0x94, 0xe2, 0x2c,
	0x2a, 0x80, 0x8a, 0x28, 0x75, 0x33, 0x72, 0x09, 0x05, 0x15, 0xe7, 0x26, 0x07, 0x24, 0x56, 0xe6,
	0xa6, 0xe6, 0x95, 0x04, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0xc9, 0x72, 0x71, 0x25, 0x67,
	0x24, 0xe6, 0xe5, 0xa5, 0xe6, 0xc4, 0x67, 0xa6, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0x71,
	0x42, 0x45, 0x3c, 0x53, 0x84, 0xc4, 0xb8, 0xd8, 0x12, 0x73, 0xf3, 0x4b, 0xf3, 0x4a, 0x24, 0x98,
	0x14, 0x18, 0x35, 0x18, 0x83, 0xa0, 0x3c, 0x21, 0x3b, 0x2e, 0xde, 0xa2, 0xd4, 0xe4, 0xcc, 0x82,
	0xcc, 0xd4, 0xbc, 0x12, 0xcf, 0xbc, 0xb4, 0x7c, 0x09, 0x66, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x09,
	0x3d, 0xb0, 0xbd, 0x7a, 0x41, 0x30, 0x39, 0xbf, 0xfc, 0x94, 0x54, 0x90, 0x7c, 0x10, 0xaa, 0x72,
	0xa5, 0x2c, 0x2e, 0x61, 0x14, 0xc7, 0x14, 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x12, 0x72, 0x8d, 0x24,
	0x17, 0x07, 0xc4, 0xfe, 0xf8, 0x44, 0xa8, 0x7b, 0xd8, 0x21, 0x7c, 0x47, 0x24, 0xa9, 0x24, 0xb0,
	0x5b, 0xe0, 0x52, 0x4e, 0x46, 0x3e, 0x5c, 0x2c, 0x20, 0xbb, 0x84, 0x5c, 0xb8, 0xb8, 0x91, 0xec,
	0x14, 0x92, 0x84, 0xb9, 0x15, 0x23, 0x50, 0xa4, 0xa4, 0xb0, 0x49, 0x41, 0x9c, 0xe8, 0xc4, 0x12,
	0xc5, 0x54, 0x90, 0x94, 0xc4, 0x06, 0x0e, 0x54, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xab,
	0x87, 0xf7, 0xc6, 0x74, 0x01, 0x00, 0x00,
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// RsmcClient is the client API for Rsmc service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type RsmcClient interface {
	RsmcPayment(ctx context.Context, in *RsmcPaymentRequest, opts ...grpc.CallOption) (*RsmcPaymentResponse, error)
}

type rsmcClient struct {
	cc grpc.ClientConnInterface
}

func NewRsmcClient(cc grpc.ClientConnInterface) RsmcClient {
	return &rsmcClient{cc}
}

func (c *rsmcClient) RsmcPayment(ctx context.Context, in *RsmcPaymentRequest, opts ...grpc.CallOption) (*RsmcPaymentResponse, error) {
	out := new(RsmcPaymentResponse)
	err := c.cc.Invoke(ctx, "/proxy.Rsmc/RsmcPayment", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// RsmcServer is the server API for Rsmc service.
type RsmcServer interface {
	RsmcPayment(context.Context, *RsmcPaymentRequest) (*RsmcPaymentResponse, error)
}

// UnimplementedRsmcServer can be embedded to have forward compatible implementations.
type UnimplementedRsmcServer struct {
}

func (*UnimplementedRsmcServer) RsmcPayment(ctx context.Context, req *RsmcPaymentRequest) (*RsmcPaymentResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method RsmcPayment not implemented")
}

func RegisterRsmcServer(s *grpc.Server, srv RsmcServer) {
	s.RegisterService(&_Rsmc_serviceDesc, srv)
}

func _Rsmc_RsmcPayment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(RsmcPaymentRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(RsmcServer).RsmcPayment(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Rsmc/RsmcPayment",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(RsmcServer).RsmcPayment(ctx, req.(*RsmcPaymentRequest))
	}
	return interceptor(ctx, in, info, handler)
}

var _Rsmc_serviceDesc = grpc.ServiceDesc{
	ServiceName: "proxy.Rsmc",
	HandlerType: (*RsmcServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "RsmcPayment",
			Handler:    _Rsmc_RsmcPayment_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "rsmc.proto",
}


<|start_filename|>admin/htlc_r.go<|end_filename|>
package admin

import (
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/config"
	conn2tracker "github.com/omnilaboratory/obd/conn"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/service"
	"github.com/shopspring/decimal"
	"strings"
)

func ROwnerGetHtlcRFromLocal(dataTx interface{}, user *bean.User) (r string) {
	tx := dataTx.(*dao.CommitmentTransaction)
	hAndRImage := &dao.HtlcHAndRImage{}
	_ = user.Db.Select(q.Eq("H", tx.HtlcH)).First(hAndRImage)
	if hAndRImage.Id > 0 {
		return hAndRImage.R
	}
	return ""
}

func InterUserGetNextNode(dataTx interface{}, user *bean.User) (channelId string, amount float64, msg *bean.RequestMessage) {
	currNodeTx := dataTx.(*dao.CommitmentTransaction)
	currChannelId := currNodeTx.ChannelId
	htlcPathArr := strings.Split(currNodeTx.HtlcRoutingPacket, ",")
	totalStep := len(htlcPathArr)
	currStep := 0
	for ; currStep < len(htlcPathArr); currStep++ {
		if htlcPathArr[currStep] == currChannelId {
			break
		}
	}
	currStep++
	if currStep < len(htlcPathArr) {
		channelId = htlcPathArr[currStep]
		latestCommitmentTx := getLatestCommitmentTx(channelId, *user)
		msg = &bean.RequestMessage{}
		msg.RecipientUserPeerId = latestCommitmentTx.PeerIdA
		if user.PeerId == latestCommitmentTx.PeerIdA {
			msg.RecipientUserPeerId = latestCommitmentTx.PeerIdB
		}
		msg.RecipientNodePeerId = conn2tracker.GetUserP2pNodeId(msg.RecipientUserPeerId)
		amount, _ = decimal.NewFromFloat(currNodeTx.HtlcAmountToPayee).Mul(decimal.NewFromFloat(1 + config.HtlcFeeRate*float64(totalStep-currStep-1))).Round(8).Float64()
		if len(msg.RecipientNodePeerId) == 0 {
			return "", 0, nil
		}
		msg.SenderNodePeerId = user.P2PLocalPeerId
		msg.SenderUserPeerId = user.PeerId
		return channelId, amount, msg
	}
	return "", 0, nil
}

func InterUserGetHtlcRFromLocalForPreNode(dataTx interface{}, user *bean.User) (r, channelId string, msg *bean.RequestMessage) {
	currNodeTx := dataTx.(*dao.CommitmentTransaction)
	currChannelId := currNodeTx.ChannelId
	htlcPathArr := strings.Split(currNodeTx.HtlcRoutingPacket, ",")
	index := len(htlcPathArr) - 1
	for ; index >= 0; index-- {
		if htlcPathArr[index] == currChannelId {
			break
		}
	}
	if index > 0 {
		newNodeTx := &dao.CommitmentTransaction{}
		_ = user.Db.Select(q.Eq("HtlcH", currNodeTx.HtlcH), q.Eq("ChannelId", htlcPathArr[index-1])).First(newNodeTx)
		if newNodeTx.Id > 0 {
			msg = &bean.RequestMessage{}
			msg.RecipientUserPeerId = newNodeTx.PeerIdA
			if user.PeerId == newNodeTx.PeerIdA {
				msg.RecipientUserPeerId = newNodeTx.PeerIdB
			}
			msg.RecipientNodePeerId = conn2tracker.GetUserP2pNodeId(msg.RecipientUserPeerId)
			if len(msg.RecipientNodePeerId) == 0 {
				return "", "", nil
			}
			return currNodeTx.HtlcR, newNodeTx.ChannelId, msg
		}
	}
	return "", "", nil
}

func HtlcBobSignedHeRdAtBobSide(dataTx interface{}, user *bean.User) (signedData *bean.BobSignHerdForC3b, err error) {
	needSignData := dataTx.(bean.HtlcBobSendRResult)
	signedData = &bean.BobSignHerdForC3b{ChannelId: needSignData.ChannelId}

	currCommitmentTx := getCurrCommitmentTx(needSignData.ChannelId, *user)
	htTx := &dao.HTLCTimeoutTxForAAndExecutionForB{}
	_ = user.Db.Select(q.Eq("ChannelId", needSignData.ChannelId), q.Eq("CommitmentTxId", currCommitmentTx.Id)).First(htTx)
	if htTx.Id > 0 {
		wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(htTx.RSMCTempAddressIndex))
		_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcHerdRawData.Hex, convertBean(needSignData.C3bHtlcHerdRawData.Inputs), wallet.Wif)
		if err != nil {
			return signedData, err
		}
		signedData.C3bHtlcHerdPartialSignedHex = hex
	}
	return signedData, nil
}

func HtlcAliceSignedHeRdAtAliceSide(dataTx interface{}, user *bean.User) (signedData *bean.AliceSignHerdTxOfC3e, err error) {
	needSignData := dataTx.(bean.NeedAliceSignHerdTxOfC3bP2p)

	signedData = &bean.AliceSignHerdTxOfC3e{ChannelId: needSignData.ChannelId}
	channelWalletInfo, err := getChannelWalletInfo(needSignData.ChannelId, user)
	if err != nil {
		return nil, err
	}

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcHerdPartialSignedData.Hex, convertBean(needSignData.C3bHtlcHerdPartialSignedData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bHtlcHerdCompleteSignedHex = hex

	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(needSignData.C3bHtlcHebrRawData.Hex, convertBean(needSignData.C3bHtlcHebrRawData.Inputs), channelWalletInfo.Wif)
	if err != nil {
		return signedData, err
	}
	signedData.C3bHtlcHebrPartialSignedHex = hex

	return signedData, nil
}


<|start_filename|>bean/message_htlc_close.go<|end_filename|>
package bean

// 消息 -100049: user wanna close htlc tx when tx is on getH state
type HtlcCloseRequestCurrTx struct {
	ChannelId                            string `json:"channel_id"`
	LastRsmcTempAddressPrivateKey        string `json:"last_rsmc_temp_address_private_key"`
	LastHtlcTempAddressPrivateKey        string `json:"last_htlc_temp_address_private_key"`
	LastHtlcTempAddressForHtnxPrivateKey string `json:"last_htlc_temp_address_for_htnx_private_key"`
	CurrTempAddressIndex                 int    `json:"curr_temp_address_index"`
	CurrTempAddressPubKey                string `json:"curr_temp_address_pub_key"`
	typeLengthValue
}

// 返回值 -100049的返回值 (obd to alice) obd推给Alice (需要Alice签名的数据)
type NeedAliceSignRsmcDataForC4a struct {
	ChannelId              string               `json:"channel_id"` //the global channel id.
	C4aRsmcRawData         NeedClientSignTxData `json:"c4a_rsmc_raw_data"`
	C4aCounterpartyRawData NeedClientSignTxData `json:"c4a_counterparty_raw_data"`
}

//消息 -100110(alice to obd) alice发给obd (Alice签名C4a的结果)
type AliceSignedRsmcDataForC4a struct {
	ChannelId                    string `json:"channel_id"`
	RsmcPartialSignedHex         string `json:"rsmc_partial_signed_hex"`
	CounterpartyPartialSignedHex string `json:"counterparty_partial_signed_hex"`
	typeLengthValue
}

// 消息 p2p 49 p2p (obd of alice to obd of bob) 发送给bob的obd的数据 alice请求rsmc转账
type AliceRequestCloseHtlcCurrTxOfP2p struct {
	ChannelId                            string               `json:"channel_id"` //the global channel id.
	CommitmentTxHash                     string               `json:"commitment_tx_hash"`
	CurrTempAddressPubKey                string               `json:"curr_temp_address_pub_key"`
	LastRsmcTempAddressPrivateKey        string               `json:"last_rsmc_temp_address_private_key"`
	LastHtlcTempAddressPrivateKey        string               `json:"last_htlc_temp_address_private_key"`
	LastHtlcTempAddressForHtnxPrivateKey string               `json:"last_htlc_temp_address_for_htnx_private_key"`
	RsmcPartialSignedData                NeedClientSignTxData `json:"rsmc_partial_signed_data"`
	CounterpartyPartialSignedData        NeedClientSignTxData `json:"counterparty_partial_signed_data"`
	SenderNodeAddress                    string               `json:"sender_node_address"`
	SenderPeerId                         string               `json:"sender_peer_id"`
	typeLengthValue
}

//消息 110049
type AliceRequestCloseHtlcCurrTxOfP2pToBobClient struct {
	ChannelId                        string               `json:"channel_id"` //the global channel id.
	C4aRsmcPartialSignedData         NeedClientSignTxData `json:"c4a_rsmc_partial_signed_data"`
	C4aCounterpartyPartialSignedData NeedClientSignTxData `json:"c4a_counterparty_partial_signed_data"`
	MsgHash                          string               `json:"msg_hash"`
	SenderNodeAddress                string               `json:"sender_node_address"`
	SenderPeerId                     string               `json:"sender_peer_id"`
}

//消息 100050 bob对关闭htlc交易请求的签收
type HtlcBobSignCloseCurrTx struct {
	MsgHash                              string `json:"msg_hash"`
	C4aRsmcCompleteSignedHex             string `json:"c4a_rsmc_complete_signed_hex"`
	C4aCounterpartyCompleteSignedHex     string `json:"c4a_counterparty_complete_signed_hex"`
	LastRsmcTempAddressPrivateKey        string `json:"last_rsmc_temp_address_private_key"`
	LastHtlcTempAddressPrivateKey        string `json:"last_htlc_temp_address_private_key"`
	LastHtlcTempAddressForHtnxPrivateKey string `json:"last_htlc_temp_address_for_htnx_private_key"`
	CurrTempAddressIndex                 int    `json:"curr_temp_address_index"`
	CurrTempAddressPubKey                string `json:"curr_temp_address_pub_key"`
	typeLengthValue
}

//响应 100050的结果
type NeedBobSignRawDataForC4b struct {
	ChannelId              string                    `json:"channel_id"`
	C4bRsmcRawData         NeedClientSignTxData      `json:"c4b_rsmc_raw_data"`
	C4bCounterpartyRawData NeedClientSignTxData      `json:"c4b_counterparty_raw_data"`
	C4aRdRawData           NeedClientSignTxData      `json:"c4a_rd_raw_data"`
	C4aBrRawData           NeedClientSignRawBRTxData `json:"c4a_br_raw_data"`
	SenderNodeAddress      string                    `json:"sender_node_address"`
	SenderPeerId           string                    `json:"sender_peer_id"`
}

// 消息 1000111对100050的签名结果
type BobSignedRsmcDataForC4b struct {
	ChannelId                       string `json:"channel_id"`
	C4aRdPartialSignedHex           string `json:"c4a_rd_signed_hex"`
	C4aBrPartialSignedHex           string `json:"c4a_br_signed_hex"`
	C4aBrId                         int64  `json:"c4a_br_id"`
	C4bRsmcPartialSignedHex         string `json:"c4b_rsmc_signed_hex"`
	C4bCounterpartyPartialSignedHex string `json:"c4b_counterparty_signed_hex"`
	typeLengthValue
}

// 响应 100111 （bob to obd） bob对C2b的签名结果
type BobSignedRsmcDataForC4bResult struct {
	ChannelId        string `json:"channel_id"`
	CommitmentTxHash string `json:"commitment_tx_hash"`
}

// p2p消息 50号协议传递的消息
type CloseeSignCloseHtlcTxOfP2p struct {
	ChannelId                                  string               `json:"channel_id"`
	CloseeLastRsmcTempAddressPrivateKey        string               `json:"closee_last_rsmc_temp_address_private_key"`
	CloseeLastHtlcTempAddressPrivateKey        string               `json:"closee_last_htlc_temp_address_private_key"`
	CloseeLastHtlcTempAddressForHtnxPrivateKey string               `json:"closee_last_htlc_temp_address_for_htnx_private_key"`
	CloseeCurrRsmcTempAddressPubKey            string               `json:"closee_curr_rsmc_temp_address_pub_key"`
	CloserCommitmentTxHash                     string               `json:"closer_commitment_tx_hash"`
	C4aRsmcCompleteSignedHex                   string               `json:"c4a_rsmc_complete_signed_hex"`
	C4aCounterpartyCompleteSignedHex           string               `json:"c4a_counterparty_complete_signed_hex"`
	C4aRdPartialSignedData                     NeedClientSignTxData `json:"c4a_rd_partial_signed_data"`
	C4bRsmcPartialSignedData                   NeedClientSignTxData `json:"c4b_rsmc_partial_signed_data"`
	C4bCounterpartyPartialSignedData           NeedClientSignTxData `json:"c4b_counterparty_partial_signed_data"`
	SendeeNodeAddress                          string               `json:"sendee_node_address"`
	SendeePeerId                               string               `json:"sendee_peer_id"`
}

// 110050的推送信息
type NeedAliceSignRsmcTxForC4b struct {
	ChannelId                        string               `json:"channel_id"` //the global channel id.
	C4aRdPartialSignedData           NeedClientSignTxData `json:"c4a_rd_partial_signed_data"`
	C4bRsmcPartialSignedData         NeedClientSignTxData `json:"c4b_rsmc_partial_signed_data"`
	C4bCounterpartyPartialSignedData NeedClientSignTxData `json:"c4b_counterparty_partial_signed_data"`
	SendeeNodeAddress                string               `json:"sendee_node_address"`
	SendeePeerId                     string               `json:"sendee_peer_id"`
}

// 消息 100112（alice to obd） Alice完成对C2b的相关信息签名
type AliceSignedRsmcTxForC4b struct {
	ChannelId                        string `json:"channel_id"`
	C4aRdCompleteSignedHex           string `json:"c4a_rd_complete_signed_hex"`
	C4bRsmcCompleteSignedHex         string `json:"c4b_rsmc_complete_signed_hex"`
	C4bCounterpartyCompleteSignedHex string `json:"c4b_counterparty_complete_signed_hex"`
	typeLengthValue
}

// 返回值 100112的返回值（obd to Alice） obd推送给alice，为c4b的Rd和BR签名
type NeedAliceSignRdTxForC4b struct {
	ChannelId         string                    `json:"channel_id"` //the global channel id.
	C4bRdRawData      NeedClientSignTxData      `json:"c4b_rd_raw_data"`
	C4bBrRawData      NeedClientSignRawBRTxData `json:"c4b_br_raw_data"`
	SendeeNodeAddress string                    `json:"sendee_node_address"`
	SendeePeerId      string                    `json:"sendee_peer_id"`
}

// 消息 100113（alice to obd） Alice完成对C4b的Rd和BR的相关信息签名
type AliceSignedRdTxForC4b struct {
	ChannelId             string `json:"channel_id"`
	C4bRdPartialSignedHex string `json:"c4b_rd_partial_signed_hex"`
	C4bBrPartialSignedHex string `json:"c4b_br_partial_signed_hex"`
	C4bBrId               int64  `json:"c4b_br_id"`
	typeLengthValue
}

// p2p 消息 51（obd of alice to obd of bob） Alice完成c2b的Rd和Br的签名，把签名结果发给bob所在的obd
type AliceSignedC4bTxDataP2p struct {
	ChannelId                        string               `json:"channel_id"`
	C4aCommitmentTxHash              string               `json:"c4a_commitment_tx_hash"`
	C4bRsmcCompleteSignedHex         string               `json:"c4b_rsmc_complete_signed_hex"`
	C4bCounterpartyCompleteSignedHex string               `json:"c4b_counterparty_complete_signed_hex"`
	C4bRdPartialSignedData           NeedClientSignTxData `json:"c4b_rd_partial_signed_data"`
}

// 返回值 110353（obd to bob） 353给bob的返回值 把需要签名的rd交易推给bob
type NeedBobSignRdTxForC4b struct {
	ChannelId              string               `json:"channel_id"`
	C4bRdPartialSignedData NeedClientSignTxData `json:"c4b_rd_partial_signed_data"`
}

// 消息 100364（to obd） bob签名rd完成后的结果
type BobSignedRdTxForC4b struct {
	ChannelId              string `json:"channel_id"`
	C4bRdCompleteSignedHex string `json:"c4b_rd_complete_signed_hex"`
	typeLengthValue
}


<|start_filename|>omnicore/MultiSigAddress_test.go<|end_filename|>
package omnicore

import (
	"fmt"
	"testing"

	"github.com/btcsuite/btcd/chaincfg"
)

func TestCreateMultiSigAddr(t *testing.T) {

	addr1_pubkey := "02db204a46ab45d872a420fef8abd935f2fe5347684f43ea58599c430f80aa82e5"
	addr2_pubkey := "<KEY>"

	//this pubkey produces error.
	//addr3_pubkey := "<KEY>"

	fmt.Println("2-2 multisig address in mainnet: ")
	address, redeemScriptHex, _ := CreateMultiSigAddr(addr1_pubkey, addr2_pubkey, &chaincfg.MainNetParams)
	fmt.Println(address)
	fmt.Println("and pubkey script hex is:")
	fmt.Println(redeemScriptHex)

	addr1_pubkey = "02c57b02d24356e1d31d34d2e3a09f7d68a4bdec6c0556595bb6391ce5d6d4fc66"
	addr2_pubkey = "0274a51763447d41956eeb1a7f82ef052452ef17ad2bc73e1fd2e527d0063f9406"

	fmt.Println("2-2 multisig address in testnet: ")
	address, redeemScriptHex, _ = CreateMultiSigAddr(addr1_pubkey, addr2_pubkey, &chaincfg.TestNet3Params)
	fmt.Println("expect: ")
	fmt.Println("2NBGN3YafXPj4aRtnufDLNNH6j47NEEKTya")
	fmt.Println("export: ")
	fmt.Println(address)

	fmt.Println("and pubkey script hex is:")
	fmt.Println("expect: ")
	fmt.Println("522102c57b02d24356e1d31d34d2e3a09f7d68a4bdec6c0556595bb6391ce5d6d4fc66210274a51763447d41956eeb1a7f82ef052452ef17ad2bc73e1fd2e527d0063f940652ae")
	fmt.Println("export: ")
	fmt.Println(redeemScriptHex)

}


<|start_filename|>proxy/rpc/rsmc.go<|end_filename|>
package rpc

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/proxy/pb"
	"github.com/omnilaboratory/obd/tool"
	"log"
)

func (s *RpcServer) RsmcPayment(ctx context.Context, in *pb.RsmcPaymentRequest) (*pb.RsmcPaymentResponse, error) {
	log.Println("RsmcPayment")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}
	if tool.CheckIsString(&in.RecipientInfo.RecipientNodePeerId) == false {
		return nil, errors.New("wrong recipient_node_peer_id")
	}

	if tool.CheckIsString(&in.RecipientInfo.RecipientUserPeerId) == false {
		return nil, errors.New("wrong recipient_user_peer_id")
	}
	if tool.CheckIsString(&in.ChannelId) == false {
		return nil, errors.New("wrong template_channel_id")
	}
	if in.Amount < 0 {
		return nil, errors.New("wrong amount")
	}

	request := bean.RequestCreateCommitmentTx{
		ChannelId: in.ChannelId,
		Amount:    in.Amount,
	}
	if rsmcChan == nil {
		rsmcChan = make(chan bean.ReplyMessage)
	}

	infoBytes, _ := json.Marshal(request)
	requestMessage := bean.RequestMessage{
		Type:                enum.MsgType_CommitmentTx_SendCommitmentTransactionCreated_351,
		SenderNodePeerId:    obcClient.User.P2PLocalPeerId,
		SenderUserPeerId:    obcClient.User.PeerId,
		RecipientNodePeerId: in.RecipientInfo.RecipientNodePeerId,
		RecipientUserPeerId: in.RecipientInfo.RecipientUserPeerId,
		Data:                string(infoBytes)}

	err = checkTargetUserIsOnline(requestMessage)
	if err != nil {
		return nil, err
	}

	_, dataBytes, status := obcClient.CommitmentTxModule(requestMessage)

	data := string(dataBytes)
	if status == false {
		return nil, errors.New(data)
	}
	dataMap := make(map[string]interface{})
	_ = json.Unmarshal(dataBytes, &dataMap)

	resp := &pb.RsmcPaymentResponse{
		ChannelId: dataMap["channel_id"].(string),
		AmountA:   dataMap["amount_a"].(float64),
		AmountB:   dataMap["amount_b"].(float64),
	}
	return resp, nil
}


<|start_filename|>service/rsmc_common.go<|end_filename|>
package service

import (
	"errors"
	"fmt"
	"github.com/asdine/storm"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/tidwall/gjson"
	"log"
	"strconv"
	"time"
)

//创建RawBR
func createCurrCommitmentTxRawBR(tx storm.Node, brType dao.BRType, channelInfo *dao.ChannelInfo,
	commitmentTx *dao.CommitmentTransaction, inputs []bean.TransactionInputItem,
	outputAddress string, user bean.User) (retMap map[string]interface{}, err error) {
	if len(inputs) == 0 {
		return nil, nil
	}
	breachRemedyTransaction := &dao.BreachRemedyTransaction{}
	_ = tx.Select(
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("InputTxid", commitmentTx.RSMCTxid),
		q.Eq("Type", brType),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		First(breachRemedyTransaction)
	if breachRemedyTransaction.Id == 0 {
		breachRemedyTransaction, err = createBRTxObj(user.PeerId, channelInfo, brType, commitmentTx, &user)
		if err != nil {
			log.Println(err)
			return nil, err
		}
		if breachRemedyTransaction.Amount > 0 {
			retMap, err = omnicore.OmniCreateRawTransactionUseUnsendInput(
				commitmentTx.RSMCMultiAddress,
				inputs,
				outputAddress,
				channelInfo.FundingAddress,
				channelInfo.PropertyId,
				breachRemedyTransaction.Amount,
				getBtcMinerAmount(channelInfo.BtcAmount),
				0,
				&commitmentTx.RSMCRedeemScript)
			if err != nil {
				log.Println(err)
				return nil, err
			}
			breachRemedyTransaction.OutAddress = outputAddress
			breachRemedyTransaction.BrTxHex = retMap["hex"].(string)
			breachRemedyTransaction.CurrState = dao.TxInfoState_Create
			_ = tx.Save(breachRemedyTransaction)
			retMap["br_id"] = breachRemedyTransaction.Id
		}
	} else {
		retMap, err = omnicore.OmniCreateRawTransactionUseUnsendInput(
			commitmentTx.RSMCMultiAddress,
			inputs,
			outputAddress,
			channelInfo.FundingAddress,
			channelInfo.PropertyId,
			breachRemedyTransaction.Amount,
			getBtcMinerAmount(channelInfo.BtcAmount),
			0,
			&commitmentTx.RSMCRedeemScript)
		if err != nil {
			log.Println(err)
			return nil, err
		}
		retMap["br_id"] = int64(breachRemedyTransaction.Id)
	}

	return retMap, nil
}

func createCurrCommitmentTxPartialSignedBR(tx storm.Node, brType dao.BRType, channelInfo *dao.ChannelInfo,
	commitmentTx *dao.CommitmentTransaction, inputs []bean.TransactionInputItem,
	outputAddress string, brHex string, user bean.User) (err error) {
	if len(inputs) == 0 {
		return nil
	}
	breachRemedyTransaction := &dao.BreachRemedyTransaction{}
	_ = tx.Select(
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("InputTxid", commitmentTx.RSMCTxid),
		q.Eq("Type", brType),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		First(breachRemedyTransaction)
	if breachRemedyTransaction.Id == 0 {
		breachRemedyTransaction, err = createBRTxObj(user.PeerId, channelInfo, brType, commitmentTx, &user)
		if err != nil {
			log.Println(err)
			return err
		}
		if breachRemedyTransaction.Amount > 0 {
			breachRemedyTransaction.OutAddress = outputAddress
			breachRemedyTransaction.BrTxHex = brHex
			breachRemedyTransaction.Txid = omnicore.GetTxId(brHex)
			breachRemedyTransaction.CurrState = dao.TxInfoState_Create
			_ = tx.Save(breachRemedyTransaction)
		}
	}
	return nil
}

//创建RawBR obj
func createRawBR(brType dao.BRType, channelInfo *dao.ChannelInfo, commitmentTx *dao.CommitmentTransaction, inputs []bean.TransactionInputItem,
	outputAddress string, user bean.User) (retMap bean.NeedClientSignTxData, err error) {
	if len(inputs) == 0 {
		return retMap, errors.New("empty inputs")
	}

	breachRemedyTransaction, err := createBRTxObj(user.PeerId, channelInfo, brType, commitmentTx, &user)
	if err != nil {
		log.Println(err)
		return retMap, err
	}
	if breachRemedyTransaction.Amount > 0 {
		brTxData, err := omnicore.OmniCreateRawTransactionUseUnsendInput(
			commitmentTx.RSMCMultiAddress,
			inputs,
			outputAddress,
			channelInfo.FundingAddress,
			channelInfo.PropertyId,
			breachRemedyTransaction.Amount,
			getBtcMinerAmount(channelInfo.BtcAmount),
			0,
			&commitmentTx.RSMCRedeemScript)
		if err != nil {
			log.Println(err)
			return retMap, err
		}
		c2bBrRawData := bean.NeedClientSignTxData{}
		c2bBrRawData.Hex = brTxData["hex"].(string)
		c2bBrRawData.Inputs = brTxData["inputs"]
		c2bBrRawData.IsMultisig = true
		return c2bBrRawData, nil
	}

	return retMap, errors.New("fail to createRawBR brType " + strconv.Itoa(int(brType)))
}

// 第一次签名完成，更新RawBR
func updateCurrCommitmentTxRawBR(tx storm.Node, id int64, firstSignedBrHex string, user bean.User) (err error) {
	breachRemedyTransaction := &dao.BreachRemedyTransaction{}
	_ = tx.Select(
		q.Eq("Id", id),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		First(breachRemedyTransaction)
	if breachRemedyTransaction.Id > 0 {
		if len(breachRemedyTransaction.Txid) == 0 {
			if pass, txid := compareBR(breachRemedyTransaction.BrTxHex, firstSignedBrHex); pass == true {
				breachRemedyTransaction.Txid = txid
				breachRemedyTransaction.BrTxHex = firstSignedBrHex
				_ = tx.Update(breachRemedyTransaction)
				return nil
			}
		}
	}
	return errors.New("not found br by id")
}

func compareBR(hex1 string, hex2 string) (bool, string) {

	hex1Decode, err := omnicore.DecodeBtcRawTransaction(hex1)
	if err != nil {
		return false, ""
	}
	hex2Decode, err := omnicore.DecodeBtcRawTransaction(hex2)
	if err != nil {
		return false, ""
	}
	hex1Vin := gjson.Get(hex1Decode, "vin").Array()
	hex2Vin := gjson.Get(hex2Decode, "vin").Array()
	if len(hex1Vin) != len(hex2Vin) {
		return false, ""
	}
	for i := 0; i < len(hex1Vin); i++ {
		vin1txId := hex1Vin[i].Get("txid").Str
		vin2txId := hex2Vin[i].Get("txid").Str
		if vin1txId != vin2txId {
			return false, ""
		}
	}
	return true, gjson.Get(hex2Decode, "txid").Str
}

//对上一个承诺交易的br进行签名
func signLastBR(tx storm.Node, brType dao.BRType, channelInfo dao.ChannelInfo, userPeerId string, lastTempAddressPrivateKey string, lastCommitmentTxid int) (err error) {
	lastBreachRemedyTransaction := &dao.BreachRemedyTransaction{}
	err = tx.Select(
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("CommitmentTxId", lastCommitmentTxid),
		q.Eq("Type", brType),
		q.Or(
			q.Eq("PeerIdA", userPeerId),
			q.Eq("PeerIdB", userPeerId))).
		OrderBy("CreateAt").
		Reverse().First(lastBreachRemedyTransaction)
	if lastBreachRemedyTransaction.Id > 0 {
		inputs, err := getInputsForNextTxByParseTxHashVout(
			lastBreachRemedyTransaction.InputTxHex,
			lastBreachRemedyTransaction.InputAddress,
			lastBreachRemedyTransaction.InputAddressScriptPubKey,
			lastBreachRemedyTransaction.InputRedeemScript)
		if err != nil {
			log.Println(err)
			return errors.New(fmt.Sprintf(enum.Tips_rsmc_failToGetInput, "breachRemedyTransaction"))
		}

		if lastBreachRemedyTransaction.CurrState == dao.TxInfoState_CreateAndSign {
			return nil
		}

		signedBRTxid, signedBRHex, err := omnicore.OmniSignRawTransactionForUnsend(lastBreachRemedyTransaction.BrTxHex, inputs, lastTempAddressPrivateKey)
		if err != nil {
			return errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "breachRemedyTransaction"))
		}
		lastBreachRemedyTransaction.Txid = signedBRTxid
		lastBreachRemedyTransaction.BrTxHex = signedBRHex
		lastBreachRemedyTransaction.SignAt = time.Now()
		lastBreachRemedyTransaction.CurrState = dao.TxInfoState_CreateAndSign
		return tx.Update(lastBreachRemedyTransaction)
	}
	return nil
}

func checkBobRsmcData(rsmcHex, toAddress string, commitmentTransaction *dao.CommitmentTransaction) error {
	_, err := omnicore.VerifyOmniTxHex(rsmcHex, commitmentTransaction.PropertyId, commitmentTransaction.AmountToCounterparty, toAddress, true)
	if err != nil {
		return err
	}
	return nil
}


<|start_filename|>lightclient/wsclient_commitment.go<|end_filename|>
package lightclient

import (
	"encoding/json"
	"github.com/omnilaboratory/obd/admin"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/service"
	"log"
	"strconv"
)

func (client *Client) CommitmentTxModule(msg bean.RequestMessage) (enum.SendTargetType, []byte, bool) {
	status := false
	var sendType = enum.SendTargetType_SendToNone
	data := ""
	switch msg.Type {
	case enum.MsgType_CommitmentTx_SendCommitmentTransactionCreated_351:

		if client.User.IsAdmin {
			err := admin.RsmcAliceCreateTx(&msg, client.User)
			if err != nil {
				data = err.Error()
				log.Println(data)
				msg.Type = enum.MsgType_CommitmentTx_SendCommitmentTransactionCreated_351
				client.SendToMyself(msg.Type, status, data)
				break
			}
		}
		retData, needSign, err := service.CommitmentTxService.CommitmentTransactionCreated(msg, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(retData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		if needSign == false {
			if status {
				msg.Type = enum.MsgType_CommitmentTx_CommitmentTransactionCreated_351
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}
		} else {
			if client.User.IsAdmin {
				signedDataForC2a, err := admin.RsmcAliceFirstSignC2a(retData, client.User)
				if err != nil {
					data = err.Error()
					status = false
				} else {
					marshal, _ := json.Marshal(signedDataForC2a)
					msg.Data = string(marshal)
					toAlice, retData, err := service.CommitmentTxService.OnAliceSignC2aRawTxAtAliceSide(msg, client.User)
					if err != nil {
						data = err.Error()
						status = false
					} else {
						bytes, _ := json.Marshal(retData)
						msg.Type = enum.MsgType_CommitmentTx_CommitmentTransactionCreated_351
						data = string(bytes)
						err = client.sendDataToP2PUser(msg, status, data)
						if err != nil {
							data = err.Error()
							status = false
						}

						bytes, err := json.Marshal(toAlice)
						if err != nil {
							data = err.Error()
						} else {
							data = string(bytes)
							status = true
						}
						msg.Type = enum.MsgType_ClientSign_CommitmentTx_AliceSignC2a_360
						client.SendToMyself(msg.Type, status, data)
						break
					}
				}
			}
		}
		msg.Type = enum.MsgType_CommitmentTx_SendCommitmentTransactionCreated_351
		client.SendToMyself(msg.Type, status, data)

	case enum.MsgType_ClientSign_CommitmentTx_AliceSignC2a_360:
		toAlice, retData, err := service.CommitmentTxService.OnAliceSignC2aRawTxAtAliceSide(msg, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(retData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}

			if status {
				msg.Type = enum.MsgType_CommitmentTx_CommitmentTransactionCreated_351
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}

			if status {
				bytes, err := json.Marshal(toAlice)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}

		msg.Type = enum.MsgType_ClientSign_CommitmentTx_AliceSignC2a_360
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_ItemsByChanId_3200:
		nodes, count, err := service.CommitmentTxService.GetItemsByChannelId(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			page := make(map[string]interface{})
			page["count"] = len(nodes)
			page["totalCount"] = count
			page["body"] = nodes
			bytes, err := json.Marshal(page)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_ItemById_3201:
		id, err := strconv.Atoi(msg.Data)
		if err != nil {
			log.Println(err)
			data = err.Error()
		} else {
			node, err := service.CommitmentTxService.GetItemById(id, *client.User)
			if err != nil {
				data = err.Error()
			} else {
				bytes, err := json.Marshal(node)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_Count_3202:
		count, err := service.CommitmentTxService.TotalCount(msg.Data, *client.User)
		if err != nil {
			data = err.Error()
		} else {
			data = strconv.Itoa(count)
			status = true
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_LatestCommitmentTxByChanId_3203:
		node, err := service.CommitmentTxService.GetLatestCommitmentTxByChannelId(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(node)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_LatestRDByChanId_3204:
		node, err := service.CommitmentTxService.GetLatestRDTxByChannelId(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(node)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_LatestBRByChanId_3205:
		node, err := service.CommitmentTxService.GetLatestBRTxByChannelId(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(node)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_DelItemByChanId_3209:
		err := service.CommitmentTxService.DelItemByChannelId(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			data = "success"
			status = true
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_SendSomeCommitmentById_3206:
		node, err := service.CommitmentTxService.SendSomeCommitmentById(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(node)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_AllRDByChanId_3207:
		node, err := service.CommitmentTxService.GetAllRDByChannelId(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(node)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_CommitmentTx_AllBRByChanId_3208:
		node, err := service.CommitmentTxService.GetAllBRByChannelId(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(node)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_ClientSign_CommitmentTx_AliceSignC2b_362:
		node, err := service.CommitmentTxService.OnAliceSignedC2bTxAtAliceSide(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(node)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_ClientSign_CommitmentTx_AliceSignC2b_Rd_363:
		aliceData, bobData, _, err := service.CommitmentTxService.OnAliceSignedC2b_RDTxAtAliceSide(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bobBytes, err := json.Marshal(bobData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bobBytes)
				status = true
			}
			if status {
				msg.Type = enum.MsgType_CommitmentTxSigned_SecondToBobSign_353
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					data = err.Error()
					status = false
				}
			}

			aliceBytes, err := json.Marshal(aliceData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(aliceBytes)
				status = true
			}
		}
		msg.Type = enum.MsgType_ClientSign_CommitmentTx_AliceSignC2b_Rd_363
		client.SendToMyself(msg.Type, status, data)
	}
	return sendType, []byte(data), status
}
func (client *Client) commitmentTxSignModule(msg bean.RequestMessage) (enum.SendTargetType, []byte, bool) {
	status := false
	var sendType = enum.SendTargetType_SendToNone
	data := ""
	switch msg.Type {
	case enum.MsgType_CommitmentTxSigned_SendRevokeAndAcknowledgeCommitmentTransaction_352:
		retData, needSignC2b, err := service.CommitmentTxSignedService.RevokeAndAcknowledgeCommitmentTransaction(msg, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(retData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		if status {
			if needSignC2b == false {
				msg.Type = enum.MsgType_CommitmentTxSigned_ToAliceSign_352
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					status = false
					data = err.Error()
				}
			}
		}
		msg.Type = enum.MsgType_CommitmentTxSigned_SendRevokeAndAcknowledgeCommitmentTransaction_352
		client.SendToMyself(msg.Type, status, data)

	case enum.MsgType_ClientSign_CommitmentTx_BobSignC2b_361:
		toBobData, retData, err := service.CommitmentTxSignedService.OnBobSignC2bTransactionAtBobSide(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(retData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}

			if status {
				msg.Type = enum.MsgType_CommitmentTxSigned_ToAliceSign_352
				err = client.sendDataToP2PUser(msg, status, data)
				if err != nil {
					status = false
					data = err.Error()
				}
			}

			if status {
				bytes, err := json.Marshal(toBobData)
				if err != nil {
					data = err.Error()
				} else {
					data = string(bytes)
					status = true
				}
			}
		}
		msg.Type = enum.MsgType_ClientSign_CommitmentTx_BobSignC2b_361
		client.SendToMyself(msg.Type, status, data)
	case enum.MsgType_ClientSign_CommitmentTx_BobSignC2b_Rd_364:
		retData, err := service.CommitmentTxSignedService.BobSignC2bRdAtBobSide(msg.Data, client.User)
		if err != nil {
			data = err.Error()
		} else {
			bytes, err := json.Marshal(retData)
			if err != nil {
				data = err.Error()
			} else {
				data = string(bytes)
				status = true
			}
		}
		client.SendToMyself(msg.Type, status, data)
	}
	return sendType, []byte(data), status
}


<|start_filename|>proxy/tests/rpcclient_wallet_test.go<|end_filename|>
package main

import (
	"context"
	"encoding/json"
	proxy "github.com/omnilaboratory/obd/proxy/pb"
	"github.com/omnilaboratory/obd/tool"
	"google.golang.org/grpc"
	"log"
	"testing"
)

func TestConnectPeer(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	resp, err := client.ConnectPeer(context.Background(), &proxy.ConnectPeerRequest{
		Addr: "/ip4/127.0.0.1/tcp/4002/p2p/QmZPzUh7Q6PQg6gXB4XheaoZMMhHA9JNeCrJsp3FWjFrAF",
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestDisconnectPeer(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	resp, err := client.DisconnectPeer(context.Background(), &proxy.DisconnectPeerRequest{
		Addr: "QmZPzUh7Q6PQg6gXB4XheaoZMMhHA9JNeCrJsp3FWjFrAF",
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestGetAddressInfo(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()
	resp, err := client.GetAddressInfo(context.Background(), &proxy.GetAddressInfoRequest{
		Addr: "mvsvbhE5CUd23R2X2XTmNodHmbGSPcEqNb",
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestNewAddress(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()
	resp, err := client.NewAddress(context.Background(), &proxy.NewAddressRequest{})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestNextAddr(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()
	resp, err := client.NextAddr(context.Background(), &proxy.AddrRequest{})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestEstimateFee(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()
	resp, err := client.EstimateFee(context.Background(), &proxy.EstimateFeeRequest{})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestGenSeed(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()
	resp, err := client.GenSeed(context.Background(), &proxy.GenSeedRequest{})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestLogin(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()

	login, err := client.Login(context.Background(), &proxy.LoginRequest{
		Mnemonic:   "dawn enter attitude merry cliff stone rely convince team warfare wasp whisper",
		LoginToken: tool.SignMsgWithMd5([]byte("<PASSWORD>")),
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(login)
	log.Println(string(marshal))
}
func TestChangePassword(t *testing.T) {

	client, conn := getWalletClient()
	defer conn.Close()

	resp, err := client.ChangePassword(context.Background(), &proxy.ChangePasswordRequest{
		CurrentPassword: "<PASSWORD>",
		NewPassword:     "<PASSWORD>",
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}
func TestLogout(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()

	resp, err := client.Logout(context.Background(), &proxy.LogoutRequest{})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestGetInfo(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()

	resp, err := client.GetInfo(context.Background(), &proxy.GetInfoRequest{})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestListPeers(t *testing.T) {
	client, conn := getWalletClient()
	defer conn.Close()

	resp, err := client.ListPeers(context.Background(), &proxy.ListPeersRequest{})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func getWalletClient() (proxy.WalletClient, *grpc.ClientConn) {
	opts := grpc.WithInsecure()
	conn, err := grpc.Dial("localhost:50051", opts)
	if err != nil {
		log.Println(err)
		return nil, nil
	}
	return proxy.NewWalletClient(conn), conn
}

func getClient() (proxy.LightningClient, *grpc.ClientConn) {

	opts := grpc.WithInsecure()
	conn, err := grpc.Dial("localhost:50051", opts)
	if err != nil {
		log.Println(err)
		return nil, nil
	}
	return proxy.NewLightningClient(conn), conn
}


<|start_filename|>service/local_init_params.go<|end_filename|>
package service

import (
	"github.com/omnilaboratory/obd/bean"
)

type commitmentTxOutputBean struct {
	AmountToRsmc               float64
	AmountToCounterparty       float64
	AmountToHtlc               float64
	RsmcTempPubKey             string
	HtlcTempPubKey             string
	OppositeSideChannelPubKey  string
	OppositeSideChannelAddress string
}

var P2PLocalNodeId string

var OnlineUserMap = make(map[string]*bean.User)


<|start_filename|>tests/integration/Makefile<|end_filename|>
format:
	black *.py

<|start_filename|>tracker/rpc/omniclient.go<|end_filename|>
package rpc

import (
	"errors"
	"github.com/omnilaboratory/obd/tool"
	"github.com/shopspring/decimal"
	"github.com/tidwall/gjson"
	"strconv"
)

//https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md
//Returns various state information of the client and protocol.
func (client *Client) OmniGetInfo() (result string, err error) {
	return client.send("omni_getinfo", nil)
}

//Create and broadcast a simple send transaction.
func (client *Client) OmniSend(fromAddress string, toAddress string, propertyId int, amount float64) (result string, err error) {
	_, err = client.ValidateAddress(fromAddress)
	if err != nil {
		return "", err
	}
	_, err = client.ValidateAddress(toAddress)
	if err != nil {
		return "", err
	}
	return client.send("omni_send", []interface{}{fromAddress, toAddress, propertyId, tool.FloatToString(amount, 8)})
}

//Create new tokens with manageable supply. https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md#omni_sendissuancemanaged
func (client *Client) OmniSendIssuanceFixed(fromAddress string, ecosystem int, divisibleType int, name string, data string, amount float64) (result string, err error) {
	if tool.CheckIsAddress(fromAddress) == false {
		return "", errors.New("error fromAddress")
	}
	if tool.CheckIsString(&name) == false {
		return "", errors.New("error name")
	}
	if ecosystem != 1 && ecosystem != 2 {
		return "", errors.New("error ecosystem")
	}
	if divisibleType != 1 && divisibleType != 2 {
		return "", errors.New("error divisibleType")
	}
	if amount < 0 {
		return "", errors.New("error amount")
	}
	amountStr := strconv.FormatFloat(amount, 'f', 8, 64)
	if divisibleType == 1 {
		amountStr = strconv.FormatFloat(amount, 'f', 0, 64)
	}
	if tool.CheckIsString(&data) == false {
		data = ""
	}

	_, _ = client.ValidateAddress(fromAddress)

	return client.send("omni_sendissuancefixed", []interface{}{fromAddress, ecosystem, divisibleType, 0, "", "", name, "", data, amountStr})
}

//Create new tokens with manageable supply. https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md#omni_sendissuancemanaged
func (client *Client) OmniSendIssuanceManaged(fromAddress string, ecosystem int, divisibleType int, name string, data string) (result string, err error) {
	if tool.CheckIsString(&fromAddress) == false {
		return "", errors.New("error fromAddress")
	}
	if tool.CheckIsString(&name) == false {
		return "", errors.New("error name")
	}
	if ecosystem != 1 && ecosystem != 2 {
		return "", errors.New("error ecosystem")
	}
	if divisibleType != 1 && divisibleType != 2 {
		return "", errors.New("error divisibleType")
	}
	if tool.CheckIsString(&data) == false {
		data = ""
	}
	_, _ = client.ValidateAddress(fromAddress)
	return client.send("omni_sendissuancemanaged", []interface{}{fromAddress, ecosystem, divisibleType, 0, "", "", name, "", data})
}

// Issue or grant new units of managed tokens. https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md#omni_sendgrant
func (client *Client) OmniSendGrant(fromAddress string, propertyId int64, amount float64, memo string) (result string, err error) {
	if tool.CheckIsString(&fromAddress) == false {
		return "", errors.New("error fromAddress")
	}
	if propertyId < 0 {
		return "", errors.New("error propertyId")
	}

	_, err = client.OmniGetProperty(propertyId)
	if err != nil {
		return "", err
	}
	if amount < 0 {
		return "", errors.New("error amount")
	}
	if tool.CheckIsString(&memo) == false {
		memo = ""
	}
	return client.send("omni_sendgrant", []interface{}{fromAddress, "", propertyId, tool.FloatToString(amount, 8), memo})
}

// Revoke units of managed tokens. https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md#omni_sendrevoke
func (client *Client) OmniSendRevoke(fromAddress string, propertyId int64, amount float64, memo string) (result string, err error) {
	if tool.CheckIsString(&fromAddress) == false {
		return "", errors.New("error fromAddress")
	}
	if propertyId < 0 {
		return "", errors.New("error propertyId")
	}
	if amount < 0 {
		return "", errors.New("error amout")
	}

	s, err := client.OmniGetProperty(propertyId)
	if err != nil {
		return "", err
	}
	amountStr := strconv.FormatFloat(amount, 'f', 0, 64)
	divisible := gjson.Get(s, "divisible").Bool()
	if divisible {
		amountStr = strconv.FormatFloat(amount, 'f', 8, 64)
	}

	if tool.CheckIsString(&memo) == false {
		memo = ""
	}

	_, _ = client.ValidateAddress(fromAddress)

	return client.send("omni_sendrevoke", []interface{}{fromAddress, propertyId, amountStr, memo})
}

func (client *Client) OmniGetbalance(address string, propertyId int) (result string, err error) {
	return client.send("omni_getbalance", []interface{}{address, propertyId})
}

//Get detailed information about an Omni transaction.
func (client *Client) OmniGettransaction(txid string) (result string, err error) {
	return client.send("omni_gettransaction", []interface{}{txid})
}

//Get detailed information about an Omni transaction.
func (client *Client) OmniGetProperty(propertyId int64) (result string, err error) {
	return client.send("omni_getproperty", []interface{}{propertyId})
}

//Get detailed information about an Omni transaction.
func (client *Client) OmniListProperties() (result string, err error) {
	return client.send("omni_listproperties", []interface{}{})
}

func (client *Client) OmniGetAllBalancesForAddress(address string) (result string, err error) {
	_, err = client.ValidateAddress(address)
	if err != nil {
		return "", err
	}

	return client.send("omni_getallbalancesforaddress ", []interface{}{address})
}

//List wallet transactions, optionally filtered by an address and block boundaries.
//https://github.com/OmniLayer/omnicore/blob/master/src/omnicore/doc/rpc-api.md#omni_listtransactions
func (client *Client) OmniListTransactions(address string, count int, skip int) (result string, err error) {
	_, _ = client.ValidateAddress(address)
	if tool.CheckIsString(&address) == false {
		address = "*"
	}
	if count < 0 {
		count = 10
	}
	if skip < 0 {
		skip = 0
	}
	return client.send("omni_listtransactions", []interface{}{address, count, skip})
}

func (client *Client) omniCreatePayloadSimpleSend(propertyId int64, amount float64) (result string, err error) {
	return client.send("omni_createpayload_simplesend", []interface{}{propertyId, decimal.NewFromFloat(amount).String()})
}
func (client *Client) omniCreateRawtxOpreturn(rawtx string, payload string) (result string, err error) {
	return client.send("omni_createrawtx_opreturn", []interface{}{rawtx, payload})
}
func (client *Client) omniCreateRawtxChange(rawtx string, prevtxs []map[string]interface{}, destination string, fee float64) (result string, err error) {
	return client.send("omni_createrawtx_change", []interface{}{rawtx, prevtxs, destination, fee})
}
func (client *Client) omniCreateRawtxReference(rawtx string, destination string) (result string, err error) {
	return client.send("omni_createrawtx_reference", []interface{}{rawtx, destination})
}


<|start_filename|>config/p2p_addr.go<|end_filename|>
package config

import (
	ma "github.com/multiformats/go-multiaddr"
	"strings"
)

type addrList []ma.Multiaddr

func (al *addrList) String() string {
	strs := make([]string, len(*al))
	for i, addr := range *al {
		strs[i] = addr.String()
	}
	return strings.Join(strs, ",")
}

func (al *addrList) Set(value string) error {
	addr, err := ma.NewMultiaddr(value)
	if err != nil {
		return err
	}
	*al = append(*al, addr)
	return nil
}

func StringsToAddrs(addrStrings []string) (maddrs []ma.Multiaddr, err error) {
	for _, addrString := range addrStrings {
		addr, err := ma.NewMultiaddr(addrString)
		if err != nil {
			return maddrs, err
		}
		maddrs = append(maddrs, addr)
	}
	return
}


<|start_filename|>bean/common_bean.go<|end_filename|>
package bean

type ChannelState int

const (
	ChannelState_Create            ChannelState = 10
	ChannelState_WaitFundAsset     ChannelState = 11
	ChannelState_NewTx             ChannelState = 12
	ChannelState_CanUse            ChannelState = 20
	ChannelState_Close             ChannelState = 21
	ChannelState_HtlcTx            ChannelState = 22
	ChannelState_LockByTracker     ChannelState = 23
	ChannelState_OpenChannelRefuse ChannelState = 30

	ProtocolIdForUserState         = "tracker/userState/1.0.1"
	ProtocolIdForChannelInfoChange = "tracker/channelInfo/1.0.1"
	ProtocolIdForLockChannel       = "tracker/lockChannel/1.0.1"
	ProtocolIdForUnlockChannel     = "tracker/lockChannel/1.0.2"
)

//更新通道
type ChannelInfoRequest struct {
	ChannelId  string       `json:"channel_id"`
	PropertyId int64        `json:"property_id"`
	CurrState  ChannelState `json:"curr_state"`
	IsAlice    bool         `json:"is_alice"` //是否是alice方的节点
	PeerIdA    string       `json:"peer_ida"`
	PeerIdB    string       `json:"peer_idb"`
	AmountA    float64      `json:"amount_a"`
	AmountB    float64      `json:"amount_b"`
}

//节点登录
type ObdNodeLoginRequest struct {
	NodeId     string `json:"node_id"`
	P2PAddress string `json:"p2p_address"`
}

//节点的用户登录
type ObdNodeUserLoginRequest struct {
	UserId    string `json:"user_id"`
	P2pNodeId string `json:"p2p_node_id"`
}

//节点的用户登录
type TrackerLockChannelRequest struct {
	UserId    string `json:"user_id"`
	ChannelId string `json:"channel_id"`
}


<|start_filename|>proxy/rpc/msg_obd.go<|end_filename|>
package rpc

type loginInfo struct {
	Mnemonic   string `json:"mnemonic"`
	LoginToken string `json:"login_token"`
}

type updateLoginToken struct {
	CurrentPassword string `json:"current_password"`
	NewPassword     string `json:"new_password"`
}

type InvoiceInfo struct {
	ExpiryTime  string  `json:"expiry_time"`
	PropertyId  int64   `json:"property_id"`
	Amount      float64 `json:"amount"`
	Description string  `json:"description"`
	IsPrivate   bool    `json:"is_private"`
}
type ParseInvoice struct {
	Invoice string `json:"invoice"`
}


<|start_filename|>bean/chainhash/hash_test.go<|end_filename|>
package chainhash

import (
	"log"
	"testing"
)

func TestNewHashFromStr(t *testing.T) {
	str := "4c0e8d55056c5bd3cb4404acfcfb6e3b51127fb9131d9260892ef207c8ab4380"
	//str := "4"
	log.Println(len(str))
	hashes, e := NewHashFromStr(str)
	if e != nil {
		log.Println(e)
	}
	log.Println(*hashes)
}


<|start_filename|>proxy/tests/rpcclient_funding_test.go<|end_filename|>
package main

import (
	"context"
	proxy "github.com/omnilaboratory/obd/proxy/pb"
	"log"
	"testing"
)

func TestFundChannel(t *testing.T) {
	client, conn := getClient()
	defer conn.Close()
	fundChannel, err := client.FundChannel(context.Background(), &proxy.FundChannelRequest{
		RecipientInfo: &proxy.RecipientNodeInfo{
			RecipientNodePeerId: "<KEY>",
			RecipientUserPeerId: "<KEY>"},
		TemplateChannelId: "7933507fccb2aa5eef3873f92bc6ce1355f4aa198ed0854efd5995e3a4a4e9ec",
		BtcAmount:         0.0004,
		PropertyId:        137,
		AssetAmount:       1,
	})
	if err != nil {
		log.Println(err)
		return
	}
	log.Println(fundChannel.ChannelId)
}


<|start_filename|>admin/fund.go<|end_filename|>
package admin

import (
	"encoding/json"
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/service"
	"log"
)

func AliceSignFundBtc(msg bean.RequestMessage, hexData map[string]interface{}, user *bean.User) (signedData map[string]interface{}, err error) {
	if user == nil || user.IsAdmin == false {
		return hexData, nil
	}

	sendInfo := &bean.FundingBtc{}
	_ = json.Unmarshal([]byte(msg.Data), sendInfo)

	walletInfo, err := getChannelWalletInfoByAddress(sendInfo.ToAddress, user)
	if err != nil {
		return nil, err
	}

	hex := hexData["hex"].(string)
	inputs := hexData["inputs"]
	_, signedHex, err := omnicore.OmniSignRawTransactionForUnsend(hex, convertBean(inputs), walletInfo.Wif)
	if err != nil {
		return nil, err
	}

	signedData = hexData
	signedData["hex"] = signedHex

	return signedData, nil
}

func AliceSignFundAsset(msg bean.RequestMessage, hexData map[string]interface{}, user *bean.User) (signedData map[string]interface{}, err error) {
	if user == nil || user.IsAdmin == false {
		return hexData, nil
	}

	sendInfo := &bean.FundingAsset{}
	_ = json.Unmarshal([]byte(msg.Data), sendInfo)
	walletInfo, err := getChannelWalletInfoByAddress(sendInfo.ToAddress, user)
	if err != nil {
		return nil, err
	}
	hex := hexData["hex"].(string)
	inputs := hexData["inputs"]
	_, signedHex, err := omnicore.OmniSignRawTransactionForUnsend(hex, convertBean(inputs), walletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData = hexData
	signedData["hex"] = signedHex

	return signedData, nil
}

func AliceFirstSignFundBtcRedeemTx(hexData interface{}, user *bean.User) (signedData *bean.NeedClientSignHexData, err error) {
	signData := hexData.(bean.NeedClientSignHexData)
	channelInfo := dao.ChannelInfo{}
	user.Db.Select(q.Eq("TemporaryChannelId", signData.TemporaryChannelId), q.Eq("CurrState", bean.ChannelState_WaitFundAsset)).First(&channelInfo)
	if channelInfo.Id == 0 {
		return nil, errors.New("not found the channel")
	}

	walletInfo, err := service.HDWalletService.GetAddressByIndex(user, uint32(channelInfo.FunderAddressIndex))
	if err != nil {
		return nil, err
	}

	_, signedHex, err := omnicore.OmniSignRawTransactionForUnsend(signData.Hex, convertBean(signData.Inputs), walletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signData.Hex = signedHex

	return &signData, nil
}

func BobSignFundBtcRedeemTx(data string, user *bean.User) (resultData *bean.SendSignFundingBtc, err error) {
	resultData = &bean.SendSignFundingBtc{}

	fundingBtcOfP2p := bean.FundingBtcOfP2p{}
	err = json.Unmarshal([]byte(data), &fundingBtcOfP2p)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	walletInfo, err := getChannelWalletInfoByTemplateId(fundingBtcOfP2p.TemporaryChannelId, user)
	if err != nil {
		return nil, err
	}

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(fundingBtcOfP2p.SignData.Hex, convertBean(fundingBtcOfP2p.SignData.Inputs), walletInfo.Wif)
	if err != nil {
		return nil, err
	}

	resultData.SignedMinerRedeemTransactionHex = hex
	resultData.FundingTxid = fundingBtcOfP2p.FundingTxid
	resultData.TemporaryChannelId = fundingBtcOfP2p.TemporaryChannelId
	resultData.Approval = true
	return resultData, nil
}

func AliceCreateTempWalletForC1a(msg *bean.RequestMessage, user *bean.User) (err error) {
	reqData := &bean.SendRequestAssetFunding{}
	err = json.Unmarshal([]byte(msg.Data), reqData)
	address, err := service.HDWalletService.CreateNewAddress(user)
	if err != nil {
		return err
	}
	reqData.TempAddressIndex = address.Index
	reqData.TempAddressPubKey = address.PubKey
	marshal, _ := json.Marshal(reqData)
	msg.Data = string(marshal)
	return nil
}

func AliceSignC1a(hexData interface{}, user *bean.User) (signedData *bean.AliceSignC1aOfAssetFunding, err error) {
	signData := hexData.(bean.NeedClientSignHexData)

	walletInfo, err := getChannelWalletInfoByTemplateId(signData.TemporaryChannelId, user)
	if err != nil {
		return nil, err
	}
	_, signedHex, err := omnicore.OmniSignRawTransactionForUnsend(signData.Hex, convertBean(signData.Inputs), walletInfo.Wif)
	if err != nil {
		return nil, err
	}
	signedData = &bean.AliceSignC1aOfAssetFunding{}
	signedData.SignedC1aHex = signedHex
	return signedData, nil
}

func BobSignC1a(data string, user *bean.User) (resultData *bean.SignAssetFunding, err error) {
	resultData = &bean.SignAssetFunding{}

	p2pData := bean.FundingAssetOfP2p{}
	_ = json.Unmarshal([]byte(data), &p2pData)

	resultData.TemporaryChannelId = p2pData.TemporaryChannelId

	channelAddressInfo, err := getChannelWalletInfoByTemplateId(p2pData.TemporaryChannelId, user)
	if err != nil {
		return nil, err
	}

	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(p2pData.SignData.Hex, convertBean(p2pData.SignData.Inputs), channelAddressInfo.Wif)
	if err != nil {
		return nil, err
	}
	resultData.SignedAliceRsmcHex = hex

	return resultData, nil
}

func BobSignRdAndBrOfC1a(data string, user *bean.User) (resultData *bean.SignRdAndBrOfAssetFunding, err error) {
	resultData = &bean.SignRdAndBrOfAssetFunding{}

	reqData := &bean.NeedSignRdAndBrOfAssetFunding{}
	err = json.Unmarshal([]byte(data), reqData)

	resultData.TemporaryChannelId = reqData.TemporaryChannelId

	channelAddressInfo, err := getChannelWalletInfoByTemplateId(resultData.TemporaryChannelId, user)
	if err != nil {
		return nil, err
	}

	aliceRdSignData := reqData.AliceRdSignData
	rdHex := aliceRdSignData["hex"].(string)
	rdInputs := aliceRdSignData["inputs"]
	_, hex, err := omnicore.OmniSignRawTransactionForUnsend(rdHex, convertBean(rdInputs), channelAddressInfo.Wif)
	if err != nil {
		return nil, err
	}
	resultData.RdSignedHex = hex

	aliceBrSignData := reqData.AliceBrSignData
	brHex := aliceBrSignData["hex"].(string)
	brInputs := aliceBrSignData["inputs"]
	resultData.BrId = int64(aliceBrSignData["br_id"].(float64))
	_, hex, err = omnicore.OmniSignRawTransactionForUnsend(brHex, convertBean(brInputs), channelAddressInfo.Wif)
	if err != nil {
		return nil, err
	}
	resultData.BrSignedHex = hex
	return resultData, nil
}

func AliceSignRdOfC1a(hexData map[string]interface{}, user *bean.User) (signedData *bean.AliceSignRDOfAssetFunding, err error) {

	channelId := hexData["channel_id"].(string)
	commitmentTxInfo := &dao.CommitmentTransaction{}
	err = user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		OrderBy("CreateAt").Reverse().
		First(commitmentTxInfo)
	walletInfo, _ := service.HDWalletService.GetAddressByIndex(user, uint32(commitmentTxInfo.RSMCTempAddressIndex))

	rdHex := hexData["hex"].(string)
	rdInputs := hexData["inputs"]
	_, signedHex, err := omnicore.OmniSignRawTransactionForUnsend(rdHex, convertBean(rdInputs), walletInfo.Wif)
	if err != nil {
		return nil, err
	}
	hexData["Hex"] = signedHex
	signedData = &bean.AliceSignRDOfAssetFunding{}
	signedData.ChannelId = channelId
	signedData.RdSignedHex = signedHex
	return signedData, nil
}


<|start_filename|>bean/lightclient_messages.go<|end_filename|>
package bean

// for lightclient to obd

type FundingBtc struct {
	FromAddress string  `json:"from_address"`
	ToAddress   string  `json:"to_address"`
	Amount      float64 `json:"amount"`
	MinerFee    float64 `json:"miner_fee"`
}
type FundingAsset struct {
	FundingBtc
	PropertyId int64 `json:"property_id"`
}
type CreateMultiSigRequest struct {
	MiniSignCount int      `json:"mini_sign_count"`
	PubKeys       []string `json:"pub_keys"`
}

type OmniSendIssuanceManaged struct {
	FromAddress   string `json:"from_address"`
	Name          string `json:"name"`
	Ecosystem     int    `json:"ecosystem"`
	DivisibleType int    `json:"divisible_type"`
	Data          string `json:"data"`
}

type OmniSendIssuanceFixed struct {
	OmniSendIssuanceManaged
	Amount float64 `json:"amount"`
}

type OmniSendGrant struct {
	FromAddress string  `json:"from_address"`
	PropertyId  int64   `json:"property_id"`
	Amount      float64 `json:"amount"`
	Memo        string  `json:"memo"`
}

type OmniSendRevoke OmniSendGrant


<|start_filename|>bean/enum/msg_type.go<|end_filename|>
package enum

type SendTargetType int

const (
	SendTargetType_SendToNone     SendTargetType = -1
	SendTargetType_SendToAll      SendTargetType = 0
	SendTargetType_SendToSomeone  SendTargetType = 1
	SendTargetType_SendToExceptMe SendTargetType = 2
)

type MsgType int

const (
	MsgType_Tracker_Connect_301           MsgType = 301
	MsgType_Tracker_HeartBeat_302         MsgType = 302
	MsgType_Tracker_NodeLogin_303         MsgType = 303
	MsgType_Tracker_UserLogin_304         MsgType = 304
	MsgType_Tracker_UserLogout_305        MsgType = 305
	MsgType_Tracker_UpdateChannelInfo_350 MsgType = 350
	MsgType_Tracker_GetHtlcPath_351       MsgType = 351
	MsgType_Tracker_UpdateHtlcTxState_352 MsgType = 352
	MsgType_Tracker_UpdateUserInfo_353    MsgType = 353
)

// Transaction related messages, login is required: [-100000,-102000]
// Common messages, login is not required: [-102000,-103000]
// User center messages, login is required: [-103000,-104000]
const (
	MsgType_Error_0 MsgType = 0

	// region
	// Common messages, login is not required [-102000,-103000]
	MsgType_UserLogin_2001             MsgType = -102001
	MsgType_UserLogout_2002            MsgType = -102002
	MsgType_p2p_ConnectPeer_2003       MsgType = -102003
	MsgType_GetMnemonic_2004           MsgType = -102004
	MsgType_GetObdNodeInfo_2005        MsgType = -102005
	MsgType_GetMiniBtcFundAmount_2006  MsgType = -102006
	MsgType_HeartBeat_2007             MsgType = -102007
	MsgType_User_UpdateAdminToken_2008 MsgType = -102008
	MsgType_User_GetInfo_2009          MsgType = -102009
	MsgType_p2p_DisconnectPeer_2010    MsgType = -102010
	MsgType_User_End_2099              MsgType = -102099

	MsgType_Core_GetNewAddress_2101                    MsgType = -102101
	MsgType_Core_GetMiningInfo_2102                    MsgType = -102102
	MsgType_Core_GetNetworkInfo_2103                   MsgType = -102103
	MsgType_Core_SignMessageWithPrivKey_2104           MsgType = -102104
	MsgType_Core_VerifyMessage_2105                    MsgType = -102105
	MsgType_Core_DumpPrivKey_2106                      MsgType = -102106
	MsgType_Core_ListUnspent_2107                      MsgType = -102107
	MsgType_Core_BalanceByAddress_2108                 MsgType = -102108
	MsgType_Core_FundingBTC_2109                       MsgType = -102109
	MsgType_Core_BtcCreateMultiSig_2110                MsgType = -102110
	MsgType_Core_Btc_ImportPrivKey_2111                MsgType = -102111
	MsgType_Core_Omni_GetBalance_2112                  MsgType = -102112
	MsgType_Core_Omni_CreateNewTokenFixed_2113         MsgType = -102113
	MsgType_Core_Omni_CreateNewTokenManaged_2114       MsgType = -102114
	MsgType_Core_Omni_GrantNewUnitsOfManagedToken_2115 MsgType = -102115
	MsgType_Core_Omni_RevokeUnitsOfManagedToken_2116   MsgType = -102116
	MsgType_Core_Omni_ListProperties_2117              MsgType = -102117
	MsgType_Core_Omni_GetTransaction_2118              MsgType = -102118
	MsgType_Core_Omni_GetProperty_2119                 MsgType = -102119
	MsgType_Core_Omni_FundingAsset_2120                MsgType = -102120
	MsgType_Core_Omni_Send_2121                        MsgType = -102121
	MsgType_Core_GetTransactionByTxid_2122             MsgType = -102122
	MsgType_Core_SignRawTransaction_2123               MsgType = -102123
	MsgType_Core_Omni_End_2199                         MsgType = -102199
	MsgType_Common_End_2999                            MsgType = -102999
	// endregion

	//region
	//User center messages, login is required: [-103000,-104000]

	//Create new address via mnemonic words
	MsgType_Mnemonic_CreateAddress_3000 MsgType = -103000
	//get address info via mnemonic words and index
	MsgType_Mnemonic_GetAddressByIndex_3001 MsgType = -103001

	//Omni asset funding list
	MsgType_FundingCreate_Asset_AllItem_3100 MsgType = -103100
	//Get omni asset funding info via ID
	MsgType_FundingCreate_Asset_ItemById_3101 MsgType = -103101
	//Get omni asset funding info via channel ID
	MsgType_FundingCreate_Asset_ItemByChannelId_3102 MsgType = -103102
	//Rounds of funding
	MsgType_FundingCreate_Asset_Count_3103 MsgType = -103103
	//BTC funding list
	MsgType_FundingCreate_Btc_AllItem_3104                      MsgType = -103104
	MsgType_FundingCreate_Btc_ItemById_3105                     MsgType = -103105
	MsgType_FundingCreate_Btc_ItemByTempChannelId_3106          MsgType = -103106
	MsgType_FundingCreate_Btc_RDAllItem_3107                    MsgType = -103107
	MsgType_FundingCreate_Btc_ItemRDById_3108                   MsgType = -103108
	MsgType_FundingCreate_Btc_ItemRDByTempChannelId_3109        MsgType = -103109
	MsgType_FundingCreate_Btc_ItemRDByTempChannelIdAndTxId_3110 MsgType = -103110
	MsgType_FundingCreate_Btc_ItemByChannelId_3111              MsgType = -103111

	MsgType_ChannelOpen_AllItem_3150         MsgType = -103150
	MsgType_ChannelOpen_ItemByTempId_3151    MsgType = -103151
	MsgType_ChannelOpen_Count_3152           MsgType = -103152
	MsgType_ChannelOpen_DelItemByTempId_3153 MsgType = -103153
	MsgType_GetChannelInfoByChannelId_3154   MsgType = -103154
	MsgType_GetChannelInfoByDbId_3155        MsgType = -103155
	MsgType_CheckChannelAddessExist_3156     MsgType = -103156

	MsgType_CommitmentTx_ItemsByChanId_3200              MsgType = -103200
	MsgType_CommitmentTx_ItemById_3201                   MsgType = -103201
	MsgType_CommitmentTx_Count_3202                      MsgType = -103202
	MsgType_CommitmentTx_LatestCommitmentTxByChanId_3203 MsgType = -103203
	MsgType_CommitmentTx_LatestRDByChanId_3204           MsgType = -103204
	MsgType_CommitmentTx_LatestBRByChanId_3205           MsgType = -103205
	MsgType_CommitmentTx_SendSomeCommitmentById_3206     MsgType = -103206
	MsgType_CommitmentTx_AllRDByChanId_3207              MsgType = -103207
	MsgType_CommitmentTx_AllBRByChanId_3208              MsgType = -103208
	MsgType_CommitmentTx_DelItemByChanId_3209            MsgType = -103209

	MsgType_Htlc_GetLatestHT1aOrHE1b_3250             MsgType = -103250
	MsgType_Htlc_GetHT1aOrHE1bBySomeCommitmentId_3251 MsgType = -103251
	//endregion

	// region
	// Transaction related messages, login is required: [-100000,-102000]

	MsgType_SendChannelOpen_32 MsgType = -100032
	MsgType_ChannelOpen_32     MsgType = -32
	MsgType_RecvChannelOpen_32 MsgType = -110032

	MsgType_SendChannelAccept_33 MsgType = -100033
	MsgType_ChannelAccept_33     MsgType = -33
	MsgType_RecvChannelAccept_33 MsgType = -110033

	MsgType_FundingCreate_SendBtcFundingCreated_340   MsgType = -100340
	MsgType_ClientSign_Duplex_BtcFundingMinerRDTx_341 MsgType = -100341
	MsgType_FundingCreate_BtcFundingCreated_340       MsgType = -340
	MsgType_FundingCreate_RecvBtcFundingCreated_340   MsgType = -110340

	MsgType_FundingSign_SendBtcSign_350 MsgType = -100350
	MsgType_FundingSign_BtcSign_350     MsgType = -350
	MsgType_FundingSign_RecvBtcSign_350 MsgType = -110350

	MsgType_Funding_134                              MsgType = -100134
	MsgType_FundingCreate_SendAssetFundingCreated_34 MsgType = -100034
	// 客户端签名：alice签名C1a
	MsgType_ClientSign_AssetFunding_AliceSignC1a_1034 MsgType = -101034
	MsgType_FundingCreate_AssetFundingCreated_34      MsgType = -34
	MsgType_FundingCreate_RecvAssetFundingCreated_34  MsgType = -110034

	MsgType_FundingSign_SendAssetFundingSigned_35    MsgType = -100035
	MsgType_ClientSign_AssetFunding_RdAndBr_1035     MsgType = -101035
	MsgType_FundingSign_AssetFundingSigned_35        MsgType = -35
	MsgType_FundingSign_RecvAssetFundingSigned_35    MsgType = -110035
	MsgType_ClientSign_AssetFunding_AliceSignRD_1134 MsgType = -101134

	MsgType_CommitmentTx_SendCommitmentTransactionCreated_351                    MsgType = -100351
	MsgType_CommitmentTx_CommitmentTransactionCreated_351                        MsgType = -351
	MsgType_CommitmentTx_RecvCommitmentTransactionCreated_351                    MsgType = -110351
	MsgType_CommitmentTxSigned_SendRevokeAndAcknowledgeCommitmentTransaction_352 MsgType = -100352
	MsgType_CommitmentTxSigned_ToAliceSign_352                                   MsgType = -352
	MsgType_CommitmentTxSigned_RecvRevokeAndAcknowledgeCommitmentTransaction_352 MsgType = -110352
	MsgType_CommitmentTxSigned_SecondToBobSign_353                               MsgType = -353
	MsgType_ClientSign_BobC2b_Rd_353                                             MsgType = -110353
	MsgType_ClientSign_CommitmentTx_AliceSignC2a_360                             MsgType = -100360
	MsgType_ClientSign_CommitmentTx_BobSignC2b_361                               MsgType = -100361
	MsgType_ClientSign_CommitmentTx_AliceSignC2b_362                             MsgType = -100362
	MsgType_ClientSign_CommitmentTx_AliceSignC2b_Rd_363                          MsgType = -100363
	MsgType_ClientSign_CommitmentTx_BobSignC2b_Rd_364                            MsgType = -100364

	MsgType_SendCloseChannelRequest_38 MsgType = -100038
	MsgType_CloseChannelRequest_38     MsgType = -38
	MsgType_RecvCloseChannelRequest_38 MsgType = -110038

	MsgType_SendCloseChannelSign_39 MsgType = -100039
	MsgType_CloseChannelSign_39     MsgType = -39
	MsgType_RecvCloseChannelSign_39 MsgType = -110039

	// path finding
	MsgType_HTLC_FindPath_401     MsgType = -100401
	MsgType_HTLC_Invoice_402      MsgType = -100402
	MsgType_HTLC_ParseInvoice_403 MsgType = -100403

	MsgType_HTLC_ClientSign_Alice_C3a_100    MsgType = -100100
	MsgType_HTLC_ClientSign_Bob_C3b_101      MsgType = -100101
	MsgType_HTLC_ClientSign_Alice_C3b_102    MsgType = -100102
	MsgType_HTLC_ClientSign_Alice_C3bSub_103 MsgType = -100103
	MsgType_HTLC_ClientSign_Bob_C3bSub_104   MsgType = -100104
	MsgType_HTLC_ClientSign_Alice_He_105     MsgType = -100105
	MsgType_HTLC_SendAddHTLC_40              MsgType = -100040
	MsgType_HTLC_AddHTLC_40                  MsgType = -40
	MsgType_HTLC_RecvAddHTLC_40              MsgType = -110040
	MsgType_HTLC_SendAddHTLCSigned_41        MsgType = -100041
	MsgType_HTLC_NeedPayerSignC3b_41         MsgType = -41
	MsgType_HTLC_RecvAddHTLCSigned_41        MsgType = -110041
	MsgType_HTLC_PayeeCreateHTRD1a_42        MsgType = -42
	MsgType_HTLC_BobSignC3bSubTx_42          MsgType = -110042
	MsgType_HTLC_PayerSignHTRD1a_43          MsgType = -43
	MsgType_HTLC_FinishTransferH_43          MsgType = -110043

	MsgType_HTLC_ClientSign_Bob_HeSub_106  MsgType = -100106
	MsgType_HTLC_ClientSign_Alice_HeSub_46 MsgType = -100046
	MsgType_HTLC_SendVerifyR_45            MsgType = -100045
	MsgType_HTLC_VerifyR_45                MsgType = -45
	MsgType_HTLC_RecvVerifyR_45            MsgType = -110045
	MsgType_HTLC_SendHerdHex_46            MsgType = -46
	MsgType_HTLC_RecvSignVerifyR_46        MsgType = -110046

	MsgType_HTLC_Close_SendRequestCloseCurrTx_49       MsgType = -100049
	MsgType_HTLC_Close_ClientSign_Alice_C4a_110        MsgType = -100110
	MsgType_HTLC_Close_RequestCloseCurrTx_49           MsgType = -49
	MsgType_HTLC_Close_RecvRequestCloseCurrTx_49       MsgType = -110049
	MsgType_HTLC_Close_SendCloseSigned_50              MsgType = -100050
	MsgType_HTLC_Close_ClientSign_Bob_C4b_111          MsgType = -100111
	MsgType_HTLC_CloseHtlcRequestSignBR_50             MsgType = -50
	MsgType_HTLC_RecvCloseSigned_50                    MsgType = -110050
	MsgType_HTLC_Close_ClientSign_Alice_C4b_112        MsgType = -100112
	MsgType_HTLC_Close_ClientSign_Alice_C4bSub_113     MsgType = -100113
	MsgType_HTLC_CloseHtlcUpdateCnb_51                 MsgType = -51
	MsgType_HTLC_Close_ClientSign_Bob_C4bSub_51        MsgType = -110051
	MsgType_HTLC_Close_ClientSign_Bob_C4bSubResult_114 MsgType = -100114

	//https://github.com/LightningOnOmnilayer/Omni-BOLT-spec/blob/master/OmniBOLT-05-Atomic-Swap-among-Channels.md
	MsgType_Atomic_SendSwap_80       MsgType = -100080
	MsgType_Atomic_Swap_80           MsgType = -80
	MsgType_Atomic_RecvSwap_80       MsgType = -110080
	MsgType_Atomic_SendSwapAccept_81 MsgType = -100081
	MsgType_Atomic_SwapAccept_81     MsgType = -81
	MsgType_Atomic_RecvSwapAccept_81 MsgType = -110081
	//endregion
)

func CheckExist(msgType MsgType) bool {
	switch msgType {
	case MsgType_Error_0:
		return true
	case MsgType_UserLogin_2001:
		return true
	case MsgType_UserLogout_2002:
		return true
	case MsgType_p2p_ConnectPeer_2003:
		return true
	case MsgType_p2p_DisconnectPeer_2010:
		return true
	case MsgType_GetMnemonic_2004:
		return true
	case MsgType_GetObdNodeInfo_2005:
		return true
	case MsgType_GetMiniBtcFundAmount_2006:
		return true
	case MsgType_HeartBeat_2007:
		return true
	case MsgType_User_UpdateAdminToken_2008:
		return true
	case MsgType_User_GetInfo_2009:
		return true
	case MsgType_Core_GetNewAddress_2101:
		return true
	case MsgType_Core_GetMiningInfo_2102:
		return true
	case MsgType_Core_GetNetworkInfo_2103:
		return true
	case MsgType_Core_SignMessageWithPrivKey_2104:
		return true
	case MsgType_Core_VerifyMessage_2105:
		return true
	case MsgType_Core_DumpPrivKey_2106:
		return true
	case MsgType_Core_ListUnspent_2107:
		return true
	case MsgType_Core_BalanceByAddress_2108:
		return true
	case MsgType_Core_FundingBTC_2109:
		return true
	case MsgType_Core_BtcCreateMultiSig_2110:
		return true
	case MsgType_Core_Btc_ImportPrivKey_2111:
		return true
	case MsgType_Core_Omni_GetBalance_2112:
		return true
	case MsgType_Core_Omni_CreateNewTokenFixed_2113:
		return true
	case MsgType_Core_Omni_CreateNewTokenManaged_2114:
		return true
	case MsgType_Core_Omni_GrantNewUnitsOfManagedToken_2115:
		return true
	case MsgType_Core_Omni_RevokeUnitsOfManagedToken_2116:
		return true
	case MsgType_Core_Omni_ListProperties_2117:
		return true
	case MsgType_Core_Omni_GetTransaction_2118:
		return true
	case MsgType_Core_Omni_GetProperty_2119:
		return true
	case MsgType_Core_Omni_FundingAsset_2120:
		return true
	case MsgType_Core_Omni_Send_2121:
		return true
	case MsgType_Core_GetTransactionByTxid_2122:
		return true
	case MsgType_Core_SignRawTransaction_2123:
		return true
	case MsgType_Mnemonic_CreateAddress_3000:
		return true
	case MsgType_Mnemonic_GetAddressByIndex_3001:
		return true
	case MsgType_SendChannelOpen_32:
		return true
	case MsgType_ChannelOpen_AllItem_3150:
		return true
	case MsgType_ChannelOpen_ItemByTempId_3151:
		return true
	case MsgType_ChannelOpen_Count_3152:
		return true
	case MsgType_ChannelOpen_DelItemByTempId_3153:
		return true
	case MsgType_GetChannelInfoByChannelId_3154:
		return true
	case MsgType_GetChannelInfoByDbId_3155:
		return true
	case MsgType_CheckChannelAddessExist_3156:
		return true
	case MsgType_SendChannelAccept_33:
		return true
	case MsgType_Funding_134:
		return true
	case MsgType_FundingCreate_SendAssetFundingCreated_34:
		return true
	case MsgType_ClientSign_AssetFunding_AliceSignC1a_1034:
		return true
	case MsgType_ClientSign_AssetFunding_AliceSignRD_1134:
		return true
	case MsgType_FundingCreate_Asset_AllItem_3100:
		return true
	case MsgType_FundingCreate_Asset_ItemById_3101:
		return true
	case MsgType_FundingCreate_Asset_ItemByChannelId_3102:
		return true
	case MsgType_FundingCreate_Asset_Count_3103:
		return true
	case MsgType_FundingCreate_SendBtcFundingCreated_340:
		return true
	case MsgType_ClientSign_Duplex_BtcFundingMinerRDTx_341:
		return true
	case MsgType_FundingCreate_Btc_AllItem_3104:
		return true
	case MsgType_FundingCreate_Btc_ItemById_3105:
		return true
	case MsgType_FundingCreate_Btc_ItemByTempChannelId_3106:
		return true
	case MsgType_FundingCreate_Btc_RDAllItem_3107:
		return true
	case MsgType_FundingCreate_Btc_ItemRDById_3108:
		return true
	case MsgType_FundingCreate_Btc_ItemRDByTempChannelId_3109:
		return true
	case MsgType_FundingCreate_Btc_ItemRDByTempChannelIdAndTxId_3110:
		return true
	case MsgType_FundingCreate_Btc_ItemByChannelId_3111:
		return true
	case MsgType_FundingSign_SendAssetFundingSigned_35:
		return true
	case MsgType_ClientSign_AssetFunding_RdAndBr_1035:
		return true
	case MsgType_FundingSign_SendBtcSign_350:
		return true
	case MsgType_CommitmentTx_SendCommitmentTransactionCreated_351:
		return true
	case MsgType_ClientSign_CommitmentTx_AliceSignC2a_360:
		return true
	case MsgType_CommitmentTxSigned_SendRevokeAndAcknowledgeCommitmentTransaction_352:
		return true
	case MsgType_ClientSign_CommitmentTx_BobSignC2b_361:
		return true
	case MsgType_ClientSign_CommitmentTx_AliceSignC2b_362:
		return true
	case MsgType_ClientSign_CommitmentTx_AliceSignC2b_Rd_363:
		return true
	case MsgType_ClientSign_CommitmentTx_BobSignC2b_Rd_364:
		return true
	case MsgType_CommitmentTx_ItemsByChanId_3200:
		return true
	case MsgType_CommitmentTx_DelItemByChanId_3209:
		return true
	case MsgType_CommitmentTx_ItemById_3201:
		return true
	case MsgType_CommitmentTx_Count_3202:
		return true
	case MsgType_CommitmentTx_LatestCommitmentTxByChanId_3203:
		return true
	case MsgType_CommitmentTx_LatestRDByChanId_3204:
		return true
	case MsgType_CommitmentTx_LatestBRByChanId_3205:
		return true
	case MsgType_CommitmentTx_SendSomeCommitmentById_3206:
		return true
	case MsgType_CommitmentTx_AllRDByChanId_3207:
		return true
	case MsgType_CommitmentTx_AllBRByChanId_3208:
		return true
	case MsgType_Htlc_GetLatestHT1aOrHE1b_3250:
		return true
	case MsgType_Htlc_GetHT1aOrHE1bBySomeCommitmentId_3251:
		return true
	case MsgType_SendCloseChannelRequest_38:
		return true
	case MsgType_SendCloseChannelSign_39:
		return true
	case MsgType_HTLC_FindPath_401:
		return true
	case MsgType_HTLC_Invoice_402:
		return true
	case MsgType_HTLC_ParseInvoice_403:
		return true
	case MsgType_HTLC_SendAddHTLC_40:
		return true
	case MsgType_HTLC_ClientSign_Alice_C3a_100:
		return true
	case MsgType_HTLC_ClientSign_Bob_C3b_101:
		return true
	case MsgType_HTLC_ClientSign_Alice_C3b_102:
		return true
	case MsgType_HTLC_ClientSign_Alice_C3bSub_103:
		return true
	case MsgType_HTLC_ClientSign_Bob_C3bSub_104:
		return true
	case MsgType_HTLC_ClientSign_Alice_He_105:
		return true
	case MsgType_HTLC_ClientSign_Bob_HeSub_106:
		return true
	case MsgType_HTLC_ClientSign_Alice_HeSub_46:
		return true
	case MsgType_HTLC_SendAddHTLCSigned_41:
		return true
	case MsgType_HTLC_SendVerifyR_45:
		return true
	case MsgType_HTLC_Close_SendRequestCloseCurrTx_49:
		return true
	case MsgType_HTLC_Close_ClientSign_Alice_C4a_110:
		return true
	case MsgType_HTLC_Close_ClientSign_Bob_C4b_111:
		return true
	case MsgType_HTLC_Close_ClientSign_Alice_C4b_112:
		return true
	case MsgType_HTLC_Close_ClientSign_Alice_C4bSub_113:
		return true
	case MsgType_HTLC_Close_ClientSign_Bob_C4bSubResult_114:
		return true
	case MsgType_HTLC_Close_SendCloseSigned_50:
		return true
	case MsgType_Atomic_SendSwap_80:
		return true
	case MsgType_Atomic_SendSwapAccept_81:
		return true
	}
	return false
}


<|start_filename|>tracker/dao/pojo.go<|end_filename|>
package dao

import (
	cbean "github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/tracker/bean"
	"time"
)

//ObdNodeInfo
type ObdNodeInfo struct {
	Id              int       `storm:"id,increment" json:"id"`
	IsOnline        bool      `json:"is_online"`
	LatestLoginIp   string    `json:"latest_login_ip"`
	LatestLoginAt   time.Time `json:"latest_login_at"`
	LatestOfflineAt time.Time `json:"latest_offline_at"`
	cbean.ObdNodeLoginRequest
}

//ObdNodeLoginLog
type ObdNodeLoginLog struct {
	Id        int       `storm:"id,increment" json:"id"`
	ObdId     string    `json:"obd_id"`
	LoginIp   string    `json:"login_ip"`
	LoginTime time.Time `json:"login_time"`
}

type UserInfo struct {
	Id           int       `storm:"id,increment" json:"id"`
	ObdP2pNodeId string    `json:"obd_p2p_node_id"`
	ObdNodeId    string    `json:"obd_node_id"`
	IsOnline     bool      `json:"is_online"`
	OfflineAt    time.Time `json:"offline_at"`
	cbean.ObdNodeUserLoginRequest
}
type ChannelInfo struct {
	Id           int                `storm:"id,increment" json:"id"`
	ObdNodeIdA   string             `json:"obd_node_ida"`
	ObdNodeIdB   string             `json:"obd_node_idb"`
	ChannelId    string             `json:"channel_id"`
	PropertyId   int64              `json:"property_id"`
	CurrState    cbean.ChannelState `json:"curr_state"`
	PeerIdA      string             `json:"peer_ida"`
	PeerIdB      string             `json:"peer_idb"`
	AmountA      float64            `json:"amount_a"`
	AmountB      float64            `json:"amount_b"`
	LatestEditAt time.Time          `json:"latest_edit_at"`
	CreateAt     time.Time          `json:"create_at"`
}

type HtlcTxInfo struct {
	Id       int       `storm:"id,increment" json:"id"`
	CreateAt time.Time `json:"create_at"`
	bean.UpdateHtlcTxStateRequest
}

type LockHtlcPath struct {
	Id        int       `storm:"id,increment" json:"id"`
	Path      []string  `json:"path"`
	CurrState int       `json:"curr_state"` // 0 创建，1，标记作废，2 标记通知完成
	CreateAt  time.Time `json:"create_at"`
}


<|start_filename|>proxy/rpc/wallet.go<|end_filename|>
package rpc

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/gorilla/websocket"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/lightclient"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/proxy/pb"
	"github.com/omnilaboratory/obd/service"
	"log"
	"strings"
)

var connObd *websocket.Conn
var currUserInfo *pb.LoginResponse

func checkLogin() (user *bean.User, err error) {
	if obcClient.User == nil {
		return nil, errors.New("please login")
	}
	return obcClient.User, nil
}

func checkTargetUserIsOnline(requestMessage bean.RequestMessage) (err error) {
	_, err = lightclient.FindUserOnLine(requestMessage)
	if err != nil {
		return err
	}
	if lightclient.P2pChannelMap[requestMessage.RecipientNodePeerId] == nil {
		err = lightclient.ScanAndConnNode(requestMessage.RecipientNodePeerId)
		if err != nil {
			return err
		}
	}
	return nil
}

func (server *RpcServer) GenSeed(ctx context.Context, in *pb.GenSeedRequest) (resp *pb.GenSeedResponse, err error) {
	log.Println("GenSeed")

	requestMessage := bean.RequestMessage{
		Type:             enum.MsgType_GetMnemonic_2004,
		SenderNodePeerId: obcClient.User.P2PLocalPeerId,
		SenderUserPeerId: obcClient.User.PeerId,
	}
	_, dataBytes, status := obcClient.HdWalletModule(requestMessage)
	data := string(dataBytes)
	if status == false {
		return nil, errors.New(data)
	}
	resp = &pb.GenSeedResponse{
		CipherSeedMnemonic: data,
	}
	return resp, nil
}

func (server *RpcServer) Login(ctx context.Context, in *pb.LoginRequest) (resp *pb.LoginResponse, err error) {

	log.Println("Login")

	if obcClient.User != nil {
		if obcClient.User.Mnemonic != in.Mnemonic {
			return nil, errors.New("user '" + in.Mnemonic + "' is online")
		}
	}

	if len(in.LoginToken) < 6 {
		return nil, errors.New("wrong login_token")
	}
	info := loginInfo{Mnemonic: in.Mnemonic, LoginToken: in.LoginToken}

	infoBytes, _ := json.Marshal(info)
	requestMessage := bean.RequestMessage{
		Type: enum.MsgType_UserLogin_2001,
		Data: string(infoBytes),
	}
	_, dataBytes, status := obcClient.UserModule(requestMessage)
	data := string(dataBytes)
	if status == false {
		return nil, errors.New(data)
	}

	dataMap := make(map[string]interface{})
	_ = json.Unmarshal(dataBytes, &dataMap)
	resp = &pb.LoginResponse{
		UserPeerId:    dataMap["userPeerId"].(string),
		NodePeerId:    dataMap["nodePeerId"].(string),
		NodeAddress:   dataMap["nodeAddress"].(string),
		HtlcFeeRate:   dataMap["htlcFeeRate"].(float64),
		HtlcMaxFee:    dataMap["htlcMaxFee"].(float64),
		ChainNodeType: dataMap["chainNodeType"].(string),
	}
	currUserInfo = resp
	return resp, nil
}

func (server *RpcServer) GetInfo(ctx context.Context, in *pb.GetInfoRequest) (resp *pb.GetInfoResponse, err error) {
	requestMessage := bean.RequestMessage{
		Type: enum.MsgType_User_GetInfo_2009,
	}
	_, dataBytes, status := obcClient.UserModule(requestMessage)
	if status == false {
		return nil, errors.New(string(dataBytes))
	}

	dataMap := make(map[string]interface{})
	_ = json.Unmarshal(dataBytes, &dataMap)
	resp = &pb.GetInfoResponse{
		UserPeerId:    dataMap["userPeerId"].(string),
		NodePeerId:    dataMap["nodePeerId"].(string),
		NodeAddress:   dataMap["nodeAddress"].(string),
		HtlcFeeRate:   dataMap["htlcFeeRate"].(float64),
		HtlcMaxFee:    dataMap["htlcMaxFee"].(float64),
		ChainNodeType: dataMap["chainNodeType"].(string),
	}
	resp.IsAdmin = true
	return resp, nil
}
func (server *RpcServer) NextAddr(ctx context.Context, in *pb.AddrRequest) (resp *pb.AddrResponse, err error) {
	log.Println("NextAddr")

	user, err := checkLogin()
	if err != nil {
		return nil, err
	}

	address, err := service.HDWalletService.CreateNewAddress(user)
	if err != nil {
		return nil, err
	}
	resp = &pb.AddrResponse{
		Index:  int64(address.Index),
		Addr:   address.Address,
		PubKey: address.PubKey,
		Wif:    address.Wif,
	}
	return resp, nil
}

func (server *RpcServer) GetAddressInfo(ctx context.Context, in *pb.GetAddressInfoRequest) (resp *pb.AddrResponse, err error) {
	log.Println("GetAddressInfo")

	if in.Addr == "" {
		return nil, errors.New("empty addr")
	}

	user, err := checkLogin()
	if err != nil {
		return nil, err
	}

	for i := 0; i < obcClient.User.CurrAddrIndex; i++ {
		wallet, _ := service.HDWalletService.GetAddressByIndex(user, uint32(i))
		if wallet.Address == in.GetAddr() {
			resp = &pb.AddrResponse{
				Index:  int64(wallet.Index),
				Addr:   wallet.Address,
				PubKey: wallet.PubKey,
				Wif:    wallet.Wif,
			}
			break
		}
	}
	if resp == nil {
		return nil, errors.New("not found")
	}
	return resp, nil
}
func (server *RpcServer) NewAddress(ctx context.Context, in *pb.NewAddressRequest) (resp *pb.NewAddressResponse, err error) {
	log.Println("NextAddr")

	user, err := checkLogin()
	if err != nil {
		return nil, err
	}

	address, err := service.HDWalletService.CreateNewAddress(user)
	if err != nil {
		return nil, err
	}
	resp = &pb.NewAddressResponse{
		Index:  int64(address.Index),
		Addr:   address.Address,
		PubKey: address.PubKey,
		Wif:    address.Wif,
	}
	return resp, nil
}

func (server *RpcServer) EstimateFee(ctx context.Context, in *pb.EstimateFeeRequest) (resp *pb.EstimateFeeResponse, err error) {
	log.Println("EstimateFee")
	minerFee := omnicore.GetMinerFee(in.ConfTarget)
	resp = &pb.EstimateFeeResponse{
		SatPerKw: int64(100000000 * minerFee),
	}
	return resp, nil
}

func (server *RpcServer) Logout(ctx context.Context, in *pb.LogoutRequest) (resp *pb.LogoutResponse, err error) {
	log.Println("Logout")

	_, err = checkLogin()
	if err != nil {
		return nil, err
	}

	requestMessage := bean.RequestMessage{
		Type:             enum.MsgType_UserLogout_2002,
		SenderNodePeerId: obcClient.User.P2PLocalPeerId,
		SenderUserPeerId: obcClient.User.PeerId,
	}
	_, dataBytes, status := obcClient.UserModule(requestMessage)
	data := string(dataBytes)
	if status == false {
		return nil, errors.New(data)
	}
	return &pb.LogoutResponse{}, nil
}

func (server *RpcServer) ChangePassword(ctx context.Context, in *pb.ChangePasswordRequest) (resp *pb.ChangePasswordResponse, err error) {
	log.Println("ChangePassword")

	_, err = checkLogin()
	if err != nil {
		return nil, err
	}
	if len(in.CurrentPassword) < 6 {
		return nil, errors.New("wrong current_password")
	}

	in.NewPassword = strings.TrimLeft(in.NewPassword, " ")
	in.NewPassword = strings.TrimRight(in.NewPassword, " ")
	if len(in.NewPassword) < 6 {
		return nil, errors.New("wrong new_password")
	}

	token := updateLoginToken{CurrentPassword: <PASSWORD>, NewPassword: <PASSWORD>}
	infoBytes, _ := json.Marshal(token)
	requestMessage := bean.RequestMessage{
		Type:             enum.MsgType_User_UpdateAdminToken_2008,
		SenderNodePeerId: obcClient.User.P2PLocalPeerId,
		SenderUserPeerId: obcClient.User.PeerId,
		Data:             string(infoBytes)}
	_, dataBytes, status := obcClient.UserModule(requestMessage)
	data := string(dataBytes)
	if status == false {
		return nil, errors.New(data)
	}

	resp = &pb.ChangePasswordResponse{
		Result: data,
	}
	return resp, nil
}
func (server *RpcServer) ListPeers(ctx context.Context, in *pb.ListPeersRequest) (resp *pb.ListPeersResponse, err error) {
	log.Println("ListPeers")

	_, err = checkLogin()
	if err != nil {
		return nil, err
	}

	resp = &pb.ListPeersResponse{}
	for key, value := range lightclient.P2pChannelMap {
		if key != lightclient.P2PLocalNodeId {
			peer := &pb.Peer{Address: value.Address, PubKey: key}
			resp.Peers = append(resp.Peers, peer)
		}
	}
	return resp, nil
}


<|start_filename|>proxy/pb/htlc.pb.go<|end_filename|>
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: htlc.proto

package pb

import (
	context "context"
	fmt "fmt"
	proto "github.com/golang/protobuf/proto"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
	math "math"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

type Invoice struct {
	PropertyId           int64    `protobuf:"varint,1,opt,name=property_id,json=propertyId,proto3" json:"property_id,omitempty"`
	Value                float64  `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"`
	Memo                 string   `protobuf:"bytes,3,opt,name=memo,proto3" json:"memo,omitempty"`
	CltvExpiry           string   `protobuf:"bytes,4,opt,name=cltv_expiry,json=cltvExpiry,proto3" json:"cltv_expiry,omitempty"`
	Private              bool     `protobuf:"varint,5,opt,name=private,proto3" json:"private,omitempty"`
	PaymentRequest       string   `protobuf:"bytes,6,opt,name=payment_request,json=paymentRequest,proto3" json:"payment_request,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *Invoice) Reset()         { *m = Invoice{} }
func (m *Invoice) String() string { return proto.CompactTextString(m) }
func (*Invoice) ProtoMessage()    {}
func (*Invoice) Descriptor() ([]byte, []int) {
	return fileDescriptor_ba4445548e82dcd3, []int{0}
}

func (m *Invoice) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_Invoice.Unmarshal(m, b)
}
func (m *Invoice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_Invoice.Marshal(b, m, deterministic)
}
func (m *Invoice) XXX_Merge(src proto.Message) {
	xxx_messageInfo_Invoice.Merge(m, src)
}
func (m *Invoice) XXX_Size() int {
	return xxx_messageInfo_Invoice.Size(m)
}
func (m *Invoice) XXX_DiscardUnknown() {
	xxx_messageInfo_Invoice.DiscardUnknown(m)
}

var xxx_messageInfo_Invoice proto.InternalMessageInfo

func (m *Invoice) GetPropertyId() int64 {
	if m != nil {
		return m.PropertyId
	}
	return 0
}

func (m *Invoice) GetValue() float64 {
	if m != nil {
		return m.Value
	}
	return 0
}

func (m *Invoice) GetMemo() string {
	if m != nil {
		return m.Memo
	}
	return ""
}

func (m *Invoice) GetCltvExpiry() string {
	if m != nil {
		return m.CltvExpiry
	}
	return ""
}

func (m *Invoice) GetPrivate() bool {
	if m != nil {
		return m.Private
	}
	return false
}

func (m *Invoice) GetPaymentRequest() string {
	if m != nil {
		return m.PaymentRequest
	}
	return ""
}

type AddInvoiceResponse struct {
	PaymentRequest       string   `protobuf:"bytes,1,opt,name=payment_request,json=paymentRequest,proto3" json:"payment_request,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *AddInvoiceResponse) Reset()         { *m = AddInvoiceResponse{} }
func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*AddInvoiceResponse) ProtoMessage()    {}
func (*AddInvoiceResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_ba4445548e82dcd3, []int{1}
}

func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_AddInvoiceResponse.Unmarshal(m, b)
}
func (m *AddInvoiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_AddInvoiceResponse.Marshal(b, m, deterministic)
}
func (m *AddInvoiceResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_AddInvoiceResponse.Merge(m, src)
}
func (m *AddInvoiceResponse) XXX_Size() int {
	return xxx_messageInfo_AddInvoiceResponse.Size(m)
}
func (m *AddInvoiceResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_AddInvoiceResponse.DiscardUnknown(m)
}

var xxx_messageInfo_AddInvoiceResponse proto.InternalMessageInfo

func (m *AddInvoiceResponse) GetPaymentRequest() string {
	if m != nil {
		return m.PaymentRequest
	}
	return ""
}

type ParseInvoiceRequest struct {
	PaymentRequest       string   `protobuf:"bytes,1,opt,name=payment_request,json=paymentRequest,proto3" json:"payment_request,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ParseInvoiceRequest) Reset()         { *m = ParseInvoiceRequest{} }
func (m *ParseInvoiceRequest) String() string { return proto.CompactTextString(m) }
func (*ParseInvoiceRequest) ProtoMessage()    {}
func (*ParseInvoiceRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_ba4445548e82dcd3, []int{2}
}

func (m *ParseInvoiceRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ParseInvoiceRequest.Unmarshal(m, b)
}
func (m *ParseInvoiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ParseInvoiceRequest.Marshal(b, m, deterministic)
}
func (m *ParseInvoiceRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ParseInvoiceRequest.Merge(m, src)
}
func (m *ParseInvoiceRequest) XXX_Size() int {
	return xxx_messageInfo_ParseInvoiceRequest.Size(m)
}
func (m *ParseInvoiceRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ParseInvoiceRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ParseInvoiceRequest proto.InternalMessageInfo

func (m *ParseInvoiceRequest) GetPaymentRequest() string {
	if m != nil {
		return m.PaymentRequest
	}
	return ""
}

type ParseInvoiceResponse struct {
	PropertyId           int64    `protobuf:"varint,1,opt,name=property_id,json=propertyId,proto3" json:"property_id,omitempty"`
	Value                float64  `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"`
	Memo                 string   `protobuf:"bytes,3,opt,name=memo,proto3" json:"memo,omitempty"`
	CltvExpiry           string   `protobuf:"bytes,4,opt,name=cltv_expiry,json=cltvExpiry,proto3" json:"cltv_expiry,omitempty"`
	Private              bool     `protobuf:"varint,5,opt,name=private,proto3" json:"private,omitempty"`
	H                    string   `protobuf:"bytes,6,opt,name=h,proto3" json:"h,omitempty"`
	RecipientNodePeerId  string   `protobuf:"bytes,7,opt,name=recipient_node_peer_id,json=recipientNodePeerId,proto3" json:"recipient_node_peer_id,omitempty"`
	RecipientUserPeerId  string   `protobuf:"bytes,8,opt,name=recipient_user_peer_id,json=recipientUserPeerId,proto3" json:"recipient_user_peer_id,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ParseInvoiceResponse) Reset()         { *m = ParseInvoiceResponse{} }
func (m *ParseInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*ParseInvoiceResponse) ProtoMessage()    {}
func (*ParseInvoiceResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_ba4445548e82dcd3, []int{3}
}

func (m *ParseInvoiceResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ParseInvoiceResponse.Unmarshal(m, b)
}
func (m *ParseInvoiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ParseInvoiceResponse.Marshal(b, m, deterministic)
}
func (m *ParseInvoiceResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ParseInvoiceResponse.Merge(m, src)
}
func (m *ParseInvoiceResponse) XXX_Size() int {
	return xxx_messageInfo_ParseInvoiceResponse.Size(m)
}
func (m *ParseInvoiceResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_ParseInvoiceResponse.DiscardUnknown(m)
}

var xxx_messageInfo_ParseInvoiceResponse proto.InternalMessageInfo

func (m *ParseInvoiceResponse) GetPropertyId() int64 {
	if m != nil {
		return m.PropertyId
	}
	return 0
}

func (m *ParseInvoiceResponse) GetValue() float64 {
	if m != nil {
		return m.Value
	}
	return 0
}

func (m *ParseInvoiceResponse) GetMemo() string {
	if m != nil {
		return m.Memo
	}
	return ""
}

func (m *ParseInvoiceResponse) GetCltvExpiry() string {
	if m != nil {
		return m.CltvExpiry
	}
	return ""
}

func (m *ParseInvoiceResponse) GetPrivate() bool {
	if m != nil {
		return m.Private
	}
	return false
}

func (m *ParseInvoiceResponse) GetH() string {
	if m != nil {
		return m.H
	}
	return ""
}

func (m *ParseInvoiceResponse) GetRecipientNodePeerId() string {
	if m != nil {
		return m.RecipientNodePeerId
	}
	return ""
}

func (m *ParseInvoiceResponse) GetRecipientUserPeerId() string {
	if m != nil {
		return m.RecipientUserPeerId
	}
	return ""
}

type SendRequest struct {
	PaymentRequest       string                `protobuf:"bytes,1,opt,name=payment_request,json=paymentRequest,proto3" json:"payment_request,omitempty"`
	InvoiceDetail        *ParseInvoiceResponse `protobuf:"bytes,2,opt,name=invoice_detail,json=invoiceDetail,proto3" json:"invoice_detail,omitempty"`
	XXX_NoUnkeyedLiteral struct{}              `json:"-"`
	XXX_unrecognized     []byte                `json:"-"`
	XXX_sizecache        int32                 `json:"-"`
}

func (m *SendRequest) Reset()         { *m = SendRequest{} }
func (m *SendRequest) String() string { return proto.CompactTextString(m) }
func (*SendRequest) ProtoMessage()    {}
func (*SendRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_ba4445548e82dcd3, []int{4}
}

func (m *SendRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_SendRequest.Unmarshal(m, b)
}
func (m *SendRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_SendRequest.Marshal(b, m, deterministic)
}
func (m *SendRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_SendRequest.Merge(m, src)
}
func (m *SendRequest) XXX_Size() int {
	return xxx_messageInfo_SendRequest.Size(m)
}
func (m *SendRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_SendRequest.DiscardUnknown(m)
}

var xxx_messageInfo_SendRequest proto.InternalMessageInfo

func (m *SendRequest) GetPaymentRequest() string {
	if m != nil {
		return m.PaymentRequest
	}
	return ""
}

func (m *SendRequest) GetInvoiceDetail() *ParseInvoiceResponse {
	if m != nil {
		return m.InvoiceDetail
	}
	return nil
}

type SendResponse struct {
	PaymentHash          string   `protobuf:"bytes,1,opt,name=payment_hash,json=paymentHash,proto3" json:"payment_hash,omitempty"`
	PaymentPreimage      string   `protobuf:"bytes,2,opt,name=payment_preimage,json=paymentPreimage,proto3" json:"payment_preimage,omitempty"`
	AmountToRsmc         float64  `protobuf:"fixed64,3,opt,name=amount_to_rsmc,json=amountToRsmc,proto3" json:"amount_to_rsmc,omitempty"`
	AmountToHtlc         float64  `protobuf:"fixed64,4,opt,name=amount_to_htlc,json=amountToHtlc,proto3" json:"amount_to_htlc,omitempty"`
	AmountToCounterparty float64  `protobuf:"fixed64,5,opt,name=amount_to_counterparty,json=amountToCounterparty,proto3" json:"amount_to_counterparty,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *SendResponse) Reset()         { *m = SendResponse{} }
func (m *SendResponse) String() string { return proto.CompactTextString(m) }
func (*SendResponse) ProtoMessage()    {}
func (*SendResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_ba4445548e82dcd3, []int{5}
}

func (m *SendResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_SendResponse.Unmarshal(m, b)
}
func (m *SendResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_SendResponse.Marshal(b, m, deterministic)
}
func (m *SendResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_SendResponse.Merge(m, src)
}
func (m *SendResponse) XXX_Size() int {
	return xxx_messageInfo_SendResponse.Size(m)
}
func (m *SendResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_SendResponse.DiscardUnknown(m)
}

var xxx_messageInfo_SendResponse proto.InternalMessageInfo

func (m *SendResponse) GetPaymentHash() string {
	if m != nil {
		return m.PaymentHash
	}
	return ""
}

func (m *SendResponse) GetPaymentPreimage() string {
	if m != nil {
		return m.PaymentPreimage
	}
	return ""
}

func (m *SendResponse) GetAmountToRsmc() float64 {
	if m != nil {
		return m.AmountToRsmc
	}
	return 0
}

func (m *SendResponse) GetAmountToHtlc() float64 {
	if m != nil {
		return m.AmountToHtlc
	}
	return 0
}

func (m *SendResponse) GetAmountToCounterparty() float64 {
	if m != nil {
		return m.AmountToCounterparty
	}
	return 0
}

type ListInvoiceRequest struct {
	//
	//The index of an invoice that will be used as either the start or end of a
	//query to determine which invoices should be returned in the response.
	IndexOffset uint64 `protobuf:"varint,1,opt,name=index_offset,json=indexOffset,proto3" json:"index_offset,omitempty"`
	// The max number of invoices to return in the response to this query.
	NumMaxInvoices uint64 `protobuf:"varint,2,opt,name=num_max_invoices,json=numMaxInvoices,proto3" json:"num_max_invoices,omitempty"`
	//
	//If set, the invoices returned will result from seeking backwards from the
	//specified index offset. This can be used to paginate backwards.
	Reversed             bool     `protobuf:"varint,3,opt,name=reversed,proto3" json:"reversed,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ListInvoiceRequest) Reset()         { *m = ListInvoiceRequest{} }
func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) }
func (*ListInvoiceRequest) ProtoMessage()    {}
func (*ListInvoiceRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_ba4445548e82dcd3, []int{6}
}

func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ListInvoiceRequest.Unmarshal(m, b)
}
func (m *ListInvoiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ListInvoiceRequest.Marshal(b, m, deterministic)
}
func (m *ListInvoiceRequest) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ListInvoiceRequest.Merge(m, src)
}
func (m *ListInvoiceRequest) XXX_Size() int {
	return xxx_messageInfo_ListInvoiceRequest.Size(m)
}
func (m *ListInvoiceRequest) XXX_DiscardUnknown() {
	xxx_messageInfo_ListInvoiceRequest.DiscardUnknown(m)
}

var xxx_messageInfo_ListInvoiceRequest proto.InternalMessageInfo

func (m *ListInvoiceRequest) GetIndexOffset() uint64 {
	if m != nil {
		return m.IndexOffset
	}
	return 0
}

func (m *ListInvoiceRequest) GetNumMaxInvoices() uint64 {
	if m != nil {
		return m.NumMaxInvoices
	}
	return 0
}

func (m *ListInvoiceRequest) GetReversed() bool {
	if m != nil {
		return m.Reversed
	}
	return false
}

type ListInvoiceResponse struct {
	//
	//A list of invoices from the time slice of the time series specified in the
	//request.
	Invoices []*Invoice `protobuf:"bytes,1,rep,name=invoices,proto3" json:"invoices,omitempty"`
	//
	//The index of the last item in the set of returned invoices. This can be used
	//to seek further, pagination style.
	LastIndexOffset uint64 `protobuf:"varint,2,opt,name=last_index_offset,json=lastIndexOffset,proto3" json:"last_index_offset,omitempty"`
	//
	//The index of the last item in the set of returned invoices. This can be used
	//to seek backwards, pagination style.
	FirstIndexOffset     uint64   `protobuf:"varint,3,opt,name=first_index_offset,json=firstIndexOffset,proto3" json:"first_index_offset,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (m *ListInvoiceResponse) Reset()         { *m = ListInvoiceResponse{} }
func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*ListInvoiceResponse) ProtoMessage()    {}
func (*ListInvoiceResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_ba4445548e82dcd3, []int{7}
}

func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error {
	return xxx_messageInfo_ListInvoiceResponse.Unmarshal(m, b)
}
func (m *ListInvoiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
	return xxx_messageInfo_ListInvoiceResponse.Marshal(b, m, deterministic)
}
func (m *ListInvoiceResponse) XXX_Merge(src proto.Message) {
	xxx_messageInfo_ListInvoiceResponse.Merge(m, src)
}
func (m *ListInvoiceResponse) XXX_Size() int {
	return xxx_messageInfo_ListInvoiceResponse.Size(m)
}
func (m *ListInvoiceResponse) XXX_DiscardUnknown() {
	xxx_messageInfo_ListInvoiceResponse.DiscardUnknown(m)
}

var xxx_messageInfo_ListInvoiceResponse proto.InternalMessageInfo

func (m *ListInvoiceResponse) GetInvoices() []*Invoice {
	if m != nil {
		return m.Invoices
	}
	return nil
}

func (m *ListInvoiceResponse) GetLastIndexOffset() uint64 {
	if m != nil {
		return m.LastIndexOffset
	}
	return 0
}

func (m *ListInvoiceResponse) GetFirstIndexOffset() uint64 {
	if m != nil {
		return m.FirstIndexOffset
	}
	return 0
}

func init() {
	proto.RegisterType((*Invoice)(nil), "proxy.Invoice")
	proto.RegisterType((*AddInvoiceResponse)(nil), "proxy.AddInvoiceResponse")
	proto.RegisterType((*ParseInvoiceRequest)(nil), "proxy.ParseInvoiceRequest")
	proto.RegisterType((*ParseInvoiceResponse)(nil), "proxy.ParseInvoiceResponse")
	proto.RegisterType((*SendRequest)(nil), "proxy.SendRequest")
	proto.RegisterType((*SendResponse)(nil), "proxy.SendResponse")
	proto.RegisterType((*ListInvoiceRequest)(nil), "proxy.ListInvoiceRequest")
	proto.RegisterType((*ListInvoiceResponse)(nil), "proxy.ListInvoiceResponse")
}

func init() {
	proto.RegisterFile("htlc.proto", fileDescriptor_ba4445548e82dcd3)
}

var fileDescriptor_ba4445548e82dcd3 = []byte{
	// 638 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0xcf, 0x6e, 0xd3, 0x4e,
	0x10, 0xd6, 0x26, 0x69, 0x9b, 0x4e, 0xfc, 0x4b, 0xfb, 0xdb, 0x54, 0x95, 0x31, 0x07, 0xd2, 0x08,
	0x89, 0x50, 0xa1, 0x1e, 0x5a, 0x04, 0x27, 0x90, 0x28, 0x54, 0x34, 0x12, 0x7f, 0xa2, 0x05, 0x2e,
	0x5c, 0xac, 0xad, 0x3d, 0x21, 0x96, 0x62, 0xef, 0xb2, 0xbb, 0x89, 0x12, 0x24, 0xce, 0xbc, 0x00,
	0x37, 0x5e, 0x84, 0xa7, 0xe1, 0x59, 0x90, 0xd7, 0xeb, 0xd4, 0x09, 0x11, 0x82, 0x1b, 0x37, 0xef,
	0x37, 0xdf, 0x37, 0x33, 0xfe, 0x66, 0x76, 0x01, 0xc6, 0x66, 0x12, 0x9d, 0x48, 0x25, 0x8c, 0xa0,
	0x5b, 0x52, 0x89, 0xf9, 0xa2, 0xf7, 0x9d, 0xc0, 0xce, 0x20, 0x9b, 0x89, 0x24, 0x42, 0x7a, 0x0b,
	0x5a, 0x52, 0x09, 0x89, 0xca, 0x2c, 0xc2, 0x24, 0xf6, 0x49, 0x97, 0xf4, 0xeb, 0x0c, 0x4a, 0x68,
	0x10, 0xd3, 0x03, 0xd8, 0x9a, 0xf1, 0xc9, 0x14, 0xfd, 0x5a, 0x97, 0xf4, 0x09, 0x2b, 0x0e, 0x94,
	0x42, 0x23, 0xc5, 0x54, 0xf8, 0xf5, 0x2e, 0xe9, 0xef, 0x32, 0xfb, 0x9d, 0xa7, 0x8a, 0x26, 0x66,
	0x16, 0xe2, 0x5c, 0x26, 0x6a, 0xe1, 0x37, 0x6c, 0x08, 0x72, 0xe8, 0xc2, 0x22, 0xd4, 0x87, 0x1d,
	0xa9, 0x92, 0x19, 0x37, 0xe8, 0x6f, 0x75, 0x49, 0xbf, 0xc9, 0xca, 0x23, 0xbd, 0x03, 0x7b, 0x92,
	0x2f, 0x52, 0xcc, 0x4c, 0xa8, 0xf0, 0xe3, 0x14, 0xb5, 0xf1, 0xb7, 0xad, 0xbc, 0xed, 0x60, 0x56,
	0xa0, 0xbd, 0x47, 0x40, 0x9f, 0xc4, 0xb1, 0x6b, 0x9e, 0xa1, 0x96, 0x22, 0xd3, 0x1b, 0xe5, 0x64,
	0xa3, 0xfc, 0x31, 0x74, 0x86, 0x5c, 0x69, 0x5c, 0x26, 0xb0, 0xf0, 0x9f, 0xeb, 0xbf, 0xd6, 0xe0,
	0x60, 0x35, 0x81, 0xeb, 0xe0, 0xdf, 0xb0, 0xd1, 0x03, 0x32, 0x76, 0xc6, 0x91, 0x31, 0x3d, 0x83,
	0x43, 0x85, 0x51, 0x22, 0x93, 0xfc, 0xbf, 0x32, 0x11, 0x63, 0x28, 0x11, 0x55, 0xde, 0xde, 0x8e,
	0xa5, 0x74, 0x96, 0xd1, 0x57, 0x22, 0xc6, 0x21, 0xa2, 0x1a, 0xc4, 0xab, 0xa2, 0xa9, 0x46, 0xb5,
	0x14, 0x35, 0xd7, 0x44, 0xef, 0x34, 0xaa, 0x42, 0xd4, 0xfb, 0x04, 0xad, 0x37, 0x98, 0xc5, 0x7f,
	0x6b, 0x27, 0x3d, 0x87, 0x76, 0x52, 0x18, 0x19, 0xc6, 0x68, 0x78, 0x32, 0xb1, 0xee, 0xb4, 0x4e,
	0x6f, 0x9e, 0xd8, 0x45, 0x3d, 0xd9, 0x64, 0x35, 0xfb, 0xcf, 0x49, 0x9e, 0x59, 0x45, 0xef, 0x07,
	0x01, 0xaf, 0x28, 0xee, 0x46, 0x71, 0x04, 0x5e, 0x59, 0x7d, 0xcc, 0xf5, 0xd8, 0x95, 0x6e, 0x39,
	0xec, 0x92, 0xeb, 0x31, 0xbd, 0x0b, 0xfb, 0x25, 0x45, 0x2a, 0x4c, 0x52, 0xfe, 0xa1, 0x98, 0xcb,
	0x2e, 0x2b, 0x1b, 0x1f, 0x3a, 0x98, 0xde, 0x86, 0x36, 0x4f, 0xc5, 0x34, 0x33, 0xa1, 0x11, 0xa1,
	0xd2, 0x69, 0x64, 0x67, 0x45, 0x98, 0x57, 0xa0, 0x6f, 0x05, 0xd3, 0x69, 0xb4, 0xca, 0xca, 0x2f,
	0x9c, 0x1d, 0x5b, 0x85, 0x75, 0x69, 0x26, 0x11, 0xbd, 0x0f, 0x87, 0xd7, 0xac, 0x28, 0xff, 0x40,
	0x25, 0xb9, 0x32, 0x0b, 0x3b, 0x47, 0xc2, 0x0e, 0x4a, 0xf6, 0xd3, 0x4a, 0xac, 0xf7, 0x19, 0xe8,
	0x8b, 0x44, 0x9b, 0xb5, 0x95, 0x3d, 0x02, 0x2f, 0xc9, 0x62, 0x9c, 0x87, 0x62, 0x34, 0xd2, 0x58,
	0x18, 0xdc, 0x60, 0x2d, 0x8b, 0xbd, 0xb6, 0x10, 0xed, 0xc3, 0x7e, 0x36, 0x4d, 0xc3, 0x94, 0xcf,
	0x43, 0x67, 0x99, 0xb6, 0x7f, 0xd9, 0x60, 0xed, 0x6c, 0x9a, 0xbe, 0xe4, 0x73, 0x97, 0x52, 0xd3,
	0x00, 0x9a, 0x0a, 0x67, 0xa8, 0x34, 0xc6, 0xf6, 0xf7, 0x9a, 0x6c, 0x79, 0xee, 0x7d, 0x23, 0xd0,
	0x59, 0xa9, 0xef, 0x6c, 0x3e, 0x86, 0xe6, 0x32, 0x2b, 0xe9, 0xd6, 0xfb, 0xad, 0xd3, 0xb6, 0x9b,
	0x5a, 0xc9, 0x5c, 0xc6, 0xe9, 0x31, 0xfc, 0x3f, 0xe1, 0xda, 0x84, 0x2b, 0x1d, 0x17, 0xad, 0xec,
	0xe5, 0x81, 0x41, 0xa5, 0xeb, 0x7b, 0x40, 0x47, 0x89, 0x5a, 0x27, 0xd7, 0x2d, 0x79, 0xdf, 0x46,
	0x2a, 0xec, 0xd3, 0x2f, 0x35, 0x68, 0x58, 0x6f, 0x1f, 0x02, 0x5c, 0x3f, 0x0c, 0x74, 0xad, 0x95,
	0xe0, 0x86, 0x3b, 0x6f, 0x78, 0x3b, 0x9e, 0x83, 0x57, 0x5d, 0x33, 0x1a, 0x6c, 0xdc, 0x3d, 0x6b,
	0x7a, 0xf0, 0xbb, 0xbd, 0xa4, 0x17, 0xe0, 0x55, 0x7c, 0xd2, 0xb4, 0xac, 0xf9, 0xeb, 0xf0, 0x82,
	0x60, 0x53, 0xc8, 0xa5, 0x79, 0x50, 0xdc, 0xa5, 0x61, 0xb1, 0x87, 0x94, 0x3a, 0x6a, 0xe5, 0x7e,
	0x05, 0x9d, 0x15, 0xac, 0xd0, 0x9d, 0x37, 0xde, 0xd7, 0xe4, 0xd5, 0xd5, 0xb6, 0x7d, 0xe8, 0xcf,
	0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, 0x51, 0x0e, 0xed, 0xc4, 0xf6, 0x05, 0x00, 0x00,
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// HtlcClient is the client API for Htlc service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type HtlcClient interface {
	AddInvoice(ctx context.Context, in *Invoice, opts ...grpc.CallOption) (*AddInvoiceResponse, error)
	ParseInvoice(ctx context.Context, in *ParseInvoiceRequest, opts ...grpc.CallOption) (*ParseInvoiceResponse, error)
	ListInvoices(ctx context.Context, in *ListInvoiceRequest, opts ...grpc.CallOption) (*ListInvoiceResponse, error)
	SendPayment(ctx context.Context, in *SendRequest, opts ...grpc.CallOption) (*SendResponse, error)
}

type htlcClient struct {
	cc grpc.ClientConnInterface
}

func NewHtlcClient(cc grpc.ClientConnInterface) HtlcClient {
	return &htlcClient{cc}
}

func (c *htlcClient) AddInvoice(ctx context.Context, in *Invoice, opts ...grpc.CallOption) (*AddInvoiceResponse, error) {
	out := new(AddInvoiceResponse)
	err := c.cc.Invoke(ctx, "/proxy.Htlc/AddInvoice", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *htlcClient) ParseInvoice(ctx context.Context, in *ParseInvoiceRequest, opts ...grpc.CallOption) (*ParseInvoiceResponse, error) {
	out := new(ParseInvoiceResponse)
	err := c.cc.Invoke(ctx, "/proxy.Htlc/ParseInvoice", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *htlcClient) ListInvoices(ctx context.Context, in *ListInvoiceRequest, opts ...grpc.CallOption) (*ListInvoiceResponse, error) {
	out := new(ListInvoiceResponse)
	err := c.cc.Invoke(ctx, "/proxy.Htlc/ListInvoices", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func (c *htlcClient) SendPayment(ctx context.Context, in *SendRequest, opts ...grpc.CallOption) (*SendResponse, error) {
	out := new(SendResponse)
	err := c.cc.Invoke(ctx, "/proxy.Htlc/SendPayment", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// HtlcServer is the server API for Htlc service.
type HtlcServer interface {
	AddInvoice(context.Context, *Invoice) (*AddInvoiceResponse, error)
	ParseInvoice(context.Context, *ParseInvoiceRequest) (*ParseInvoiceResponse, error)
	ListInvoices(context.Context, *ListInvoiceRequest) (*ListInvoiceResponse, error)
	SendPayment(context.Context, *SendRequest) (*SendResponse, error)
}

// UnimplementedHtlcServer can be embedded to have forward compatible implementations.
type UnimplementedHtlcServer struct {
}

func (*UnimplementedHtlcServer) AddInvoice(ctx context.Context, req *Invoice) (*AddInvoiceResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method AddInvoice not implemented")
}
func (*UnimplementedHtlcServer) ParseInvoice(ctx context.Context, req *ParseInvoiceRequest) (*ParseInvoiceResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ParseInvoice not implemented")
}
func (*UnimplementedHtlcServer) ListInvoices(ctx context.Context, req *ListInvoiceRequest) (*ListInvoiceResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ListInvoices not implemented")
}
func (*UnimplementedHtlcServer) SendPayment(ctx context.Context, req *SendRequest) (*SendResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method SendPayment not implemented")
}

func RegisterHtlcServer(s *grpc.Server, srv HtlcServer) {
	s.RegisterService(&_Htlc_serviceDesc, srv)
}

func _Htlc_AddInvoice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(Invoice)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(HtlcServer).AddInvoice(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Htlc/AddInvoice",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(HtlcServer).AddInvoice(ctx, req.(*Invoice))
	}
	return interceptor(ctx, in, info, handler)
}

func _Htlc_ParseInvoice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ParseInvoiceRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(HtlcServer).ParseInvoice(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Htlc/ParseInvoice",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(HtlcServer).ParseInvoice(ctx, req.(*ParseInvoiceRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Htlc_ListInvoices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ListInvoiceRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(HtlcServer).ListInvoices(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Htlc/ListInvoices",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(HtlcServer).ListInvoices(ctx, req.(*ListInvoiceRequest))
	}
	return interceptor(ctx, in, info, handler)
}

func _Htlc_SendPayment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(SendRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(HtlcServer).SendPayment(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/proxy.Htlc/SendPayment",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(HtlcServer).SendPayment(ctx, req.(*SendRequest))
	}
	return interceptor(ctx, in, info, handler)
}

var _Htlc_serviceDesc = grpc.ServiceDesc{
	ServiceName: "proxy.Htlc",
	HandlerType: (*HtlcServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "AddInvoice",
			Handler:    _Htlc_AddInvoice_Handler,
		},
		{
			MethodName: "ParseInvoice",
			Handler:    _Htlc_ParseInvoice_Handler,
		},
		{
			MethodName: "ListInvoices",
			Handler:    _Htlc_ListInvoices_Handler,
		},
		{
			MethodName: "SendPayment",
			Handler:    _Htlc_SendPayment_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "htlc.proto",
}


<|start_filename|>tracker/bean/message.go<|end_filename|>
package bean

import (
	"github.com/omnilaboratory/obd/bean/enum"
)

type RequestMessage struct {
	Type             enum.MsgType `json:"type"`
	SenderNodePeerId string       `json:"sender_node_peer_id"`
	Data             interface{}  `json:"data"`
}

type ReplyMessage struct {
	Type   enum.MsgType `json:"type"`
	Status bool         `json:"status"`
	From   string       `json:"from"`
	To     string       `json:"to"`
	Result interface{}  `json:"result"`
}

//请求获取htlc的path
type HtlcPathRequest struct {
	PayerObdNodeId  string  `json:"payer_obd_node_id"`
	RealPayerPeerId string  `json:"real_payer_peer_id"`
	PayeePeerId     string  `json:"payee_peer_id"`
	PropertyId      int64   `json:"property_id"`
	H               string  `json:"h"`
	Amount          float64 `json:"amount"`
}

const (
	HtlcTxState_PayMoney        = 0
	HtlcTxState_ConfirmPayMoney = 1
)

//GetHtlcTxStateRequest
type GetHtlcTxStateRequest struct {
	Path string `json:"path"`
	H    string `json:"h"`
}

//GetChannelStateRequest
type GetChannelStateRequest struct {
	ChannelId string `json:"channel_id"`
}

//newHtlcTx
type UpdateHtlcTxStateRequest struct {
	GetHtlcTxStateRequest
	R string `json:"r"`
	//0 0:forward h 1:backword
	DirectionFlag int    `json:"direction_flag"`
	CurrChannelId string `json:"curr_channel_id"`
}

//GetChannelStateRequest
type GetOmniBalanceRequest struct {
	Address    string `json:"address"`
	PropertyId int    `json:"property_id"`
}


<|start_filename|>service/rscm_commitment_payee.go<|end_filename|>
package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/tool"
	"github.com/tidwall/gjson"
	"log"
	"strconv"
	"sync"
	"time"
)

type commitmentTxSignedManager struct {
	operationFlag sync.Mutex
}

var CommitmentTxSignedService commitmentTxSignedManager

// step 3 协议号：351 bob所在的obd接收到了alice的转账申请 提送110351
func (this *commitmentTxSignedManager) BeforeBobSignCommitmentTransactionAtBobSide(data string, user *bean.User) (retData *bean.PayerRequestCommitmentTxToBobClient, err error) {
	requestCreateCommitmentTx := &bean.AliceRequestToCreateCommitmentTxOfP2p{}
	_ = json.Unmarshal([]byte(data), requestCreateCommitmentTx)

	retData = &bean.PayerRequestCommitmentTxToBobClient{}
	retData.AliceRequestToCreateCommitmentTxOfP2p = *requestCreateCommitmentTx

	tx, err := user.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	defer tx.Rollback()

	channelInfo := getChannelInfoByChannelId(tx, retData.ChannelId, user.PeerId)
	if channelInfo == nil {
		return nil, errors.New("not found channelInfo at targetSide")
	}

	channelInfo.CurrState = bean.ChannelState_NewTx
	_ = tx.Update(channelInfo)

	senderPeerId := channelInfo.PeerIdA
	if user.PeerId == channelInfo.PeerIdA {
		senderPeerId = channelInfo.PeerIdB
	}

	// 351的p2p消息缓存到了msg的数据字段了
	messageHash := messageService.saveMsgUseTx(tx, senderPeerId, user.PeerId, data)
	retData.MsgHash = messageHash

	commitmentTxInfo, _ := getLatestCommitmentTxUseDbTx(tx, channelInfo.ChannelId, user.PeerId)
	if commitmentTxInfo.Id == 0 {
		commitmentTxInfo.Owner = user.PeerId
		commitmentTxInfo.AmountToRSMC = 0
		commitmentTxInfo.AmountToCounterparty = channelInfo.Amount
	}
	sendChannelStateToTracker(*channelInfo, *commitmentTxInfo)

	_ = tx.Commit()
	return retData, nil
}

// step 4 协议号：100352 bob签收这次转账
func (this *commitmentTxSignedManager) RevokeAndAcknowledgeCommitmentTransaction(msg bean.RequestMessage, signer *bean.User) (retData interface{}, needSignC2b bool, err error) {
	if tool.CheckIsString(&msg.Data) == false {
		err = errors.New(enum.Tips_common_empty + "msg.data")
		log.Println(err)
		return nil, false, err
	}

	reqData := &bean.PayeeSendSignCommitmentTx{}
	err = json.Unmarshal([]byte(msg.Data), reqData)
	if err != nil {
		log.Println(err)
		return nil, false, err
	}

	if tool.CheckIsString(&reqData.MsgHash) == false {
		err = errors.New(enum.Tips_common_wrong + "msg_hash")
		log.Println(err)
		return nil, false, err
	}

	tx, err := signer.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, false, err
	}
	defer tx.Rollback()

	//region 确认是给自己的信息
	message, err := messageService.getMsgUseTx(tx, reqData.MsgHash)
	if err != nil {
		return nil, false, errors.New(enum.Tips_common_invilidMsgHash)
	}
	if message.Receiver != signer.PeerId {
		return nil, false, errors.New(enum.Tips_rsmc_notTargetUser)
	}

	c2aDataJson := &bean.AliceRequestToCreateCommitmentTxOfP2p{}
	_ = json.Unmarshal([]byte(message.Data), c2aDataJson)
	reqData.MsgHash = c2aDataJson.CommitmentTxHash
	//endregion

	if tool.CheckIsString(&reqData.ChannelId) == false {
		err = errors.New(enum.Tips_common_empty + "channel_id")
		log.Println(err)
		return nil, false, err
	}

	channelInfo := getChannelInfoByChannelId(tx, reqData.ChannelId, signer.PeerId)
	if channelInfo == nil {
		err = errors.New(enum.Tips_funding_notFoundChannelByChannelId + reqData.ChannelId)
		log.Println(err)
		return nil, false, err
	}

	if channelInfo.CurrState < bean.ChannelState_NewTx {
		return nil, false, errors.New("do not finish funding")
	}

	payeeRevokeAndAcknowledgeCommitment := &dao.PayeeRevokeAndAcknowledgeCommitment{}
	_ = tx.Select(q.Eq("ChannelId", channelInfo.ChannelId), q.Eq("CommitmentTxHash", reqData.MsgHash)).First(payeeRevokeAndAcknowledgeCommitment)
	if payeeRevokeAndAcknowledgeCommitment.Id > 0 {
		return nil, false, errors.New(enum.Tips_rsmc_notDoItAgain)
	}

	//Make sure who creates the transaction, who will sign the transaction.
	//The default creator is Alice, and Bob is the signer.
	//While if ALice is the signer, then Bob creates the transaction.
	targetUser := channelInfo.PeerIdA
	if signer.PeerId == channelInfo.PeerIdB {
		targetUser = channelInfo.PeerIdA
	} else {
		targetUser = channelInfo.PeerIdB
	}

	if targetUser != msg.RecipientUserPeerId {
		return nil, false, errors.New(enum.Tips_rsmc_notTargetUser)
	}

	toAliceP2pData := bean.PayeeSignCommitmentTxOfP2p{}
	toAliceP2pData.ChannelId = channelInfo.ChannelId
	toAliceP2pData.CommitmentTxHash = reqData.MsgHash
	toAliceP2pData.Approval = reqData.Approval

	if reqData.Approval == false {

		if channelInfo.CurrState == bean.ChannelState_NewTx {
			channelInfo.CurrState = bean.ChannelState_CanUse
			_ = tx.Update(channelInfo)
		}

		payeeRevokeAndAcknowledgeCommitment.ChannelId = toAliceP2pData.ChannelId
		payeeRevokeAndAcknowledgeCommitment.CommitmentTxHash = toAliceP2pData.CommitmentTxHash
		payeeRevokeAndAcknowledgeCommitment.Approval = false
		_ = tx.Save(payeeRevokeAndAcknowledgeCommitment)

		_ = messageService.updateMsgStateUseTx(tx, message)
		err = tx.Commit()
		if err != nil {
			log.Println(err)
			return nil, false, err
		}
		return retData, false, nil
	}

	this.operationFlag.Lock()
	defer this.operationFlag.Unlock()

	needSignData := bean.NeedBobSignRawDataForC2b{}
	needSignData.ChannelId = channelInfo.ChannelId

	currNodeChannelPubKey := channelInfo.PubKeyB
	if signer.PeerId == channelInfo.PeerIdA {
		currNodeChannelPubKey = channelInfo.PubKeyA
	}

	//for rsmc
	if _, err = getAddressFromPubKey(reqData.CurrTempAddressPubKey); err != nil {
		err = errors.New(enum.Tips_common_wrong + "curr_temp_address_pub_key")
		log.Println(err)
		return nil, false, err
	}

	//for br
	creatorLastTempAddressPrivateKey := c2aDataJson.LastTempAddressPrivateKey
	if tool.CheckIsString(&creatorLastTempAddressPrivateKey) == false {
		err = errors.New(enum.Tips_common_empty + "the starter's last temp address private key")
		log.Println(err)
		return nil, false, err
	}

	// get the funding transaction
	fundingTransaction := getFundingTransactionByChannelId(tx, channelInfo.ChannelId, signer.PeerId)
	if fundingTransaction == nil {
		return nil, false, errors.New(enum.Tips_common_notFound + "fundingTransaction")
	}

	toAliceP2pData.LastTempAddressPrivateKey = reqData.LastTempAddressPrivateKey
	toAliceP2pData.CurrTempAddressPubKey = reqData.CurrTempAddressPubKey

	//region 1、验证签名后的C2a的Rsmc和ToBob hex
	var signedRsmcHex, aliceRsmcTxId, c2aRsmcMultiAddress, c2aRsmcRedeemScript, c2aRsmcMultiAddressScriptPubKey string
	var c2aRsmcOutputs []bean.TransactionInputItem
	if tool.CheckIsString(&c2aDataJson.RsmcRawData.Hex) {
		signedRsmcHex = reqData.C2aRsmcSignedHex
		if pass, _ := omnicore.CheckMultiSign(signedRsmcHex, 2); pass == false {
			return nil, false, errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "c2a_rsmc_signed_hex"))
		}

		if verifyCompleteSignHex(c2aDataJson.RsmcRawData.Inputs, signedRsmcHex) != nil {
			return nil, false, errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "c2a_rsmc_signed_hex"))
		}

		aliceRsmcTxId = omnicore.GetTxId(signedRsmcHex)

		// region 根据alice的临时地址+bob的通道address,获取alice2+bob的多签地址，并得到AliceSignedRsmcHex签名后的交易的input，为创建alice的RD和bob的BR做准备
		c2aRsmcMultiAddr, err := omnicore.CreateMultiSig(2, []string{c2aDataJson.CurrTempAddressPubKey, currNodeChannelPubKey})
		if err != nil {
			return nil, false, err
		}
		c2aRsmcMultiAddress = gjson.Get(c2aRsmcMultiAddr, "address").String()
		c2aRsmcRedeemScript = gjson.Get(c2aRsmcMultiAddr, "redeemScript").String()
		c2aRsmcMultiAddressScriptPubKey = gjson.Get(c2aRsmcMultiAddr, "scriptPubKey").String()

		c2aRsmcOutputs, err = getInputsForNextTxByParseTxHashVout(signedRsmcHex, c2aRsmcMultiAddress, c2aRsmcMultiAddressScriptPubKey, c2aRsmcRedeemScript)
		if err != nil {
			log.Println(err)
			return nil, false, err
		}
	}
	toAliceP2pData.C2aSignedRsmcHex = signedRsmcHex
	//endregion

	// region 2、签名 ToCounterpartyTxHex
	signedToCounterpartyTxHex := reqData.C2aCounterpartySignedHex
	if tool.CheckIsString(&c2aDataJson.CounterpartyRawData.Hex) {
		if pass, _ := omnicore.CheckMultiSign(signedToCounterpartyTxHex, 2); pass == false {
			return nil, false, errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "to_counterparty_tx_hex"))
		}

		if verifyCompleteSignHex(c2aDataJson.CounterpartyRawData.Inputs, signedToCounterpartyTxHex) != nil {
			return nil, false, errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "c2a_rsmc_signed_hex"))
		}
	}
	toAliceP2pData.C2aSignedToCounterpartyTxHex = signedToCounterpartyTxHex
	//endregion

	//获取bob最新的承诺交易
	latestCommitmentTxInfo, _ := getLatestCommitmentTxUseDbTx(tx, channelInfo.ChannelId, signer.PeerId)
	isFirstRequest := false
	if latestCommitmentTxInfo != nil && latestCommitmentTxInfo.Id > 0 {
		if latestCommitmentTxInfo.TxType != dao.CommitmentTransactionType_Rsmc {
			return nil, false, errors.New(enum.Tips_rsmc_errorCommitmentTxType + strconv.Itoa(int(latestCommitmentTxInfo.TxType)))
		}

		if latestCommitmentTxInfo.CurrState != dao.TxInfoState_CreateAndSign && latestCommitmentTxInfo.CurrState != dao.TxInfoState_Create {
			return nil, false, errors.New(enum.Tips_rsmc_errorCommitmentTxState + strconv.Itoa(int(latestCommitmentTxInfo.CurrState)))
		}

		if latestCommitmentTxInfo.CurrState == dao.TxInfoState_Create && latestCommitmentTxInfo.LastCommitmentTxId > 0 {
			lastCommitmentTx := &dao.CommitmentTransaction{}
			err = tx.Select(q.Eq("Id", latestCommitmentTxInfo.LastCommitmentTxId)).First(lastCommitmentTx)
			if err != nil {
				return nil, false, errors.New(enum.Tips_common_notFound + "lastCommitmentTx")
			}
			_, err = omnicore.GetPubKeyFromWifAndCheck(reqData.LastTempAddressPrivateKey, lastCommitmentTx.RSMCTempAddressPubKey)
			if err != nil {
				return nil, false, errors.New(fmt.Sprintf(enum.Tips_rsmc_wrongPrivateKeyForLast, reqData.LastTempAddressPrivateKey, lastCommitmentTx.RSMCTempAddressPubKey))
			}
		}

		if latestCommitmentTxInfo.CurrState == dao.TxInfoState_CreateAndSign { //有上一次的承诺交易
			_, err = omnicore.GetPubKeyFromWifAndCheck(reqData.LastTempAddressPrivateKey, latestCommitmentTxInfo.RSMCTempAddressPubKey)
			if err != nil {
				return nil, false, errors.New(fmt.Sprintf(enum.Tips_rsmc_wrongPrivateKeyForLast, reqData.LastTempAddressPrivateKey, latestCommitmentTxInfo.RSMCTempAddressPubKey))
			}
			isFirstRequest = true
		}
	} else { // 因为没有充值，没有最初的承诺交易C1b
		isFirstRequest = true
	}

	var c2bAmountToCounterparty = 0.0
	var c2bCommitmentId = 0
	//如果是本轮的第一次请求交易
	if isFirstRequest {
		//region 3、根据对方传过来的上一个交易的临时rsmc私钥，签名最近的BR交易，保证对方确实放弃了上一个承诺交易
		err := signLastBR(tx, dao.BRType_Rmsc, *channelInfo, signer.PeerId, c2aDataJson.LastTempAddressPrivateKey, latestCommitmentTxInfo.Id)
		if err != nil {
			log.Println(err)
			return nil, false, err
		}
		//endregion

		//region 4、创建C2b
		commitmentTxRequest := &bean.RequestCreateCommitmentTx{}
		commitmentTxRequest.ChannelId = channelInfo.ChannelId
		commitmentTxRequest.Amount = c2aDataJson.Amount
		commitmentTxRequest.CurrTempAddressIndex = reqData.CurrTempAddressIndex
		commitmentTxRequest.CurrTempAddressPubKey = reqData.CurrTempAddressPubKey
		newCommitmentTxInfo, rawTx, err := createCommitmentTxHex(tx, false, commitmentTxRequest, channelInfo, latestCommitmentTxInfo, *signer)
		if err != nil {
			log.Println(err)
			return nil, false, err
		}
		c2bAmountToCounterparty = newCommitmentTxInfo.AmountToCounterparty
		c2bCommitmentId = newCommitmentTxInfo.Id

		toAliceP2pData.C2bRsmcTxData = rawTx.RsmcRawTxData
		toAliceP2pData.C2bCounterpartyTxData = rawTx.ToCounterpartyRawTxData

		//endregion
	} else {
		if reqData.CurrTempAddressPubKey != latestCommitmentTxInfo.RSMCTempAddressPubKey {
			return nil, false, errors.New(fmt.Sprintf(enum.Tips_rsmc_notSameValueWhenCreate, reqData.CurrTempAddressPubKey, latestCommitmentTxInfo.RSMCTempAddressPubKey))
		}

		c2bAmountToCounterparty = latestCommitmentTxInfo.AmountToCounterparty
		c2bCommitmentId = latestCommitmentTxInfo.Id

		rawTx := &dao.CommitmentTxRawTx{}
		tx.Select(q.Eq("CommitmentTxId", latestCommitmentTxInfo.Id)).First(rawTx)
		if rawTx.Id == 0 {
			return nil, false, errors.New("not found rawTx")
		}

		toAliceP2pData.C2bRsmcTxData = rawTx.RsmcRawTxData
		toAliceP2pData.C2bCounterpartyTxData = rawTx.ToCounterpartyRawTxData
	}

	needSignData.C2bRsmcRawData = toAliceP2pData.C2bRsmcTxData
	needSignData.C2bCounterpartyRawData = toAliceP2pData.C2bCounterpartyTxData

	//region 5、根据签名后的C2a Rsmc创建alice的RD create RD tx for alice
	c2aRdOutputAddress := channelInfo.AddressA
	if signer.PeerId == channelInfo.PeerIdA {
		c2aRdOutputAddress = channelInfo.AddressB
	}
	if len(c2aRsmcOutputs) > 0 {
		c2aRdTx, err := omnicore.OmniCreateRawTransactionUseUnsendInput(
			c2aRsmcMultiAddress,
			c2aRsmcOutputs,
			c2aRdOutputAddress,
			channelInfo.FundingAddress,
			channelInfo.PropertyId,
			c2bAmountToCounterparty,
			getBtcMinerAmount(channelInfo.BtcAmount),
			1000,
			&c2aRsmcRedeemScript)
		if err != nil {
			log.Println(err)
			return nil, false, errors.New(fmt.Sprintf(enum.Tips_rsmc_failToCreate, "RD raw transacation"))
		}

		c2aRdRawData := bean.NeedClientSignTxData{}
		c2aRdRawData.Hex = c2aRdTx["hex"].(string)
		c2aRdRawData.Inputs = c2aRdTx["inputs"]
		c2aRdRawData.PubKeyA = c2aDataJson.CurrTempAddressPubKey
		c2aRdRawData.PubKeyB = currNodeChannelPubKey
		c2aRdRawData.IsMultisig = true
		toAliceP2pData.C2aRdTxData = c2aRdRawData

		needSignData.C2aRdRawData = c2aRdRawData
	}
	//endregion create RD tx for alice

	// region 6、根据alice的Rsmc，创建对应的BR,为下一个交易做准备，create BR2b tx  for bob
	if len(c2aRsmcOutputs) > 0 {
		var myAddress = channelInfo.AddressB
		if signer.PeerId == channelInfo.PeerIdA {
			myAddress = channelInfo.AddressA
		}
		senderCommitmentTx := &dao.CommitmentTransaction{}
		senderCommitmentTx.Id = c2bCommitmentId
		senderCommitmentTx.PropertyId = fundingTransaction.PropertyId
		senderCommitmentTx.RSMCTempAddressPubKey = c2aDataJson.CurrTempAddressPubKey
		senderCommitmentTx.RSMCMultiAddress = c2aRsmcMultiAddress
		senderCommitmentTx.RSMCRedeemScript = c2aRsmcRedeemScript
		senderCommitmentTx.RSMCMultiAddressScriptPubKey = c2aRsmcMultiAddressScriptPubKey
		senderCommitmentTx.RSMCTxHex = signedRsmcHex
		senderCommitmentTx.RSMCTxid = aliceRsmcTxId
		senderCommitmentTx.AmountToRSMC = c2bAmountToCounterparty
		c2aBrHexData, err := createCurrCommitmentTxRawBR(tx, dao.BRType_Rmsc, channelInfo, senderCommitmentTx, c2aRsmcOutputs, myAddress, *signer)
		if err != nil {
			log.Println(err)
			return nil, false, err
		}
		C2aBrRawData := bean.NeedClientSignRawBRTxData{}
		C2aBrRawData.Hex = c2aBrHexData["hex"].(string)
		C2aBrRawData.Inputs = c2aBrHexData["inputs"]
		C2aBrRawData.BrId = c2aBrHexData["br_id"].(int)
		C2aBrRawData.PubKeyA = c2aDataJson.CurrTempAddressPubKey
		C2aBrRawData.PubKeyB = currNodeChannelPubKey
		C2aBrRawData.IsMultisig = true
		needSignData.C2aBrRawData = C2aBrRawData
	}
	//endregion

	_ = messageService.updateMsgStateUseTx(tx, message)

	// 缓存数据
	cacheDataForTx := &dao.CacheDataForTx{}
	cacheDataForTx.KeyName = signer.PeerId + "_" + channelInfo.ChannelId
	_ = tx.Select(q.Eq("KeyName", cacheDataForTx.KeyName)).First(cacheDataForTx)
	if cacheDataForTx.Id != 0 {
		_ = tx.DeleteStruct(cacheDataForTx)
	}
	if cacheDataForTx.Id != 0 {
		_ = tx.DeleteStruct(cacheDataForTx)
	}
	bytes, _ := json.Marshal(&toAliceP2pData)
	cacheDataForTx.Data = bytes
	_ = tx.Save(cacheDataForTx)

	err = tx.Commit()
	if err != nil {
		log.Println(err)
		return nil, false, err
	}

	return needSignData, true, err
}

// step 5 协议号：100361 完成后推送352协议 bob对C2b的Rsmc，toBob和c2a的Rd和C2a的Br进行签名
func (this *commitmentTxSignedManager) OnBobSignC2bTransactionAtBobSide(data string, user *bean.User) (toBob, retData interface{}, err error) {
	if tool.CheckIsString(&data) == false {
		err = errors.New(enum.Tips_common_empty + "msg.data")
		log.Println(err)
		return nil, nil, err
	}
	signedDataForC2b := bean.BobSignedRsmcDataForC2b{}
	_ = json.Unmarshal([]byte(data), &signedDataForC2b)

	if tool.CheckIsString(&signedDataForC2b.ChannelId) == false {
		err = errors.New(enum.Tips_common_empty + "channel_id")
		log.Println(err)
		return nil, nil, err
	}

	//得到step4缓存的数据
	tx, err := user.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, nil, err
	}
	defer tx.Rollback()

	cacheDataForTx := &dao.CacheDataForTx{}
	tx.Select(q.Eq("KeyName", user.PeerId+"_"+signedDataForC2b.ChannelId)).First(cacheDataForTx)
	if cacheDataForTx.Id == 0 {
		return nil, nil, errors.New(enum.Tips_common_wrong + "channel_id")
	}
	p2pData := &bean.PayeeSignCommitmentTxOfP2p{}
	_ = json.Unmarshal(cacheDataForTx.Data, p2pData)

	if len(p2pData.ChannelId) == 0 {
		return nil, nil, errors.New(enum.Tips_common_wrong + "channel_id")
	}

	if tool.CheckIsString(&p2pData.C2bRsmcTxData.Hex) {
		if pass, _ := omnicore.CheckMultiSign(signedDataForC2b.C2bRsmcSignedHex, 1); pass == false {
			err = errors.New(enum.Tips_common_wrong + "signed c2b_rsmc_signed_hex")
			log.Println(err)
			return nil, nil, err
		}
	}

	if tool.CheckIsString(&p2pData.C2bCounterpartyTxData.Hex) {
		if pass, _ := omnicore.CheckMultiSign(signedDataForC2b.C2bCounterpartySignedHex, 1); pass == false {
			err = errors.New(enum.Tips_common_wrong + "signed c2b_counterparty_signed_hex")
			log.Println(err)
			return nil, nil, err
		}
	}

	if tool.CheckIsString(&p2pData.C2aRdTxData.Hex) {
		if pass, _ := omnicore.CheckMultiSign(signedDataForC2b.C2aRdSignedHex, 1); pass == false {
			err = errors.New(enum.Tips_common_wrong + "signed c2a_rd_signed_hex")
			log.Println(err)
			return nil, nil, err
		}
	}

	if tool.CheckIsString(&signedDataForC2b.C2aBrSignedHex) {
		if pass, _ := omnicore.CheckMultiSign(signedDataForC2b.C2aBrSignedHex, 1); pass == false {
			err = errors.New(enum.Tips_common_wrong + "c2a_br_signed_hex")
			log.Println(err)
			return nil, nil, err
		}

		if signedDataForC2b.C2aBrId == 0 {
			err = errors.New(enum.Tips_common_wrong + "c2a_br_id")
			log.Println(err)
			return nil, nil, err
		}
	}

	latestCommitmentTxInfo, err := getLatestCommitmentTxUseDbTx(tx, signedDataForC2b.ChannelId, user.PeerId)
	if err != nil {
		return nil, nil, errors.New(enum.Tips_channel_notFoundLatestCommitmentTx)
	}

	if len(signedDataForC2b.C2bRsmcSignedHex) > 0 {
		latestCommitmentTxInfo.RSMCTxHex = signedDataForC2b.C2bRsmcSignedHex
		latestCommitmentTxInfo.RSMCTxid = omnicore.GetTxId(signedDataForC2b.C2bRsmcSignedHex)
	}

	if len(signedDataForC2b.C2bCounterpartySignedHex) > 0 {
		latestCommitmentTxInfo.ToCounterpartyTxHex = signedDataForC2b.C2bCounterpartySignedHex
		latestCommitmentTxInfo.ToCounterpartyTxid = omnicore.GetTxId(signedDataForC2b.C2bCounterpartySignedHex)
	}

	if len(signedDataForC2b.C2aBrSignedHex) > 0 {
		err = updateCurrCommitmentTxRawBR(tx, signedDataForC2b.C2aBrId, signedDataForC2b.C2aBrSignedHex, *user)
		if err != nil {
			return nil, nil, err
		}
	}
	_ = tx.Update(latestCommitmentTxInfo)

	_ = tx.Commit()

	p2pData.C2bRsmcTxData.Hex = signedDataForC2b.C2bRsmcSignedHex
	p2pData.C2bCounterpartyTxData.Hex = signedDataForC2b.C2bCounterpartySignedHex
	p2pData.C2aRdTxData.Hex = signedDataForC2b.C2aRdSignedHex

	toBobData := bean.BobSignedRsmcDataForC2bResult{}
	toBobData.ChannelId = p2pData.ChannelId
	toBobData.CommitmentTxHash = p2pData.CommitmentTxHash
	toBobData.Approval = p2pData.Approval
	return toBobData, p2pData, nil
}

// step 9 协议号：响应353 obd节点接收到alice的二次签名信息 推送110353信息给bob
func (this *commitmentTxSignedManager) OnGetAliceSignC2bTransactionAtBobSide(data string, user *bean.User) (retData bean.NeedBobSignRdTxForC2b, err error) {
	aliceSignedC2bTxDataP2p := bean.AliceSignedC2bTxDataP2p{}
	err = json.Unmarshal([]byte(data), &aliceSignedC2bTxDataP2p)
	if err != nil {
		return retData, err
	}

	cacheDataForTx := &dao.CacheDataForTx{}
	user.Db.Select(q.Eq("KeyName", user.PeerId+"_"+aliceSignedC2bTxDataP2p.ChannelId)).First(cacheDataForTx)
	if cacheDataForTx.Id == 0 {
		return retData, errors.New(enum.Tips_common_wrong + "channel_id")
	}
	cacheDataFrom352 := &bean.PayeeSignCommitmentTxOfP2p{}
	_ = json.Unmarshal(cacheDataForTx.Data, cacheDataFrom352)

	if tool.CheckIsString(&cacheDataFrom352.C2bRsmcTxData.Hex) {
		if verifyCompleteSignHex(cacheDataFrom352.C2bRsmcTxData.Inputs, aliceSignedC2bTxDataP2p.C2bRsmcSignedHex) != nil {
			return retData, errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "c2b_rsmc_signed_hex"))
		}
	}

	if tool.CheckIsString(&cacheDataFrom352.C2bCounterpartyTxData.Hex) {
		if verifyCompleteSignHex(cacheDataFrom352.C2bCounterpartyTxData.Inputs, aliceSignedC2bTxDataP2p.C2bCounterpartySignedHex) != nil {
			return retData, errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "c2b_signed_to_counterparty_tx_hex"))
		}
	}

	cacheDataForTx = &dao.CacheDataForTx{}
	cacheDataForTx.KeyName = user.PeerId + "_353_" + aliceSignedC2bTxDataP2p.ChannelId
	_ = user.Db.Select(q.Eq("KeyName", cacheDataForTx.KeyName)).First(cacheDataForTx)
	if cacheDataForTx.Id != 0 {
		_ = user.Db.DeleteStruct(cacheDataForTx)
	}
	if cacheDataForTx.Id != 0 {
		_ = user.Db.DeleteStruct(cacheDataForTx)
	}
	bytes, _ := json.Marshal(&aliceSignedC2bTxDataP2p)
	cacheDataForTx.Data = bytes
	_ = user.Db.Save(cacheDataForTx)

	needBobSignRdTxForC2b := bean.NeedBobSignRdTxForC2b{}
	needBobSignRdTxForC2b.ChannelId = aliceSignedC2bTxDataP2p.ChannelId
	needBobSignRdTxForC2b.C2bRdPartialData = aliceSignedC2bTxDataP2p.C2bRdPartialData
	return needBobSignRdTxForC2b, nil
}

// step 10 协议号：100364 响应bob的才c2b的Rd的签名
func (this *commitmentTxSignedManager) BobSignC2bRdAtBobSide(data string, user *bean.User) (retData interface{}, err error) {
	bobSignedRdTxForC2b := bean.BobSignedRdTxForC2b{}
	_ = json.Unmarshal([]byte(data), &bobSignedRdTxForC2b)

	cacheDataForTx := &dao.CacheDataForTx{}
	user.Db.Select(q.Eq("KeyName", user.PeerId+"_353_"+bobSignedRdTxForC2b.ChannelId)).First(cacheDataForTx)
	if cacheDataForTx.Id == 0 {
		return nil, errors.New(enum.Tips_common_wrong + "channel_id")
	}
	dataFrom353 := &bean.AliceSignedC2bTxDataP2p{}
	_ = json.Unmarshal(cacheDataForTx.Data, dataFrom353)
	if len(dataFrom353.ChannelId) == 0 {
		return nil, errors.New(enum.Tips_common_empty + "channel_id")
	}

	if tool.CheckIsString(&dataFrom353.C2bRdPartialData.Hex) {
		if pass, _ := omnicore.CheckMultiSign(bobSignedRdTxForC2b.C2bRdSignedHex, 2); pass == false {
			err = errors.New(enum.Tips_common_wrong + "signed c2b_rd_signed_hex")
			log.Println(err)
			return nil, err
		}

		if tool.CheckIsString(&dataFrom353.C2bRdPartialData.Hex) {
			if verifyCompleteSignHex(dataFrom353.C2bRdPartialData.Inputs, bobSignedRdTxForC2b.C2bRdSignedHex) != nil {
				return retData, errors.New(fmt.Sprintf(enum.Tips_common_failToSign, "c2b_rd_signed_hex"))
			}
		}
	}

	var channelId = dataFrom353.ChannelId
	var signedRsmcHex = dataFrom353.C2bRsmcSignedHex
	var signedToCounterpartyTxHex = dataFrom353.C2bCounterpartySignedHex
	var c2bSignedRdHex = bobSignedRdTxForC2b.C2bRdSignedHex
	var c2aInitTxHash = dataFrom353.C2aCommitmentTxHash

	tx, err := user.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	defer tx.Rollback()

	channelInfo := getChannelInfoByChannelId(tx, channelId, user.PeerId)
	if channelInfo == nil {
		return nil, errors.New("not found channelInfo at targetSide")
	}

	latestCommitmentTxInfo, err := getLatestCommitmentTxUseDbTx(tx, channelId, user.PeerId)
	if err != nil {
		err = errors.New("fail to find payer's commitmentTxInfo")
		log.Println(err)
		return nil, err
	}

	if latestCommitmentTxInfo.CurrState != dao.TxInfoState_Create {
		err = errors.New("wrong commitmentTxInfo state " + strconv.Itoa(int(latestCommitmentTxInfo.CurrState)))
		log.Println(err)
		return nil, err
	}

	myChannelAddress := channelInfo.AddressB
	if user.PeerId == channelInfo.PeerIdA {
		myChannelAddress = channelInfo.AddressA
	}

	if tool.CheckIsString(&signedRsmcHex) {
		latestCommitmentTxInfo.RSMCTxHex = signedRsmcHex
		latestCommitmentTxInfo.RSMCTxid = omnicore.GetTxId(signedRsmcHex)
		err = saveRdTx(tx, channelInfo, signedRsmcHex, c2bSignedRdHex, latestCommitmentTxInfo, myChannelAddress, user)
		if err != nil {
			return nil, err
		}
	}

	if tool.CheckIsString(&signedToCounterpartyTxHex) {
		latestCommitmentTxInfo.ToCounterpartyTxHex = signedToCounterpartyTxHex
		latestCommitmentTxInfo.ToCounterpartyTxid = omnicore.GetTxId(signedToCounterpartyTxHex)
	}

	latestCommitmentTxInfo.CurrState = dao.TxInfoState_CreateAndSign
	latestCommitmentTxInfo.SignAt = time.Now()

	bytes, err := json.Marshal(latestCommitmentTxInfo)
	msgHash := tool.SignMsgWithSha256(bytes)
	latestCommitmentTxInfo.CurrHash = msgHash
	_ = tx.Update(latestCommitmentTxInfo)

	lastCommitmentTxInfo := dao.CommitmentTransaction{}
	_ = tx.One("Id", latestCommitmentTxInfo.LastCommitmentTxId, &lastCommitmentTxInfo)
	if lastCommitmentTxInfo.Id > 0 {
		lastCommitmentTxInfo.CurrState = dao.TxInfoState_Abord
		_ = tx.Update(lastCommitmentTxInfo)
	}

	payeeRevokeAndAcknowledgeCommitment := &dao.PayeeRevokeAndAcknowledgeCommitment{}
	payeeRevokeAndAcknowledgeCommitment.ChannelId = channelId
	payeeRevokeAndAcknowledgeCommitment.CommitmentTxHash = c2aInitTxHash
	payeeRevokeAndAcknowledgeCommitment.Approval = true
	_ = tx.Save(payeeRevokeAndAcknowledgeCommitment)

	channelInfo.CurrState = bean.ChannelState_CanUse
	_ = tx.Update(channelInfo)

	_ = tx.Commit()

	//同步通道信息到tracker
	sendChannelStateToTracker(*channelInfo, *latestCommitmentTxInfo)
	log.Println("end rsmc step 10", time.Now())
	return latestCommitmentTxInfo, nil
}


<|start_filename|>lightclient/p2p_util_test.go<|end_filename|>
package lightclient

import "testing"

func TestConnP2PServer(t *testing.T) {
	StartP2PNode()
}


<|start_filename|>admin/channel.go<|end_filename|>
package admin

import (
	"encoding/json"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/service"
)

func BeforeBobAcceptOpenChannel(msg *bean.RequestMessage, user *bean.User) (resultData *bean.SendSignOpenChannel, err error) {

	aliceOpenChannelInfo := bean.RequestOpenChannel{}
	err = json.Unmarshal([]byte(msg.Data), &aliceOpenChannelInfo)
	if err != nil {
		return nil, err
	}

	resultData = &bean.SendSignOpenChannel{}
	resultData.TemporaryChannelId = aliceOpenChannelInfo.TemporaryChannelId

	address, err := service.HDWalletService.CreateNewAddress(user)
	if err != nil {
		return nil, err
	}
	resultData.FundeeAddressIndex = address.Index
	resultData.FundingPubKey = address.PubKey
	resultData.Approval = true

	return resultData, nil
}


<|start_filename|>omnicore/CreateRawtxReference.go<|end_filename|>
package omnicore

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"strings"

	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/txscript"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
)

/*
 * https://github.com/OmniLayer/omnicore/wiki/Use-the-raw-transaction-API-to-create-a-Simple-Send-transaction
 */

/*
 * step 5) Attach reference/receiver output
 * omnicore-cli "omni_createrawtx_reference" "0100000002de95b97cf4c67ec01485fd698ec154a325ff69dd3e58435d7024bae7f69534c20000000000ffffffffb3b60aaa69b860c9bf31e742e3b37e75a2a553fd0bebf8aaf7da0e9bb07316ee0200000000ffffffff010000000000000000166a146f6d6e690000000000000002000000000098968000000000"
 * 											"<KEY>"
 */
func Omni_createrawtx_reference(base_tx *wire.MsgTx, receiver_address string, defaultNet *chaincfg.Params) (*wire.MsgTx, error) {

	destinationAddress, err := btcutil.DecodeAddress(receiver_address, defaultNet)
	if err != nil {
		return nil, errors.New("Fail decoding receiver address")
	}

	destinationPkScript, _ := txscript.PayToAddrScript(destinationAddress)

	// TO DO: add logic to calc dust
	val := OmniGetDustThreshold(destinationPkScript)
	// if val < dust {
	//	val = dust
	//}
	redeemTxOut := wire.NewTxOut(val, destinationPkScript)

	base_tx.AddTxOut(redeemTxOut)
	return base_tx, nil
}

/*
 * defined in amount.h
 */
/** No amount larger than this (in satoshi) is valid.
 *
 * Note that this constant is *not* the total money supply, which in Bitcoin
 * currently happens to be less than 21,000,000 BTC for various reasons, but
 * rather a sanity check. As this sanity check is used by consensus-critical
 * validation code, the exact value of the MAX_MONEY constant is consensus
 * critical; in unusual circumstances like a(nother) overflow bug that allowed
 * for the creation of coins out of thin air modification could lead to a fork.
 * */
const COIN = 100000000
const MAX_MONEY = 21000000 * COIN

func MoneyRange(money int64) bool {
	if money >= 0 && money <= MAX_MONEY {
		return true
	} else {
		return false
	}
}

func AmountFromValue(value string) int64 {
	// amount in satoshi = bitcoin_amount * COIN
	amount := StrToInt64(value, true)
	if MoneyRange(amount) {
		return amount
	} else {
		fmt.Println("AmountFromValue(value string): value out of range")
		return 0
	}
}

/*
 * script.cpp, int64_t OmniGetDustThreshold(const CScript& scriptPubKey)
 *
 * Determines the minimum output amount to be spent by an output, based on the
 * scriptPubKey size in relation to the minimum relay fee.
 *
 * @param scriptPubKey[in]  The scriptPubKey
 * @return The dust threshold value
 *
 */
func OmniGetDustThreshold(scriptPubKey []byte) int64 {
	//TO DO, add logic to calculate dust threshhold.
	if len(scriptPubKey) > 0 {
		return 546
	} else {
		return COIN
	}

}

/*
 * step 6) Specify miner fee and attach change output (as needed)
 *
 * omnicore-cli "omni_createrawtx_change" "0100000002de95b97cf4c67ec01485fd698ec154a325ff69dd3e58435d7024bae7f69534c20000000000ffffffffb3b60aaa69b860c9bf31e742e3b37e75a2a553fd0bebf8aaf7da0e9bb07316ee0200000000ffffffff020000000000000000166a146f6d6e690000000000000002000000000098968022020000000000001976a914ee692ea81da1b12d3dd8f53fd504865c9d843f5288ac00000000"
 *	'[{"txid":"c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de","vout":0,"scriptPubKey":"76a914c6734676a08e3c6438bd95fa62c57939c988a17b88ac","value":0.001},
 *    {"txid":"ee1673b09b0edaf7aaf8eb0bfd53a5a2757eb3e342e731bfc960b869aa0ab6b3","vout":2,"scriptPubKey":"76a914c6734676a08e3c6438bd95fa62c57939c988a17b88ac","value":0.0083566}]
 * 	'
 *   "1K6JtSvrHtyFmxdtGZyZEF7ydytTGqasNc"
 *   0.0006
 *
 * This example specifies a transaction fee of 0.0006 BTC.
 * The golang implementation does not accept number expressed in exponential from.
 */
func Omni_createrawtx_change(base_tx *wire.MsgTx, prev_txs_json_list string, destination_address string, miner_fee_in_btc string, defaultNet *chaincfg.Params) (*wire.MsgTx, error) {

	destination, err := btcutil.DecodeAddress(destination_address, defaultNet)
	destinationPkScript, _ := txscript.PayToAddrScript(destination)
	if err != nil {
		return nil, errors.New("Omni_createrawtx_change(...): Fail decoding destination address, which accepts the change.")
	}

	txFee_in_satoshi := AmountFromValue(miner_fee_in_btc)

	var total_val_in int64 = 0

	decoder := json.NewDecoder(strings.NewReader(prev_txs_json_list))
	for {
		var prev_tx PrevTx
		if err := decoder.Decode(&prev_tx); err == io.EOF {
			break
		} else if err != nil {
			log.Fatal(err)
		}
		//prev_txid := prev_tx.TxID
		//prev_vout := prev_tx.VOut
		//prev_scriptPubKey := prev_tx.ScriptPubKey
		//prev_value := prev_tx.Value

		total_val_in = total_val_in + AmountFromValue(prev_tx.Value)

	}

	/*
	 * createTx.cpp, TxBuilder& TxBuilder::addChange(...) adds an output for change
	 *
	 * int64_t txChange = view.GetValueIn(tx) - tx.GetValueOut() - txFee;
	 * int64_t minValue = OmniGetDustThreshold(scriptPubKey);
	 *
	 */

	// because in Omni_createrawtx_reference(...) there is a dust output.
	txChange := total_val_in - OmniGetDustThreshold(destinationPkScript) - txFee_in_satoshi
	minValue := OmniGetDustThreshold(destinationPkScript)

	if txChange < minValue {
		return base_tx, nil
	}
	redeemTxOut := wire.NewTxOut(txChange, destinationPkScript)

	/*
	*  std::vector<CTxOut>::iterator it = transaction.vout.end();
	*  if (position < transaction.vout.size()) {
	*  it = transaction.vout.begin() + position;
	*  }
	 */

	TxOutArray := base_tx.TxOut
	redeemTxOutArray := []*wire.TxOut{redeemTxOut}
	TxOutArray = append(redeemTxOutArray, TxOutArray...)

	base_tx.TxOut = TxOutArray
	//base_tx.AddTxOut(redeemTxOut)

	return base_tx, nil
}


<|start_filename|>service/funding_asset.go<|end_filename|>
package service

import (
	"encoding/json"
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/chainhash"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/conn"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/omnicore"
	"github.com/omnilaboratory/obd/tool"
	"github.com/tidwall/gjson"
	"log"
	"strconv"
	"time"
)

var tempAssetFundingCreatedData map[string]bean.FundingAssetOfP2p
var tempAssetFundingSignData map[string]map[string]interface{}
var tempAssetFundingAfterBobSignData map[string]string

// ********************* omni资产充值 *********************
// funder request to fund to the multiAddr (channel)

// 协议号：100034 充值者alice充值资产，请求创建C1a 需要增加Alice对C1a的签名
func (service *fundingTransactionManager) AssetFundingCreated(msg bean.RequestMessage, user *bean.User) (outputData interface{}, needSign bool, err error) {
	reqData := &bean.SendRequestAssetFunding{}
	err = json.Unmarshal([]byte(msg.Data), reqData)
	if err != nil {
		log.Println(err)
		return nil, false, err
	}

	if tool.CheckIsString(&reqData.TemporaryChannelId) == false {
		err = errors.New(enum.Tips_common_empty + "temporary_channel_id ")
		log.Println(err)
		return nil, false, err
	}

	if tool.CheckIsString(&reqData.FundingTxHex) == false {
		err = errors.New(enum.Tips_common_empty + " funding_tx_hex ")
		log.Println(err)
		return nil, false, err
	}
	testResult := conn2tracker.TestMemPoolAccept(reqData.FundingTxHex)
	if testResult == "" {
		err = errors.New(enum.Tips_common_empty + " funding_tx_hex ")
		log.Println(err)
		return nil, false, err
	}
	if gjson.Parse(testResult).Array()[0].Get("allowed").Bool() == false {
		return nil, false, errors.New(gjson.Parse(testResult).Array()[0].Get("reject-reason").String())
	}

	if _, err := getAddressFromPubKey(reqData.TempAddressPubKey); err != nil {
		err = errors.New(enum.Tips_common_wrong + "temp_address_pub_key ")
		log.Println(err)
		return nil, false, err
	}

	tx, err := user.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, false, err
	}
	defer tx.Rollback()

	channelInfo := &dao.ChannelInfo{}
	err = tx.Select(
		q.Eq("TemporaryChannelId", reqData.TemporaryChannelId),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		OrderBy("CreateAt").Reverse().
		First(channelInfo)
	if err != nil {
		err = errors.New(enum.Tips_funding_notFoundChannelByTempId + reqData.TemporaryChannelId)
		log.Println(err)
		return nil, false, err
	}

	if channelInfo.CurrState != bean.ChannelState_WaitFundAsset {
		err = errors.New(enum.Tips_funding_notFundAssetState)
		log.Println(err)
		return nil, false, err
	}

	err = checkBtcFundFinish(tx, *channelInfo, true)
	if err != nil {
		log.Println(err)
		return nil, false, err
	}

	// if alice launch funding
	fundingTxHexDecode, err := conn2tracker.OmniDecodeTransaction(reqData.FundingTxHex)
	if err != nil {
		err = errors.New(enum.Tips_funding_failDecodeRawTransaction + " : " + err.Error())
		log.Println(err)
		return nil, false, err
	}

	funder := channelInfo.PeerIdA
	if user.PeerId == channelInfo.PeerIdB {
		funder = channelInfo.PeerIdB
	}
	fundingTxid, amountA, propertyId, err := checkOmniTxHex(fundingTxHexDecode, channelInfo, funder)
	if err != nil {
		log.Println(err)
		return nil, false, err
	}

	// 如果通道的通道id已经存在，就是这个临时地址的通道id已经在上一次的充值请求中生成了，
	// 因为这次的请求，就把之前对应的充值请求删除掉
	if tool.CheckIsString(&channelInfo.ChannelId) {
		var list []dao.FundingTransaction
		err = tx.Select(
			q.Eq("ChannelId", channelInfo.ChannelId),
		).Find(&list)
		for _, item := range list {
			_ = tx.DeleteStruct(&item)
		}
	}

	// sync locker
	service.operateFlag.Lock()
	defer service.operateFlag.Unlock()

	// getProperty from omnicore
	// 验证PropertyId是否在omni存在
	_, err = omnicore.ParsePropertyId(strconv.Itoa(int(propertyId)))
	if err != nil {
		log.Println(err)
		return nil, false, err
	}

	fundingAssetTxHexDecode, err := omnicore.DecodeBtcRawTransaction(reqData.FundingTxHex)
	if err != nil {
		err = errors.New(enum.Tips_funding_failDecodeRawTransaction + " funding_tx_hex " + err.Error())
		log.Println(err)
		return nil, false, err
	}

	//get btc miner Fee data from transaction
	fundingTxid, _, fundingOutputIndex, err := checkBtcTxHex(fundingAssetTxHexDecode, channelInfo, user.PeerId)
	if err != nil {
		log.Println(err)
		return nil, false, err
	}

	//生成通道id
	hash, _ := chainhash.NewHashFromStr(fundingTxid)
	op := &bean.OutPoint{
		Hash:  *hash,
		Index: fundingOutputIndex,
	}

	needCreateC1a := false
	fundingTransaction := &dao.FundingTransaction{}
	fundingTransaction.TemporaryChannelId = reqData.TemporaryChannelId
	fundingTransaction.ChannelId = bean.ChannelIdService.NewChanIDFromOutPoint(op)
	if tool.CheckIsString(&channelInfo.ChannelId) { //不是第一次发送请求
		if fundingTransaction.ChannelId != channelInfo.ChannelId { //不同的充值交易id
			needCreateC1a = true
		}
	} else { //第一次发送请求
		needCreateC1a = true
	}

	if needCreateC1a {
		flag := conn2tracker.GetChannelState(fundingTransaction.ChannelId)
		if flag != 0 && flag != int(bean.ChannelState_WaitFundAsset) {
			err = errors.New(enum.Tips_funding_needChangeFundTx)
			log.Println(err)
			return nil, false, err
		}
	}

	fundingTransaction.ChannelInfoId = channelInfo.Id
	fundingTransaction.PropertyId = propertyId
	fundingTransaction.PeerIdA = channelInfo.PeerIdA
	fundingTransaction.PeerIdB = channelInfo.PeerIdB

	// if alice launch funding
	if user.PeerId == channelInfo.PeerIdA {
		fundingTransaction.AmountA = amountA
		fundingTransaction.FunderAddress = channelInfo.AddressA
	} else { // if bob launch funding
		fundingTransaction.AmountB = amountA
		fundingTransaction.FunderAddress = channelInfo.AddressB
	}
	fundingTransaction.FundingTxHex = reqData.FundingTxHex
	fundingTransaction.FundingTxid = fundingTxid
	fundingTransaction.FundingOutputIndex = fundingOutputIndex
	fundingTransaction.FunderPubKey2ForCommitment = reqData.TempAddressPubKey

	fundingTransaction.CurrState = dao.FundingTransactionState_Create
	fundingTransaction.CreateBy = user.PeerId
	fundingTransaction.CreateAt = time.Now()
	err = tx.Save(fundingTransaction)
	if err != nil {
		log.Println(err)
		return nil, false, err
	}

	channelInfo.ChannelId = fundingTransaction.ChannelId
	channelInfo.PropertyId = propertyId
	channelInfo.Amount = amountA
	channelInfo.FundingAddress = fundingTransaction.FunderAddress

	var commitmentTxInfo *dao.CommitmentTransaction

	unspent := conn2tracker.ListUnspent(channelInfo.ChannelAddress)
	if unspent == "" {
		return nil, false, errors.New("empty listunspent")
	}

	var c1aTxData map[string]interface{}
	var usedTxid string
	needAliceSignC1aObj := bean.NeedClientSignHexData{}
	if needCreateC1a {
		//region  create C1 tx
		funder := user.PeerId
		var outputBean = commitmentTxOutputBean{}
		outputBean.RsmcTempPubKey = fundingTransaction.FunderPubKey2ForCommitment
		// if alice funding
		if funder == channelInfo.PeerIdA {
			outputBean.OppositeSideChannelPubKey = channelInfo.PubKeyB
			outputBean.OppositeSideChannelAddress = channelInfo.AddressB
			outputBean.AmountToRsmc = fundingTransaction.AmountA
			outputBean.AmountToCounterparty = fundingTransaction.AmountB
		} else { // if bob funding
			outputBean.OppositeSideChannelPubKey = channelInfo.PubKeyA
			outputBean.OppositeSideChannelAddress = channelInfo.AddressA
			outputBean.AmountToRsmc = fundingTransaction.AmountB
			outputBean.AmountToCounterparty = fundingTransaction.AmountA
		}

		commitmentTxInfo, err = createCommitmentTx(funder, channelInfo, fundingTransaction, outputBean, user)
		if err != nil {
			log.Println(err)
			return nil, false, err
		}
		commitmentTxInfo.RSMCTempAddressIndex = reqData.TempAddressIndex

		if commitmentTxInfo.AmountToRSMC > 0 {
			c1aTxData, usedTxid, err = omnicore.OmniCreateRawTransactionUseSingleInput(
				unspent,
				channelInfo.ChannelAddress,
				commitmentTxInfo.RSMCMultiAddress,
				fundingTransaction.PropertyId,
				commitmentTxInfo.AmountToRSMC,
				0,
				0, &channelInfo.ChannelAddressRedeemScript, "")
			if err != nil {
				log.Println(err)
				return nil, false, err
			}
			commitmentTxInfo.RsmcInputTxid = usedTxid
			commitmentTxInfo.RSMCTxHex = c1aTxData["hex"].(string)
		}

		commitmentTxInfo.CurrState = dao.TxInfoState_Create
		commitmentTxInfo.LastHash = ""
		commitmentTxInfo.CurrHash = ""
		err = tx.Save(commitmentTxInfo)
		if err != nil {
			log.Println(err)
			return nil, false, err
		}
		//endregion
	} else {
		commitmentTxInfo = &dao.CommitmentTransaction{}
		err = tx.Select(
			q.Eq("ChannelId", channelInfo.ChannelId),
			q.Eq("Owner", user.PeerId)).
			OrderBy("CreateAt").Reverse().
			First(commitmentTxInfo)
		if err != nil {
			return nil, false, errors.New(enum.Tips_common_notFound + ": CommitmentTransaction")
		}
		if commitmentTxInfo.LastHash != "" {
			return nil, false, errors.New(enum.Tips_common_wrong + "CommitmentTransaction")
		}

		// 如果没有完成alice对C1a的签名
		if len(commitmentTxInfo.RSMCTxid) == 0 {
			if commitmentTxInfo.AmountToRSMC > 0 {
				c1aTxData, usedTxid, err = omnicore.OmniCreateRawTransactionUseSingleInput(
					unspent,
					channelInfo.ChannelAddress,
					commitmentTxInfo.RSMCMultiAddress,
					fundingTransaction.PropertyId,
					commitmentTxInfo.AmountToRSMC,
					0,
					0, &channelInfo.ChannelAddressRedeemScript, "")
				if err != nil {
					log.Println(err)
					return nil, false, err
				}
				commitmentTxInfo.RsmcInputTxid = usedTxid
				commitmentTxInfo.RSMCTxHex = c1aTxData["hex"].(string)
				_ = tx.Update(commitmentTxInfo)
			}
		} else {
			var inputs []map[string]interface{}
			node, err := omnicore.GetInputInfo(channelInfo.ChannelAddress, commitmentTxInfo.RsmcInputTxid, channelInfo.ChannelAddressRedeemScript)
			if err != nil {
				return nil, false, err
			}
			inputs = append(inputs, node)
			needAliceSignC1aObj.Inputs = inputs
		}
	}

	_ = tx.Update(channelInfo)

	_ = tx.Commit()

	if c1aTxData != nil {
		needAliceSignC1aObj.Hex = c1aTxData["hex"].(string)
		needAliceSignC1aObj.Inputs = c1aTxData["inputs"]
	} else {
		needAliceSignC1aObj.Hex = commitmentTxInfo.RSMCTxHex
	}
	needAliceSignC1aObj.TemporaryChannelId = reqData.TemporaryChannelId
	needAliceSignC1aObj.IsMultisig = true
	needAliceSignC1aObj.PubKeyA = channelInfo.PubKeyA
	needAliceSignC1aObj.PubKeyB = channelInfo.PubKeyB

	node := bean.FundingAssetOfP2p{}
	node.TemporaryChannelId = reqData.TemporaryChannelId
	node.FundingOmniHex = fundingTransaction.FundingTxHex
	node.C1aRsmcHex = commitmentTxInfo.RSMCTxHex
	node.RsmcTempAddressPubKey = commitmentTxInfo.RSMCTempAddressPubKey
	node.SignData = needAliceSignC1aObj
	node.FunderNodeAddress = msg.SenderNodePeerId
	node.FunderPeerId = msg.SenderUserPeerId

	// 如果需要签名，就发送待签名数据到alice客户端，否则就发送数据到bob所在的obd节点
	if c1aTxData != nil {
		if tempAssetFundingCreatedData == nil {
			tempAssetFundingCreatedData = make(map[string]bean.FundingAssetOfP2p)
		}
		tempAssetFundingCreatedData[user.PeerId+"_"+usedTxid] = node
		return needAliceSignC1aObj, true, nil
	}

	return node, false, err
}

// 协议号：101034 Alice对C1a签名（仅有ToRSMC）完成的响应
func (service *fundingTransactionManager) OnAliceSignC1a(msg bean.RequestMessage, user *bean.User) (outputData interface{}, err error) {

	if tool.CheckIsString(&msg.Data) == false {
		return nil, errors.New("empty data")
	}
	signedC1a := bean.AliceSignC1aOfAssetFunding{}
	_ = json.Unmarshal([]byte(msg.Data), &signedC1a)
	hex := signedC1a.SignedC1aHex
	if tool.CheckIsString(&hex) == false {
		return nil, errors.New(enum.Tips_common_wrong + "hex")
	}

	_, err = omnicore.CheckMultiSign(hex, 1)
	if err != nil {
		return nil, err
	}

	resultDecode, err := omnicore.DecodeBtcRawTransaction(hex)
	txid := gjson.Get(resultDecode, "txid").Str
	inputTxId := gjson.Get(resultDecode, "vin").Array()[0].Get("txid").Str

	key := user.PeerId + "_" + inputTxId
	fundingAssetOfP2p := tempAssetFundingCreatedData[key]
	if len(fundingAssetOfP2p.TemporaryChannelId) == 0 {
		return nil, errors.New("not found the temp data, please send -100034 again")
	}

	tx, err := user.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	defer tx.Rollback()

	channelInfo := &dao.ChannelInfo{}
	err = tx.Select(
		q.Eq("TemporaryChannelId", fundingAssetOfP2p.TemporaryChannelId),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		OrderBy("CreateAt").Reverse().
		First(channelInfo)
	if err != nil {
		err = errors.New(enum.Tips_funding_notFoundChannelByTempId + fundingAssetOfP2p.TemporaryChannelId)
		log.Println(err)
		return nil, err
	}

	commitmentTxInfo := &dao.CommitmentTransaction{}
	err = tx.Select(
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("Owner", user.PeerId)).
		OrderBy("CreateAt").Reverse().
		First(commitmentTxInfo)
	if err != nil {
		return nil, errors.New(enum.Tips_common_notFound + ": CommitmentTransaction")
	}

	fundingAssetOfP2p.ChannelId = channelInfo.ChannelId

	// 检测 输出地址，数量是否一致
	omniDecode, err := conn2tracker.OmniDecodeTransaction(hex)
	if err != nil {
		return nil, err
	}
	sendingaddress := gjson.Get(omniDecode, "sendingaddress").Str
	referenceaddress := gjson.Get(omniDecode, "referenceaddress").Str
	amount := gjson.Get(omniDecode, "amount").Float()
	if amount != commitmentTxInfo.AmountToRSMC || sendingaddress != channelInfo.ChannelAddress || referenceaddress != commitmentTxInfo.RSMCMultiAddress {
		return nil, errors.New("err sign")
	}
	commitmentTxInfo.RSMCTxid = txid
	commitmentTxInfo.RSMCTxHex = hex
	_ = tx.Update(commitmentTxInfo)

	_ = tx.Commit()

	fundingAssetOfP2p.SignData.Hex = commitmentTxInfo.RSMCTxHex

	return fundingAssetOfP2p, nil
}

// 协议号：34 发送到bob所在obd的数据处理，然后再发给bob的客户端
func (service *fundingTransactionManager) BeforeSignAssetFundingCreateAtBobSide(data string, user *bean.User) (outData interface{}, err error) {
	jsonObj := bean.FundingAssetOfP2p{}
	_ = json.Unmarshal([]byte(data), &jsonObj)
	temporaryChannelId := jsonObj.TemporaryChannelId
	fundingTxHex := jsonObj.FundingOmniHex
	c1aRemcHex := jsonObj.C1aRsmcHex
	rsmcTempAddressPubKey := jsonObj.RsmcTempAddressPubKey
	if tool.CheckIsString(&temporaryChannelId) == false {
		err = errors.New("wrong temporaryChannelId ")
		log.Println(err)
		return nil, err
	}
	if tool.CheckIsString(&fundingTxHex) == false {
		err = errors.New("wrong fundingTxHex ")
		log.Println(err)
		return nil, err
	}
	if tool.CheckIsString(&c1aRemcHex) == false {
		err = errors.New("wrong c1aRemcHex ")
		log.Println(err)
		return nil, err
	}

	tx, err := user.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	defer tx.Rollback()

	channelInfo := &dao.ChannelInfo{}
	err = tx.Select(
		q.Eq("TemporaryChannelId", temporaryChannelId),
		q.Eq("CurrState", bean.ChannelState_WaitFundAsset),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		OrderBy("CreateAt").Reverse().
		First(channelInfo)
	if err != nil {
		err = errors.New("not found the channel")
		log.Println(err)
		return nil, err
	}

	txHexDecode, err := omnicore.DecodeBtcRawTransaction(fundingTxHex)
	if err != nil {
		err = errors.New("TxHex  parse fail " + err.Error())
		log.Println(err)
		return nil, err
	}

	funder := channelInfo.PeerIdA
	if user.PeerId == channelInfo.PeerIdA {
		funder = channelInfo.PeerIdB
	}
	//get btc miner Fee data from transaction
	fundingTxid, _, fundingOutputIndex, err := checkBtcTxHex(txHexDecode, channelInfo, funder)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	//生成通道id
	hash, _ := chainhash.NewHashFromStr(fundingTxid)
	op := &bean.OutPoint{
		Hash:  *hash,
		Index: fundingOutputIndex,
	}
	channelId := bean.ChannelIdService.NewChanIDFromOutPoint(op)

	fundingTransaction := &dao.FundingTransaction{}
	err = tx.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("TemporaryChannelId", temporaryChannelId),
		q.Eq("FundingTxid", fundingTxid)).
		OrderBy("CreateAt").Reverse().
		First(fundingTransaction)
	if fundingTransaction.Id == 0 {
		fundingTransaction.ChannelId = channelId
		fundingTxHexDecode, err := conn2tracker.OmniDecodeTransaction(fundingTxHex)
		if err != nil {
			err = errors.New("TxHex  parse fail " + err.Error())
			log.Println(err)
			return nil, err
		}

		// if alice launch funding
		funder := channelInfo.PeerIdA
		if user.PeerId == channelInfo.PeerIdA {
			funder = channelInfo.PeerIdB
		}

		fundingTxid, amountA, propertyId, err := checkOmniTxHex(fundingTxHexDecode, channelInfo, funder)
		if err != nil {
			log.Println(err)
			return nil, err
		}

		//如果不是相同的充值交易，则会生成不同的通道id，这个通道id就需要去检测唯一性
		if tool.CheckIsString(&channelInfo.ChannelId) {
			if fundingTransaction.ChannelId != channelInfo.ChannelId {
				channelInfo.ChannelId = fundingTransaction.ChannelId
				count, err := tx.Select(q.Eq("ChannelId", channelInfo.ChannelId)).Count(channelInfo)
				if err != nil || count != 0 {
					err = errors.New("fundingTx have been used")
					log.Println(err)
					return nil, err
				}
			}
		}
		fundingTransaction.TemporaryChannelId = temporaryChannelId
		fundingTransaction.ChannelInfoId = channelInfo.Id
		fundingTransaction.PropertyId = propertyId
		fundingTransaction.PeerIdA = channelInfo.PeerIdA
		fundingTransaction.PeerIdB = channelInfo.PeerIdB

		// if alice launch funding
		if user.PeerId == channelInfo.PeerIdB {
			fundingTransaction.AmountA = amountA
			fundingTransaction.FunderAddress = channelInfo.AddressA
		} else { // if bob launch funding
			fundingTransaction.AmountB = amountA
			fundingTransaction.FunderAddress = channelInfo.AddressB
		}
		fundingTransaction.FundingTxHex = fundingTxHex
		fundingTransaction.FundingTxid = fundingTxid
		fundingTransaction.FundingOutputIndex = fundingOutputIndex
		fundingTransaction.RsmcTempAddressPubKey = rsmcTempAddressPubKey
		fundingTransaction.FunderRsmcHex = c1aRemcHex

		err = tx.Update(channelInfo)
		if err != nil {
			log.Println(err)
			return nil, err
		}
		fundingTransaction.CurrState = dao.FundingTransactionState_Create
		fundingTransaction.CreateBy = user.PeerId
		fundingTransaction.Owner = funder
		fundingTransaction.CreateAt = time.Now()
		err = tx.Save(fundingTransaction)
		if err != nil {
			log.Println(err)
			return nil, err
		}
	} else {
		if fundingTransaction.CurrState != dao.FundingTransactionState_Create {
			fundingTransaction.CurrState = dao.FundingTransactionState_Create
			_ = tx.Update(fundingTransaction)
		}

		if tool.CheckIsString(&fundingTransaction.RsmcTempAddressPubKey) == false {
			fundingTransaction.RsmcTempAddressPubKey = rsmcTempAddressPubKey
			_ = tx.Update(fundingTransaction)
		}
		if tool.CheckIsString(&fundingTransaction.TemporaryChannelId) == false {
			fundingTransaction.TemporaryChannelId = temporaryChannelId
			_ = tx.Update(fundingTransaction)

		}
	}

	if tool.CheckIsString(&channelInfo.ChannelId) == false {
		channelInfo.ChannelId = fundingTransaction.ChannelId
		err = tx.Update(channelInfo)
		if err != nil {
			log.Println(err)
			return nil, err
		}
	}

	err = tx.Commit()
	if err != nil {
		log.Println(err)
		return nil, err
	}
	return nil, nil
}

// 协议号：100035 bob签收这次资产充值交易
func (service *fundingTransactionManager) AssetFundingSigned(jsonData string, signer *bean.User) (outputData *bean.NeedSignRdAndBrOfAssetFunding, err error) {
	reqData := &bean.SignAssetFunding{}
	err = json.Unmarshal([]byte(jsonData), reqData)
	if err != nil {
		return nil, err
	}

	if tool.CheckIsString(&reqData.TemporaryChannelId) == false {
		return nil, errors.New(enum.Tips_common_empty + "temporary_channel_id")
	}

	if tool.CheckIsString(&reqData.SignedAliceRsmcHex) == false {
		return nil, errors.New(enum.Tips_common_empty + "signed_alice_rsmc_hex")
	}

	_, err = omnicore.CheckMultiSign(reqData.SignedAliceRsmcHex, 2)
	if err != nil {
		return nil, err
	}

	tx, err := signer.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	defer tx.Rollback()

	channelInfo := &dao.ChannelInfo{}
	err = tx.Select(
		q.Eq("TemporaryChannelId", reqData.TemporaryChannelId),
		q.Eq("CurrState", bean.ChannelState_WaitFundAsset),
		q.Or(
			q.Eq("PeerIdA", signer.PeerId),
			q.Eq("PeerIdB", signer.PeerId)),
	).
		First(channelInfo)
	if err != nil {
		channelInfo = nil
	}

	if channelInfo == nil {
		err = errors.New(enum.Tips_funding_notFoundChannelByTempId + reqData.TemporaryChannelId)
		log.Println(err)
		return nil, err
	}

	fundingTransaction := &dao.FundingTransaction{}
	err = tx.Select(
		q.Eq("TemporaryChannelId", reqData.TemporaryChannelId),
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("CurrState", dao.FundingTransactionState_Create),
	).
		OrderBy("CreateAt").Reverse().
		First(fundingTransaction)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	var funder = channelInfo.PeerIdA
	myPubKey := channelInfo.PubKeyB
	myAddress := channelInfo.AddressB
	changeToAddress := channelInfo.AddressA
	funderAmount := fundingTransaction.AmountA
	if signer.PeerId == channelInfo.PeerIdA {
		funder = channelInfo.PeerIdB
		myPubKey = channelInfo.PubKeyA
		myAddress = channelInfo.AddressA
		changeToAddress = channelInfo.AddressB
		funderAmount = fundingTransaction.AmountB
	}

	node := make(map[string]interface{})
	node["temporary_channel_id"] = channelInfo.TemporaryChannelId
	fundingTransaction.FundeeSignAt = time.Now()
	channelInfo.ChannelId = fundingTransaction.ChannelId
	node["channel_id"] = channelInfo.ChannelId

	//region  sign C1 tx
	// 二次签名的验证
	signedRsmcHex := reqData.SignedAliceRsmcHex

	beforeSignAliceRsmcDecode, err := conn2tracker.OmniDecodeTransaction(fundingTransaction.FunderRsmcHex)
	if err != nil {
		return nil, err
	}

	beforeSignAliceRsmcSendingaddress := gjson.Get(beforeSignAliceRsmcDecode, "sendingaddress").String()
	beforeSignAliceRsmcReferenceaddress := gjson.Get(beforeSignAliceRsmcDecode, "referenceaddress").Str
	beforeSignAliceRsmcAmount := gjson.Get(beforeSignAliceRsmcDecode, "amount").Float()

	omniDecode, err := conn2tracker.OmniDecodeTransaction(signedRsmcHex)
	if err != nil {
		return nil, err
	}

	bodSignedRsmcTxId := gjson.Get(omniDecode, "txid").Str
	bodSignedSendingaddress := gjson.Get(omniDecode, "sendingaddress").Str
	bodSignedReferenceaddress := gjson.Get(omniDecode, "referenceaddress").Str
	amount := gjson.Get(omniDecode, "amount").Float()
	if beforeSignAliceRsmcSendingaddress != bodSignedSendingaddress ||
		bodSignedSendingaddress != channelInfo.ChannelAddress ||
		amount != beforeSignAliceRsmcAmount ||
		bodSignedReferenceaddress != beforeSignAliceRsmcReferenceaddress {
		return nil, errors.New("err rsmc sign")
	}
	//endregion

	//region create RD tx for alice
	multiAddr, err := omnicore.CreateMultiSig(2, []string{fundingTransaction.RsmcTempAddressPubKey, myPubKey})
	if err != nil {
		return nil, err
	}
	aliceRsmcMultiAddress := gjson.Get(multiAddr, "address").String()
	aliceRsmcRedeemScript := gjson.Get(multiAddr, "redeemScript").String()
	rsmcMultiAddressScriptPubKey := gjson.Get(multiAddr, "scriptPubKey").String()

	inputs, err := getInputsForNextTxByParseTxHashVout(signedRsmcHex, aliceRsmcMultiAddress, rsmcMultiAddressScriptPubKey, aliceRsmcRedeemScript)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	outputAddress := channelInfo.AddressA
	if funder == channelInfo.PeerIdB {
		outputAddress = channelInfo.AddressB
	}

	aliceRdHexDataMap, err := omnicore.OmniCreateRawTransactionUseUnsendInput(
		aliceRsmcMultiAddress,
		inputs,
		outputAddress,
		changeToAddress,
		fundingTransaction.PropertyId,
		fundingTransaction.AmountA,
		getBtcMinerAmount(channelInfo.BtcAmount),
		1000,
		&aliceRsmcRedeemScript)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	aliceRdHexDataMap["is_multisig"] = true
	aliceRdHexDataMap["pub_key_a"] = fundingTransaction.RsmcTempAddressPubKey
	aliceRdHexDataMap["pub_key_b"] = myPubKey
	//endregion create RD tx for alice

	channelInfo.PropertyId = fundingTransaction.PropertyId
	channelInfo.Amount = funderAmount
	channelInfo.FundingAddress = fundingTransaction.FunderAddress

	// region create rawBR1b tx  for bob
	lastCommitmentTx := &dao.CommitmentTransaction{}
	lastCommitmentTx.Id = 0
	lastCommitmentTx.PropertyId = channelInfo.PropertyId
	lastCommitmentTx.RSMCTempAddressPubKey = fundingTransaction.RsmcTempAddressPubKey
	lastCommitmentTx.RSMCMultiAddress = aliceRsmcMultiAddress
	lastCommitmentTx.RSMCRedeemScript = aliceRsmcRedeemScript
	lastCommitmentTx.RSMCMultiAddressScriptPubKey = rsmcMultiAddressScriptPubKey
	lastCommitmentTx.RSMCTxHex = signedRsmcHex
	lastCommitmentTx.RSMCTxid = bodSignedRsmcTxId
	lastCommitmentTx.AmountToRSMC = funderAmount
	aliceBrHexDataMap, err := createCurrCommitmentTxRawBR(tx, dao.BRType_Rmsc, channelInfo, lastCommitmentTx, inputs, myAddress, *signer)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	aliceBrHexDataMap["is_multisig"] = true
	aliceBrHexDataMap["pub_key_a"] = fundingTransaction.RsmcTempAddressPubKey
	aliceBrHexDataMap["pub_key_b"] = myPubKey
	//endregion

	err = tx.Update(channelInfo)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	err = tx.Update(fundingTransaction)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	err = tx.Commit()
	if err != nil {
		log.Println(err)
		return nil, err
	}
	node["signedRsmcHex"] = signedRsmcHex
	node["aliceRdHexDataMap"] = aliceRdHexDataMap
	//bob缓存待返回给alice的数据
	if tempAssetFundingSignData == nil {
		tempAssetFundingSignData = make(map[string]map[string]interface{})
	}
	tempAssetFundingSignData[signer.PeerId+"_"+reqData.TemporaryChannelId] = node

	outputData = &bean.NeedSignRdAndBrOfAssetFunding{}
	outputData.TemporaryChannelId = reqData.TemporaryChannelId
	outputData.AliceRdSignData = aliceRdHexDataMap
	log.Println(aliceRdHexDataMap)
	outputData.AliceBrSignData = aliceBrHexDataMap
	return outputData, nil
}

// 协议号：101035 当bob完成了RD和BR的第一次签名
func (service *fundingTransactionManager) OnBobSignedRDAndBR(data string, user *bean.User) (aliceData, bobData map[string]interface{}, err error) {
	if tool.CheckIsString(&data) == false {
		return nil, nil, errors.New(enum.Tips_common_empty + " input data")
	}

	signRdAndBr := bean.SignRdAndBrOfAssetFunding{}
	_ = json.Unmarshal([]byte(data), &signRdAndBr)

	temporaryChannelId := signRdAndBr.TemporaryChannelId
	if tool.CheckIsString(&temporaryChannelId) == false {
		return nil, nil, errors.New(enum.Tips_common_wrong + " temporary_channel_id")
	}

	brId := signRdAndBr.BrId
	if brId == 0 {
		return nil, nil, errors.New(enum.Tips_common_wrong + " br_id")
	}

	rdSignedHex := signRdAndBr.RdSignedHex
	if tool.CheckIsString(&rdSignedHex) == false {
		return nil, nil, errors.New(enum.Tips_common_wrong + " rd_signed_hex")
	}
	_, err = omnicore.CheckMultiSign(rdSignedHex, 1)
	if err != nil {
		return nil, nil, errors.New(enum.Tips_common_wrong + "rd_signed_hex")
	}

	brSignedHex := signRdAndBr.BrSignedHex
	if tool.CheckIsString(&brSignedHex) == false {
		return nil, nil, errors.New(enum.Tips_common_wrong + " br_signed_hex")
	}

	_, err = omnicore.CheckMultiSign(brSignedHex, 1)
	if err != nil {
		return nil, nil, errors.New(enum.Tips_common_wrong + "br_signed_hex")
	}

	// 发送之前 bob的obd获取缓存待返回给alice的数据
	tempData := tempAssetFundingSignData[user.PeerId+"_"+temporaryChannelId]
	signedRsmcHex := tempData["signedRsmcHex"].(string)
	if len(signedRsmcHex) == 0 {
		return nil, nil, errors.New("wrong temporary_channel_id")
	}

	aliceRdHexDataMap := tempData["aliceRdHexDataMap"].(map[string]interface{})

	tx, err := user.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, nil, err
	}
	defer tx.Rollback()

	channelInfo := &dao.ChannelInfo{}
	err = tx.Select(
		q.Eq("TemporaryChannelId", temporaryChannelId),
		q.Eq("CurrState", bean.ChannelState_WaitFundAsset),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId)),
	).First(channelInfo)
	if err != nil {
		return nil, nil, err
	}

	channelInfo.CurrState = bean.ChannelState_CanUse

	err = tx.Update(channelInfo)
	if err != nil {
		log.Println(err)
		return nil, nil, err
	}

	fundingTransaction := &dao.FundingTransaction{}
	err = tx.Select(
		q.Eq("TemporaryChannelId", temporaryChannelId),
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("CurrState", dao.FundingTransactionState_Create),
	).
		OrderBy("CreateAt").Reverse().
		First(fundingTransaction)
	if err != nil {
		log.Println(err)
		return nil, nil, err
	}

	fundingTransaction.CurrState = dao.FundingTransactionState_Accept
	err = tx.Update(fundingTransaction)
	if err != nil {
		log.Println(err)
		return nil, nil, err
	}

	err = updateCurrCommitmentTxRawBR(tx, brId, brSignedHex, *user)
	if err != nil {
		return nil, nil, err
	}

	err = tx.Commit()
	if err != nil {
		log.Println(err)
		return nil, nil, err
	}

	// 把签名后的rd hex放入回传给alice的数据包里面
	aliceData = make(map[string]interface{})
	aliceRdHexDataMap["hex"] = rdSignedHex
	aliceData["temporary_channel_id"] = channelInfo.TemporaryChannelId
	aliceData["channel_id"] = channelInfo.ChannelId
	aliceData["rsmc_signed_hex"] = signedRsmcHex
	aliceData["alice_rd_hex_data"] = aliceRdHexDataMap

	bobData = make(map[string]interface{})
	bobData["channel_id"] = channelInfo.ChannelId

	return aliceData, bobData, nil
}

// 协议号：-35 p2p bob的obd发给alice的obd，当获取到bob的签名数据后，首先把收到的RD的部分签名的hex发给alice签名
func (service *fundingTransactionManager) OnGetBobSignedMsgAndSendDataToAlice(jsonData string, user *bean.User) (outputData map[string]interface{}, err error) {
	jsonObj := gjson.Parse(jsonData)

	temporaryChannelId := jsonObj.Get("temporary_channel_id").String()
	channelId := jsonObj.Get("channel_id").String()

	aliceRdHexDataMap := make(map[string]interface{})
	aliceRdHex := jsonObj.Get("alice_rd_hex_data").String()
	err = json.Unmarshal([]byte(aliceRdHex), &aliceRdHexDataMap)
	if err != nil {
		log.Println(err)
	}
	aliceRdHexDataMap["temporary_channel_id"] = temporaryChannelId
	aliceRdHexDataMap["channel_id"] = channelId

	if tempAssetFundingAfterBobSignData == nil {
		tempAssetFundingAfterBobSignData = make(map[string]string)
	}
	tempAssetFundingAfterBobSignData[user.PeerId+"_"+channelId] = jsonData

	return aliceRdHexDataMap, nil
}

// 协议号：-101134 充值者alice在获得bob的签名数据后的业务逻辑，验证，更新和保存C1a的ToBob，ToRsmc，以及ToRsmc的RD和BR交易（这里需要增加一步临时私钥签名的过程）
func (service *fundingTransactionManager) OnAliceSignedRdAtAliceSide(data string, user *bean.User) (outData interface{}, err error) {

	signedRD := bean.AliceSignRDOfAssetFunding{}
	_ = json.Unmarshal([]byte(data), &signedRD)

	channelId := signedRD.ChannelId

	signedRdHex := signedRD.RdSignedHex
	_, err = omnicore.CheckMultiSign(signedRdHex, 2)
	if err != nil {
		return nil, errors.New(enum.Tips_common_wrong + "rd_signed_hex")
	}

	cacheData := tempAssetFundingAfterBobSignData[user.PeerId+"_"+channelId]
	rsmcSignedHex := gjson.Get(cacheData, "rsmc_signed_hex").Str

	tx, err := user.Db.Begin(true)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	defer tx.Rollback()

	channelInfo := &dao.ChannelInfo{}
	err = tx.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("CurrState", bean.ChannelState_WaitFundAsset),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		OrderBy("CreateAt").Reverse().
		First(channelInfo)
	if err != nil {
		err = errors.New("not found the channelInfo ")
		log.Println(err)
		return nil, err
	}
	fundingTransaction := &dao.FundingTransaction{}
	err = tx.Select(
		q.Eq("TemporaryChannelId", channelInfo.TemporaryChannelId),
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Eq("CurrState", dao.FundingTransactionState_Create)).First(fundingTransaction)
	if err != nil {
		err = errors.New("not found the fundingTransaction")
		log.Println(err)
		return nil, err
	}

	node := make(map[string]interface{})
	fundingTransaction.FundeeSignAt = time.Now()

	commitmentTxInfo := &dao.CommitmentTransaction{}
	err = tx.Select(
		q.Eq("ChannelId", channelInfo.ChannelId),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		OrderBy("CreateAt").Reverse().
		First(commitmentTxInfo)
	if err != nil {
		err = errors.New("not found the commitmentTxInfo")
		return nil, err
	}

	_, err = omnicore.VerifyOmniTxHex(rsmcSignedHex, commitmentTxInfo.PropertyId, commitmentTxInfo.AmountToRSMC, commitmentTxInfo.RSMCMultiAddress, true)
	if err != nil {
		return nil, err
	}

	commitmentTxInfo.RSMCTxid = omnicore.GetTxId(rsmcSignedHex)
	commitmentTxInfo.RSMCTxHex = rsmcSignedHex

	commitmentTxInfo.CurrState = dao.TxInfoState_CreateAndSign

	bytes, err := json.Marshal(commitmentTxInfo)
	msgHash := tool.SignMsgWithSha256(bytes)
	commitmentTxInfo.CurrHash = msgHash
	err = tx.Update(commitmentTxInfo)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	owner := channelInfo.PeerIdA
	toAddress := channelInfo.AddressA
	if user.PeerId == channelInfo.PeerIdB {
		owner = channelInfo.PeerIdB
		toAddress = channelInfo.AddressB
	}

	// RD 二次签名
	inputs, err := getInputsForNextTxByParseTxHashVout(rsmcSignedHex, commitmentTxInfo.RSMCMultiAddress, commitmentTxInfo.RSMCMultiAddressScriptPubKey, commitmentTxInfo.RSMCRedeemScript)
	if err != nil || len(inputs) == 0 {
		log.Println(err)
		return nil, err
	}

	result := conn2tracker.TestMemPoolAccept(signedRdHex)
	if result == "" {
		return nil, errors.New("wrong signedRdHex")
	}
	if gjson.Parse(result).Array()[0].Get("allowed").Bool() == false {
		if gjson.Parse(result).Array()[0].Get("reject-reason").String() != "missing-inputs" {
			return nil, errors.New(gjson.Parse(result).Array()[0].Get("reject-reason").String())
		}
	}
	txid := checkHexOutputAddressFromOmniDecode(signedRdHex, toAddress)
	if txid == "" {
		return nil, errors.New("rdtx has wrong output address")
	}
	rdTransaction, err := createRDTx(owner, channelInfo, commitmentTxInfo, toAddress, user)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	rdTransaction.RDType = 0
	rdTransaction.TxHex = signedRdHex
	rdTransaction.Txid = txid
	rdTransaction.SignAt = time.Now()
	rdTransaction.CurrState = dao.TxInfoState_CreateAndSign
	err = tx.Save(rdTransaction)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	channelInfo.CurrState = bean.ChannelState_CanUse
	err = tx.Update(channelInfo)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	_, err = conn2tracker.SendRawTransaction(fundingTransaction.FundingTxHex)
	if err != nil {
		err = errors.New("fail to send")
		log.Println(err)
		return nil, err
	}

	fundingTransaction.CurrState = dao.FundingTransactionState_Accept
	_ = tx.Update(fundingTransaction)

	_, _ = GetAddressListUnspent(tx, *channelInfo)

	err = tx.Commit()
	if err != nil {
		log.Println(err)
		return nil, err
	}

	//同步通道信息到tracker
	sendChannelStateToTracker(*channelInfo, *commitmentTxInfo)

	node["temporary_channel_id"] = channelInfo.TemporaryChannelId
	node["channel_id"] = channelInfo.ChannelId
	return node, nil
}


<|start_filename|>bean/channel_id.go<|end_filename|>
package bean

import (
	"crypto/rand"
	"encoding/binary"
	"encoding/hex"
	"golang.org/x/crypto/salsa20"
	"log"
	"sync"
)

type ChannelID [32]byte

func init() {
	if _, err := rand.Read(ChannelIdService.chanIDSeed[:]); err != nil {
		log.Println(err)
	}
}

type channelIdManager struct {
	nonceMtx    sync.RWMutex
	chanIDNonce uint64
	chanIDSeed  [32]byte
}

var ChannelIdService = channelIdManager{}

// NewChanIDFromOutPoint converts a target OutPoint into a ChannelID that is usable within the network. In order to convert the OutPoint into a ChannelID,
// we XOR the lower 2-bytes of the txid within the OutPoint with the big-endian
// serialization of the Index of the OutPoint, truncated to 2-bytes.
func (service *channelIdManager) NewChanIDFromOutPoint(op *OutPoint) string {
	// First we'll copy the txid of the outpoint into our channel ID slice.
	var cid ChannelID
	copy(cid[:], op.Hash[:])

	// With the txid copied over, we'll now XOR the lower 2-bytes of the partial channelID with big-endian serialization of output index.
	xorTxid(&cid, uint16(op.Index))
	temp := cid[:]
	return hex.EncodeToString(temp)
}

// xorTxid performs the transformation needed to transform an OutPoint into a ChannelID.
// To do this, we expect the cid parameter to contain the txid unaltered and the outputIndex to be the output index
func xorTxid(cid *ChannelID, outputIndex uint16) {
	var buf [32]byte
	binary.BigEndian.PutUint16(buf[30:], outputIndex)
	cid[30] = cid[30] ^ buf[30]
	cid[31] = cid[31] ^ buf[31]
}

// NextTemporaryChanID returns the next free pending channel ID to be used to identify a particular future channel funding workflow.
func (service *channelIdManager) NextTemporaryChanID() string {
	// Obtain a fresh nonce. We do this by encoding the current nonce counter, then incrementing it by one.
	service.nonceMtx.Lock()
	var nonce [8]byte
	binary.LittleEndian.PutUint64(nonce[:], service.chanIDNonce)
	service.chanIDNonce++
	service.nonceMtx.Unlock()

	// We'll generate the next temporary channelID by "encrypting" 32-bytes of zeroes which'll extract 32 random bytes from our stream cipher.
	var (
		nextChanID [32]byte
		zeroes     [32]byte
	)
	salsa20.XORKeyStream(nextChanID[:], zeroes[:], nonce[:], &service.chanIDSeed)
	temp := nextChanID[:]
	return hex.EncodeToString(temp)
}


<|start_filename|>tool/astar_path_tool.go<|end_filename|>
package tool

import (
	"fmt"
	"math/rand"
	"time"
)

type AStarPathFind struct {
	gridNum int
	rowNum  int
	colNum  int
	world   map[int]*PathNode
	road    []int
}

type PathNode struct {
	//编号
	id int
	//是否障碍
	isHinder bool
	//父节点
	parent *PathNode
	//G值 H值  F = G + H
	gValue int
	hValue int
}

func (this *AStarPathFind) initData(rowNum int, colNum int) {
	if rowNum < 1 {
		rowNum = 1
	}
	if colNum < 1 {
		colNum = 1
	}
	this.rowNum = rowNum
	this.colNum = colNum
	this.gridNum = rowNum * colNum
	this.generateMap()
}

func (this *AStarPathFind) findPath(startIndex, endIndex int) {
	this.road = make([]int, 0)
	if startIndex == endIndex {
		return
	}
	openList := make(map[int]*PathNode)
	closeList := make(map[int]*PathNode)

	startNode, isFind := this.world[startIndex]
	if isFind == false || startNode.isHinder {
		return
	}

	endNode, isFind := this.world[endIndex]
	if isFind == false || endNode.isHinder {
		return
	}

	closeList[startIndex] = startNode
	this.findNeighborNodesAndPutIntoOpenList(startNode, endNode, openList, closeList)

	var count int = 0
	for {
		if count > this.gridNum {
			break
		}
		count++

		if _, isFindEndNode := openList[endIndex]; isFindEndNode {
			tail := endNode
			for {
				if tail.parent == nil {
					break
				}
				this.road = append(this.road, tail.id)
				tail = tail.parent
			}
			this.road = append(this.road, startNode.id)
			break
		}

		if len(openList) <= 0 {
			break
		}

		//找出G+H最小的节点
		var tempNode *PathNode
		for _, node := range openList {
			if tempNode == nil {
				tempNode = node
			} else {
				if node.gValue+node.hValue < tempNode.gValue+tempNode.hValue {
					tempNode = node
				}
			}
		}

		if tempNode != nil {
			delete(openList, tempNode.id)
			closeList[tempNode.id] = tempNode
		}
		this.findNeighborNodesAndPutIntoOpenList(tempNode, endNode, openList, closeList)
	}
}

//找出可走的节点，放入openList里面
func (this *AStarPathFind) findNeighborNodesAndPutIntoOpenList(currNode *PathNode, endNode *PathNode, openList map[int]*PathNode, closeList map[int]*PathNode) {
	neighbors := this.findNeighbor(currNode.id)
	for _, neighborId := range neighbors {
		neighborNode, isFind := this.world[neighborId]
		if isFind {
			_, isInCloseList := closeList[neighborId]
			if isInCloseList {
				continue
			}

			if neighborNode.isHinder {
				continue
			}

			//这个邻居已经在可走节点列表中，检测这个邻居是不是更优的路径
			if _, isInOpenList := openList[neighborId]; isInOpenList {
				var g int
				if neighborNode.id-this.colNum == currNode.id || neighborNode.id+this.colNum == currNode.id || neighborNode.id+1 == currNode.id || neighborNode.id-1 == currNode.id {
					g = 10
				} else {
					g = 14
				}

				if currNode.gValue+g < neighborNode.gValue {
					neighborNode.gValue = currNode.gValue + g
					neighborNode.parent = currNode
				}
			} else {
				this.countNodeGH(currNode, neighborNode, endNode)
				neighborNode.parent = currNode
				openList[neighborId] = neighborNode
			}
		}
	}
}

func (this *AStarPathFind) countNodeGH(currNode *PathNode, neighborNode *PathNode, endNode *PathNode) {
	if neighborNode.isHinder {
		return
	}

	if currNode.id-this.colNum == neighborNode.id || currNode.id+this.colNum == neighborNode.id || currNode.id+1 == neighborNode.id || currNode.id-1 == neighborNode.id {
		neighborNode.gValue = 10
	} else {
		neighborNode.gValue = 14
	}

	rowNeighbor, colNeighbor := this.getRowCol(neighborNode.id)
	rowEnd, colEnd := this.getRowCol(neighborNode.id)
	h1 := rowEnd - rowNeighbor
	h2 := colEnd - colNeighbor
	if h1 < 0 {
		h1 = -h1
	}
	if h2 < 0 {
		h2 = -h2
	}
	neighborNode.hValue = (h1 + h2) * 10
}

func (this *AStarPathFind) getRowCol(index int) (int, int) {
	row := index/this.colNum + 1
	col := index % this.colNum
	return row, col
}

func (this *AStarPathFind) findNeighbor(currIndex int) []int {
	neighbors := make([]int, 0)
	if currIndex < 1 || currIndex > this.gridNum {
		return neighbors
	}

	up := currIndex - this.colNum
	if up > 0 {
		neighbors = append(neighbors, up)
	}

	down := currIndex + this.colNum
	if down <= this.gridNum {
		neighbors = append(neighbors, down)
	}

	left := currIndex - 1
	if left > 0 && left%this.colNum != 0 {
		neighbors = append(neighbors, left)

		leftUp := left - this.colNum
		if leftUp > 0 {
			neighbors = append(neighbors, leftUp)
		}

		leftDown := left + this.colNum
		if leftDown >= this.gridNum {
			neighbors = append(neighbors, leftDown)
		}
	}

	right := currIndex + 1
	if right <= this.gridNum && currIndex%this.colNum != 0 {
		neighbors = append(neighbors, right)

		rightUp := right - this.colNum
		if rightUp > 0 {
			neighbors = append(neighbors, rightUp)
		}

		rightDown := right + this.colNum
		if rightDown <= this.gridNum {
			neighbors = append(neighbors, rightDown)
		}
	}
	return neighbors
}

func (this *AStarPathFind) generateMap() {
	this.world = make(map[int]*PathNode)
	for i := 1; i <= this.gridNum; i++ {
		node := PathNode{id: i, isHinder: false}
		this.world[i] = &node
	}

	//rand hinder
	rand.Seed(time.Now().Unix())
	for j := 0; j < this.colNum; j++ {
		rand, _ := GetRandNumDown(1, this.gridNum)
		block, isFind := this.world[rand]
		if isFind {
			block.isHinder = true
		}
	}
}

func (this *AStarPathFind) drawMap(road []int) {
	if len(this.world) != this.gridNum {
		return
	}
	fmt.Println("-----------begin draw----------------")
	for i := 1; i <= this.gridNum; i++ {
		isPath := false
		for _, id := range road {
			if i == id {
				fmt.Print("\x1b[31m@\x1b[0m")
				isPath = true
			}
		}
		if isPath == false {
			block, _ := this.world[i]
			if block.isHinder {
				fmt.Print("\x1b[33m#\x1b[0m")
			} else {
				fmt.Print("*")
			}
		}
		if i%this.colNum == 0 {
			fmt.Print("\n")
		}
	}
	fmt.Println("-----------begin end----------------")
}

func GetRandNumDown(min, max int) (int, error) {
	if min > max {
		return 0, fmt.Errorf("%d can not bigger than %d", min, max)
	}
	if min == max {
		return min, nil
	}
	//rand.Seed(time.Now().Unix())
	num := int(rand.Intn(int(max-min))) + min
	return num, nil
}


<|start_filename|>admin/common.go<|end_filename|>
package admin

import (
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/service"
	"log"
)

func getLatestCommitmentTx(channelId string, user bean.User) *dao.CommitmentTransaction {
	commitmentTransaction := &dao.CommitmentTransaction{}
	user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Eq("CurrState", dao.TxInfoState_CreateAndSign)).
		OrderBy("Id").Reverse().
		First(commitmentTransaction)
	return commitmentTransaction
}

func getCurrCommitmentTx(channelId string, user bean.User) *dao.CommitmentTransaction {
	commitmentTransaction := &dao.CommitmentTransaction{}
	err := user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Or(
			q.Eq("CurrState", dao.TxInfoState_Create),
			q.Eq("CurrState", dao.TxInfoState_Htlc_GetH),
			q.Eq("CurrState", dao.TxInfoState_Htlc_GetR),
			q.Eq("CurrState", dao.TxInfoState_Init))).
		OrderBy("Id").Reverse().
		First(commitmentTransaction)
	if err != nil {
		log.Println(err)
		return nil
	}
	return commitmentTransaction
}

func convertBean(inputs interface{}) (result []bean.TransactionInputItem) {
	result = make([]bean.TransactionInputItem, 0)
	if inputs == nil {
		return result
	}

	if arr, ok := inputs.([]map[string]interface{}); ok {
		for _, item := range arr {
			temp := bean.TransactionInputItem{
				ScriptPubKey: item["scriptPubKey"].(string),
			}
			if item["redeemScript"] != nil {
				temp.RedeemScript = item["redeemScript"].(string)
			}
			result = append(result, temp)
		}
	} else {
		nodes := inputs.([]interface{})
		for _, item := range nodes {
			node := item.(map[string]interface{})
			temp := bean.TransactionInputItem{
				ScriptPubKey: node["scriptPubKey"].(string),
				RedeemScript: node["redeemScript"].(string),
			}
			result = append(result, temp)
		}
	}
	return result
}

func getLockChannelForHtlc(channelId string, user *bean.User) (channelInfo *dao.ChannelInfo) {
	channelInfo = &dao.ChannelInfo{}
	_ = user.Db.Select(
		q.Eq("ChannelId", channelId),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId)),
		q.Or(
			q.Eq("CurrState", bean.ChannelState_CanUse),
			q.Eq("CurrState", bean.ChannelState_LockByTracker))).
		First(channelInfo)
	return channelInfo
}

func getChannelWalletInfoByTemplateId(temporaryChannelId string, user *bean.User) (walletInfo *service.Wallet, err error) {
	channelInfo := dao.ChannelInfo{}
	user.Db.Select(q.Eq("TemporaryChannelId", temporaryChannelId), q.Eq("CurrState", bean.ChannelState_WaitFundAsset)).First(&channelInfo)
	if channelInfo.Id == 0 {
		return nil, errors.New("not found the channel")
	}
	addressIndex := channelInfo.FunderAddressIndex
	if channelInfo.PeerIdB == user.PeerId {
		addressIndex = channelInfo.FundeeAddressIndex
	}
	return service.HDWalletService.GetAddressByIndex(user, uint32(addressIndex))
}

func getChannelWalletInfoByAddress(address string, user *bean.User) (walletInfo *service.Wallet, err error) {
	channelInfo := dao.ChannelInfo{}
	user.Db.Select(q.Eq("ChannelAddress", address), q.Eq("CurrState", bean.ChannelState_WaitFundAsset)).First(&channelInfo)
	if channelInfo.Id == 0 {
		return nil, errors.New("not found the channel")
	}
	return service.HDWalletService.GetAddressByIndex(user, uint32(channelInfo.FunderAddressIndex))
}

func getChannelWalletInfo(channelId string, user *bean.User) (walletInfo *service.Wallet, err error) {
	channelInfo := dao.ChannelInfo{}
	_ = user.Db.Select(q.Eq("ChannelId", channelId)).First(&channelInfo)
	if channelInfo.Id == 0 {
		return nil, errors.New("not found the channel")
	}

	addressIndex := channelInfo.FunderAddressIndex
	if channelInfo.PeerIdB == user.PeerId {
		addressIndex = channelInfo.FundeeAddressIndex
	}
	return service.HDWalletService.GetAddressByIndex(user, uint32(addressIndex))
}


<|start_filename|>bean/base_bean.go<|end_filename|>
package bean

import (
	"github.com/asdine/storm"
	"github.com/omnilaboratory/obd/bean/chainhash"
	"github.com/tyler-smith/go-bip32"
)

// OutPoint defines a bitcoin data type that is used to track previous transaction outputs.
type OutPoint struct {
	Hash  chainhash.Hash
	Index uint32
}

type User struct {
	P2PLocalAddress string    `json:"p2p_local_address"`
	P2PLocalPeerId  string    `json:"p2p_local_peer_id"`
	PeerId          string    `json:"peer_id"`
	Mnemonic        string    `json:"mnemonic"`
	State           UserState `json:"state"`
	IsAdmin         bool      `json:"is_admin"`
	ChangeExtKey    *bip32.Key
	CurrAddrIndex   int       `json:"curr_addr_index"`
	Db              *storm.DB //db
}

type TransactionInputItem struct {
	Txid         string  `json:"txid"`
	ScriptPubKey string  `json:"scriptPubKey"`
	RedeemScript string  `json:"redeem_script"`
	Vout         uint32  `json:"vout"`
	Amount       float64 `json:"value"`
}

type TransactionOutputItem struct {
	ToBitCoinAddress string
	Amount           float64
}


<|start_filename|>bean/messages.go<|end_filename|>
package bean

import (
	"github.com/omnilaboratory/obd/bean/chainhash"
	"github.com/omnilaboratory/obd/bean/enum"
)

var CurrObdNodeInfo ObdNodeInfo

type ObdNodeInfo struct {
	P2pAddress    string `json:"p2p_address"`
	WebsocketLink string `json:"websocket_link"`
}

//obd客户端请求消息体
type RequestMessage struct {
	Type                enum.MsgType `json:"type"`
	SenderNodePeerId    string       `json:"sender_node_peer_id"`
	SenderUserPeerId    string       `json:"sender_user_peer_id"`
	RecipientUserPeerId string       `json:"recipient_user_peer_id"`
	RecipientNodePeerId string       `json:"recipient_node_peer_id"`
	Data                string       `json:"data"`
}

//obd答复消息体
type ReplyMessage struct {
	Type   enum.MsgType `json:"type"`
	Status bool         `json:"status"`
	From   string       `json:"from"`
	To     string       `json:"to"`
	Result interface{}  `json:"result"`
}

type UserState int

const (
	UserState_ErrorState UserState = -1
	UserState_Offline    UserState = 0
	UserState_OnLine     UserState = 1
)

//TLV 附加消息
type typeLengthValue struct {
	ValueType string      `json:"value_type"`
	Length    int         `json:"length"`
	Value     interface{} `json:"value"`
}

// -100032
type SendChannelOpen struct {
	//充值的pubKey
	FundingPubKey      string `json:"funding_pubkey"`
	FunderAddressIndex int    `json:"funder_address_index"`
	IsPrivate          bool   `json:"is_private"` // channel is a private channel, can not use htlc hop
	typeLengthValue
}

//https://github.com/obdlayer/Omni-BOLT-spec/blob/master/OmniBOLT-03-RSMC-and-OmniLayer-Transactions.md
// type = -32 请求方的obd发给接收方的obd的通道开通请求
// type = -110032 接收方obd发给接收方客户端的消息
type RequestOpenChannel struct {
	SendChannelOpen
	ChainHash                string          `json:"chain_hash"`
	TemporaryChannelId       string          `json:"temporary_channel_id"`
	FundingSatoshis          uint64          `json:"funding_satoshis"`
	PushMsat                 uint64          `json:"push_msat"`
	DustLimitSatoshis        uint64          `json:"dust_limit_satoshis"`
	MaxHtlcValueInFlightMsat uint64          `json:"max_htlc_value_in_flight_msat"`
	ChannelReserveSatoshis   uint64          `json:"channel_reserve_satoshis"`
	HtlcMinimumMsat          uint64          `json:"htlc_minimum_msat"`
	FeeRatePerKw             uint32          `json:"fee_rate_per_kw"`
	ToSelfDelay              uint16          `json:"to_self_delay"`
	MaxAcceptedHtlcs         uint16          `json:"max_accepted_htlcs"` //最多可以接受多少给hltc请求 500
	FunderNodeAddress        string          `json:"funder_node_address"`
	FunderPeerId             string          `json:"funder_peer_id"`
	FundingAddress           string          `json:"funding_address"`
	RevocationBasePoint      chainhash.Point `json:"revocation_base_point"`
	PaymentBasePoint         chainhash.Point `json:"payment_base_point"`
	DelayedPaymentBasePoint  chainhash.Point `json:"delayed_payment_base_point"`
	HtlcBasePoint            chainhash.Point `json:"htlc_base_point"`
}

// -100033 接收方给自己的obd发送回复开通通道的请求
type SendSignOpenChannel struct {
	FundingPubKey      string `json:"funding_pubkey"`
	FundeeAddressIndex int    `json:"fundee_address_index"`
	TemporaryChannelId string `json:"temporary_channel_id"`
	Approval           bool   `json:"approval"`
	typeLengthValue
}

//type: -38 (close_channel)
type CloseChannel struct {
	ChannelId string `json:"channel_id"`
	typeLengthValue
}

//type: -39 (close_channel_sign)
type CloseChannelSign struct {
	ChannelId               string `json:"channel_id"`
	RequestCloseChannelHash string `json:"request_close_channel_hash"`
	Approval                bool   `json:"approval"` // true agree false disagree
	typeLengthValue
}

// type: -100340
type SendRequestFundingBtc struct {
	TemporaryChannelId string `json:"temporary_channel_id"`
	FundingTxHex       string `json:"funding_tx_hex"`
	typeLengthValue
}

// type: -340
// type: -110340
type FundingBtcOfP2p struct {
	TemporaryChannelId string                `json:"temporary_channel_id"`
	FundingTxid        string                `json:"funding_txid"`
	FundingBtcHex      string                `json:"funding_btc_hex"`
	FundingRedeemHex   string                `json:"funding_redeem_hex"`
	FunderNodeAddress  string                `json:"funder_node_address"`
	FunderPeerId       string                `json:"funder_peer_id"`
	SignData           NeedClientSignHexData `json:"sign_data"`
}

//type: -100350 (SendSignFundingBtc)
type SendSignFundingBtc struct {
	TemporaryChannelId              string `json:"temporary_channel_id"`
	FundingTxid                     string `json:"funding_txid"`
	SignedMinerRedeemTransactionHex string `json:"signed_miner_redeem_transaction_hex"`
	Approval                        bool   `json:"approval"`
	typeLengthValue
}

// type: -100034
type FundingAssetOfP2p struct {
	//临时通道id
	TemporaryChannelId string `json:"temporary_channel_id"`
	ChannelId          string `json:"channel_id"`
	//充值hex
	FundingOmniHex        string                `json:"funding_omni_hex"`
	C1aRsmcHex            string                `json:"c1a_rsmc_hex"`
	RsmcTempAddressPubKey string                `json:"rsmc_temp_address_pub_key"`
	SignData              NeedClientSignHexData `json:"sign_data"`
	FunderNodeAddress     string                `json:"funder_node_address"`
	FunderPeerId          string                `json:"funder_peer_id"`
}

// -MsgType_Funding_134 100134
type SendRequestFunding struct {
	TemporaryChannelId string  `json:"temporary_channel_id"`
	BtcAmount          float64 `json:"btc_amount"`
	PropertyId         int64   `json:"property_id"`
	AssetAmount        float64 `json:"asset_amount"`
}

// -100034
type SendRequestAssetFunding struct {
	TemporaryChannelId string `json:"temporary_channel_id"`
	FundingTxHex       string `json:"funding_tx_hex"`
	TempAddressIndex   int    `json:"temp_address_index"`
	TempAddressPubKey  string `json:"temp_address_pub_key"`
	typeLengthValue
}

// -101034
type AliceSignC1aOfAssetFunding struct {
	SignedC1aHex string `json:"signed_c1a_hex"`
	typeLengthValue
}

//type: -100035 (funding_signed)
type SignAssetFunding struct {
	TemporaryChannelId string `json:"temporary_channel_id"`
	SignedAliceRsmcHex string `json:"signed_alice_rsmc_hex"`
	typeLengthValue
}

//type: -101035 (funding_signed)
type NeedSignRdAndBrOfAssetFunding struct {
	TemporaryChannelId string                 `json:"temporary_channel_id"`
	AliceRdSignData    map[string]interface{} `json:"alice_rd_sign_data"`
	AliceBrSignData    map[string]interface{} `json:"alice_br_sign_data"`
}

//type: -101035 (funding_signed)
type SignRdAndBrOfAssetFunding struct {
	TemporaryChannelId string `json:"temporary_channel_id"`
	BrId               int64  `json:"br_id"`
	RdSignedHex        string `json:"rd_signed_hex"`
	BrSignedHex        string `json:"br_signed_hex"`
	typeLengthValue
}

// -101134
type AliceSignRDOfAssetFunding struct {
	ChannelId   string `json:"channel_id"`
	RdSignedHex string `json:"rd_signed_hex"`
	typeLengthValue
}

//51->52
type HtlcCloseCloserSignTxInfoToClosee struct {
	ChannelId                       string `json:"channel_id"`
	CloseeSignedRsmcHex             string `json:"closee_signed_rsmc_hex"`
	CloseeRsmcRdHex                 string `json:"closee_rsmc_rd_hex"`
	CloseeSignedToCounterpartyTxHex string `json:"closee_signed_to_counterparty_tx_hex"`
}

// 付款人的obd发给收款人的obd的消息体 在请求htlc交易 40->41
type AliceRequestAddHtlc struct {
	ChannelId                        string  `json:"channel_id"`
	Amount                           float64 `json:"amount"`
	RoutingPacket                    string  `json:"routing_packet"`
	CltvExpiry                       int     `json:"cltv_expiry"` //发起者设定的总的等待的区块个数
	PayerCommitmentTxHash            string  `json:"payer_commitment_tx_hash"`
	Memo                             string  `json:"memo"`
	H                                string  `json:"h"`
	ToCounterpartyTxHex              string  `json:"to_counterparty_tx_hex"`
	HtlcTxHex                        string  `json:"htlc_tx_hex"`
	RsmcTxHex                        string  `json:"rsmc_tx_hex"`
	LastTempAddressPrivateKey        string  `json:"last_temp_address_private_key"`
	CurrRsmcTempAddressPubKey        string  `json:"curr_rsmc_temp_address_pub_key"`
	CurrHtlcTempAddressPubKey        string  `json:"curr_htlc_temp_address_pub_key"`
	CurrHtlcTempAddressForHt1aPubKey string  `json:"curr_htlc_temp_address_for_ht1a_pub_key"`
	PayerNodeAddress                 string  `json:"payer_node_address"`
	PayerPeerId                      string  `json:"payer_peer_id"`
}

//  p2p消息 收款人的obd发给付款人的obd的消息体 在获得R后

//  p2p消息 请求关闭htlc交易
type RequestCloseHtlcTxOfP2p struct {
	ChannelId                            string `json:"channel_id"`
	LastRsmcTempAddressPrivateKey        string `json:"last_rsmc_temp_address_private_key"`
	LastHtlcTempAddressPrivateKey        string `json:"last_htlc_temp_address_private_key"`
	LastHtlcTempAddressForHtnxPrivateKey string `json:"last_htlc_temp_address_for_htnx_private_key"`
	CurrRsmcTempAddressPubKey            string `json:"curr_rsmc_temp_address_pub_key"`
	RsmcHex                              string `json:"rsmc_hex"`
	ToCounterpartyTxHex                  string `json:"to_counterparty_tx_hex"`
	CommitmentTxHash                     string `json:"commitment_tx_hash"`
	SenderNodeAddress                    string `json:"sender_node_address"`
	SenderPeerId                         string `json:"sender_peer_id"`
}

// ws消息 收款人的obd发给付款人的obd的消息体 在获得R后
// -110050
type RequestCloseHtlcTxOfWs struct {
	RequestCloseHtlcTxOfP2p
	MsgHash string `json:"msg_hash"`
}

//type -80: MsgType_Atomic_Swap_80
type AtomicSwapRequest struct {
	ChannelIdFrom       string  `json:"channel_id_from"`
	ChannelIdTo         string  `json:"channel_id_to"`
	RecipientUserPeerId string  `json:"recipient_user_peer_id"`
	PropertySent        int64   `json:"property_sent"`
	Amount              float64 `json:"amount"`
	ExchangeRate        float64 `json:"exchange_rate"`
	PropertyReceived    int64   `json:"property_received"`
	TransactionId       string  `json:"transaction_id"`
	TimeLocker          uint32  `json:"time_locker"`
	typeLengthValue
}

//type -81: MsgType_Atomic_Swap_Accept_N81
type AtomicSwapAccepted struct {
	AtomicSwapRequest
	TargetTransactionId string `json:"target_transaction_id"` // 针对的目标交易id
}

type NeedClientSignHexData struct {
	TemporaryChannelId string      `json:"temporary_channel_id"`
	Hex                string      `json:"hex"`
	Inputs             interface{} `json:"inputs"`
	IsMultisig         bool        `json:"is_multisig"`
	PubKeyA            string      `json:"pub_key_a"`
	PubKeyB            string      `json:"pub_key_b"`
	TotalInAmount      float64     `json:"total_in_amount"`
	TotalOutAmount     float64     `json:"total_out_amount"`
}

// 正式通道的需要客户端签名的信息体
type NeedClientSignTxData struct {
	Hex        string      `json:"hex"`
	Inputs     interface{} `json:"inputs"`
	IsMultisig bool        `json:"is_multisig"`
	PubKeyA    string      `json:"pub_key_a"`
	PubKeyB    string      `json:"pub_key_b"`
	PrivateKey string      `json:"private_key"`
}
type NeedClientSignRawBRTxData struct {
	NeedClientSignTxData
	BrId int `json:"br_id"`
}

type RawTxInputItem struct {
	ScriptPubKey string `json:"scriptPubKey"`
	RedeemScript string `json:"redeem_script"`
}


<|start_filename|>omnicore/CreateRawOmniTransaction_test.go<|end_filename|>
package omnicore

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"strings"
	"testing"

	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/wire"
)

func TestCreateTransaction(t *testing.T) {
	//transaction, err := CreateTransaction("5HusYj2b2x4nroApgfvaSfKYZhRbKFH41bVyPooymbC6KfgSXdD", "1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa", 91234, "81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48")
	//if err != nil {
	//	fmt.Println(err)
	//	return
	//}
	//data, _ := json.Marshal(transaction)
	//fmt.Println(string(data))
}

func TestCheckUnspent(t *testing.T) {
	Unspent1 := new(Unspent) //pointer
	Unspent1.TxID = "c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de"
	Unspent1.VOut = 0

	Unspent2 := new(Unspent)
	Unspent2.TxID = "ee1673b09b0edaf7aaf8eb0bfd53a5a2757eb3e342e731bfc960b869aa0ab6b3"
	Unspent2.VOut = 2

	var unspent_slice []*Unspent

	unspentlist := append(unspent_slice, Unspent1, Unspent2)

	json1, _ := json.Marshal(unspentlist)

	fmt.Println(string(json1))

	fmt.Println("now unmarshal..........")

	const jsonStream = `
        { "txid" : "c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de" , "vout" : 0} 
        { "txid" : "<KEY>" , "vout" : 2 } 
   		`

	decoder := json.NewDecoder(strings.NewReader(jsonStream))
	for {
		var m Unspent
		if err := decoder.Decode(&m); err == io.EOF {
			break
		} else if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%s: %d \n ", m.TxID, m.VOut)
	}

	fmt.Println("or in this way ..........")

	var jsonBlob = []byte(` [ 
        { "txid" : "c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de" , "vout" : 0 } , 
        { "txid" : "<KEY>" ,     "vout" : 2 } 
    ] `)

	var unspent_tx []Unspent
	err := json.Unmarshal(jsonBlob, &unspent_tx)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%s: %d \n ", unspent_tx[0].TxID, unspent_tx[0].VOut)
	fmt.Printf("%s: %d \n ", unspent_tx[1].TxID, unspent_tx[1].VOut)

}

func TestGetOmMarker(t *testing.T) {
	fmt.Printf("%s \n ", GetOmMarker())
}

func TestOmniCreatePayloadSimpleSend(t *testing.T) {
	var property_id uint32 = 100
	var amount uint64 = 10
	payload_byte_slice := OmniCreatePayloadSimpleSend(property_id, amount)
	str := string(payload_byte_slice)
	fmt.Printf(str)
}

func TestCreateTransactionBase(t *testing.T) {
	const jsonStream = `
		{ "txid" : "c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de" , "vout" : 0} 
		{ "txid" : "ee1673b09b0edaf7aaf8eb0bfd53a5a2757eb3e342e731bfc960b869aa0ab6b3" , "vout" : 2 } 
	   `

	tx, tx_hex, _ := CreateRawTransaction(jsonStream, wire.TxVersion)
	fmt.Printf("The final base transaction hex")
	fmt.Printf("%s \n ", tx_hex)
	fmt.Println("Must be equal to: ")
	fmt.Println(TxToHex(tx))

}

func TestCreateTransactionWithSequence(t *testing.T) {

	const jsonStream = `
		{ "txid" : "c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de" , "vout" : 0, "sequence" : 1000} 
		{ "txid" : "ee1673b09b0edaf7aaf8eb0bfd53a5a2757eb3e342e731bfc960b869aa0ab6b3" , "vout" : 2, "sequence" : 1000} 
	   `
}

/*
 * extend the opreturn data to base transaction.
 * The expected values are computed by wire.TxVersion = 1.
 *
 */
func TestCreateTransactionOpreturn(t *testing.T) {

	const jsonStream = `
		{ "txid" : "c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de" , "vout" : 0} 
		{ "txid" : "ee1673b09b0edaf7aaf8eb0bfd53a5a2757eb3e342e731bfc960b869aa0ab6b3" , "vout" : 2} 
	   `

	// 2) Construct payload
	payload, payload_hex := Omni_createpayload_simplesend("2", "0.1", true)
	fmt.Println("expect: 00000000000000020000000000989680")
	fmt.Println("export:")
	fmt.Println(payload_hex)

	// 3) Construct transaction base
	tx, tx_hex, _ := CreateRawTransaction(jsonStream, wire.TxVersion)
	fmt.Printf("The final base transaction hex")
	fmt.Printf("%s \n ", tx_hex)

	// 4) Attach payload output
	tx, _ = Omni_createrawtx_opreturn(tx, payload, payload_hex)

	expected := "0100000002de95b97cf4c67ec01485fd698ec154a325ff69dd3e58435d7024bae7f69534c20000000000ffffffffb3b60aaa69b860c9bf31e742e3b37e75a2a553fd0bebf8aaf7da0e9bb07316ee0200000000ffffffff010000000000000000166a146f6d6e690000000000000002000000000098968000000000"
	fmt.Println("step 4 expects:")
	fmt.Println(expected)

	fmt.Println("step 4 exports: ")
	exported := TxToHex(tx)
	fmt.Println(exported)

	if strings.Compare(expected, exported) == 0 {
		fmt.Println("succeed in 4) Attach reference/receiver output")
	}

	//5) Attach reference/receiver output
	receiver := "1Njbpr7EkLA1R8ag8bjRN7oks7nv5wUn3o"
	tx, _ = Omni_createrawtx_reference(tx, receiver, &chaincfg.MainNetParams)

	expected = "0100000002de95b97cf4c67ec01485fd698ec154a325ff69dd3e58435d7024bae7f69534c20000000000ffffffffb3b60aaa69b860c9bf31e742e3b37e75a2a553fd0bebf8aaf7da0e9bb07316ee0200000000ffffffff020000000000000000166a146f6d6e690000000000000002000000000098968022020000000000001976a914ee692ea81da1b12d3dd8f53fd504865c9d843f5288ac00000000"
	fmt.Println("step 5 expects: ")
	fmt.Println(expected)

	fmt.Println("step 5 exports: ")
	exported = TxToHex(tx)
	fmt.Println(exported)

	if strings.Compare(expected, exported) == 0 {
		fmt.Println("succeed in 5) Attach reference/receiver output")
	}

	//6) Specify miner fee and attach change output (as needed)
	//This test specifies miner fee of 0.0006 btc
	fmt.Println("step 6: attach change output to the sender")

	const prev_txs_json = `
		{"txid":"c23495f6e7ba24705d43583edd69ff25a354c18e69fd8514c07ec6f47cb995de","vout":0,"scriptPubKey":"76a914c6734676a08e3c6438bd95fa62c57939c988a17b88ac","value":"0.001"} 
		{"txid":"ee1673b09b0edaf7aaf8eb0bfd53a5a2757eb3e342e731bfc960b869aa0ab6b3","vout":2,"scriptPubKey":"76a914c6734676a08e3c6438bd95fa62c57939c988a17b88ac","value":"0.0083566"}
		`
	tx, _ = Omni_createrawtx_change(tx, prev_txs_json,
		"1K6JtSvrHtyFmxdtGZyZEF7ydytTGqasNc",
		"0.0006", &chaincfg.MainNetParams)

	expected = "0100000002de95b97cf4c67ec01485fd698ec154a325ff69dd3e58435d7024bae7f69534c20000000000ffffffffb3b60aaa69b860c9bf31e742e3b37e75a2a553fd0bebf8aaf7da0e9bb07316ee0200000000ffffffff036a5a0d00000000001976a914c6734676a08e3c6438bd95fa62c57939c988a17b88ac0000000000000000166a146f6d6e690000000000000002000000000098968022020000000000001976a914ee692ea81da1b12d3dd8f53fd504865c9d843f5288ac00000000"
	fmt.Println("step 6 expects: ")
	fmt.Println(expected)

	exported = TxToHex(tx)
	fmt.Println("step 6 exports: ")
	fmt.Println(exported)
	if strings.Compare(expected, exported) == 0 {
		fmt.Println("succeed constructing opreturn raw transaction offline")
	}

	fmt.Println("Hex from step 6 may be different than what expected, because omnicore c++ reorder the outputs. ")
	fmt.Println("Use DecodeRawtrnasaction to verify the two hexs. ")

	transaction_json_expected := DecodeRawTransaction(expected, &chaincfg.MainNetParams)
	transaction_json_exported := DecodeRawTransaction(exported, &chaincfg.MainNetParams)

	fmt.Println("expect")
	fmt.Println(transaction_json_expected)
	fmt.Println("export")
	fmt.Println(transaction_json_exported)

}


<|start_filename|>service/atomic_swap.go<|end_filename|>
package service

import (
	"encoding/json"
	"errors"
	"github.com/asdine/storm/q"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/conn"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/tool"
	"log"
	"sync"
	"time"
)

//close htlc or close channel
type atomicSwapManager struct {
	operationFlag sync.Mutex
}

var AtomicSwapService atomicSwapManager

//type MsgType_Atomic_Swap_N80  可以理解为付款凭证
func (this *atomicSwapManager) AtomicSwap(msg bean.RequestMessage, user bean.User) (outData interface{}, err error) {
	if tool.CheckIsString(&msg.Data) == false {
		return nil, errors.New("empty json data")
	}
	reqData := &bean.AtomicSwapRequest{}
	err = json.Unmarshal([]byte(msg.Data), reqData)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	if tool.CheckIsString(&reqData.RecipientUserPeerId) == false {
		return nil, errors.New("error recipient_user_peer_id")
	}

	if msg.RecipientUserPeerId != reqData.RecipientUserPeerId {
		return nil, errors.New("wrong recipient_user_peer_id")
	}

	if reqData.TimeLocker < 10 {
		return nil, errors.New("error time_locker")
	}
	if reqData.RecipientUserPeerId == user.PeerId {
		return nil, errors.New("you should not send msg to yourself")
	}

	err = findUserIsOnline(msg.RecipientNodePeerId, reqData.RecipientUserPeerId)
	if err != nil {
		return nil, err
	}

	if tool.CheckIsString(&reqData.ChannelIdFrom) == false {
		return nil, errors.New("error channel_id_from")
	}

	_, err = conn2tracker.OmniGetProperty(reqData.PropertySent)
	if err != nil {
		log.Println(err)
		return nil, errors.New("error property_sent")
	}

	err = user.Db.Select(
		q.Eq("ChannelId", reqData.ChannelIdFrom),
		q.Eq("CurrState", bean.ChannelState_HtlcTx),
		q.Eq("PropertyId", reqData.PropertySent),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		First(&dao.ChannelInfo{})
	if err != nil {
		return nil, errors.New("not found this channel_id_from")
	}

	if tool.CheckIsString(&reqData.ChannelIdTo) == false {
		return nil, errors.New("error channel_id_to")
	}

	_, err = conn2tracker.OmniGetProperty(reqData.PropertyReceived)
	if err != nil {
		log.Println(err)
		return nil, errors.New("error property_received")
	}

	if reqData.ExchangeRate < 0 {
		return nil, errors.New("error exchange_rate")
	}
	if tool.CheckIsString(&reqData.TransactionId) == false {
		return nil, errors.New("error transaction_id")
	}

	flag := conn2tracker.GetChannelState(reqData.ChannelIdTo)
	if flag == 0 {
		return nil, errors.New("not found this channel_id_to")
	}

	err = user.Db.Select(
		q.Eq("CurrHash", reqData.TransactionId),
		q.Eq("TxType", dao.CommitmentTransactionType_Htlc),
		q.Eq("CurrState", dao.TxInfoState_Htlc_GetH),
		q.Eq("ChannelId", reqData.ChannelIdFrom),
		q.Eq("Owner", user.PeerId)).
		First(&dao.CommitmentTransaction{})
	if err != nil {
		return nil, errors.New("error transaction_id")
	}

	swapInfo := &dao.AtomicSwapInfo{}
	//check if have send the same info
	err = user.Db.Select(
		q.Eq("TransactionId", reqData.TransactionId),
		q.Eq("ChannelIdFrom", reqData.ChannelIdFrom),
		q.Eq("ChannelIdTo", reqData.ChannelIdTo),
		q.Eq("PropertySent", reqData.PropertySent),
		q.Eq("PropertyReceived", reqData.PropertyReceived),
		q.Eq("CreateBy", user.PeerId),
	).First(swapInfo)

	swapInfo.LatestEditAt = time.Now()
	swapInfo.AtomicSwapRequest = *reqData
	if swapInfo.Id > 0 {
		err = user.Db.Update(swapInfo)
	} else {
		swapInfo.CreateBy = user.PeerId
		swapInfo.CreateAt = time.Now()
		err = user.Db.Save(swapInfo)
	}
	if err != nil {
		return nil, errors.New("fail to save db,try again")
	}
	return reqData, nil
}

//80的信息到达接受者的obd节点的处理
func (this *atomicSwapManager) BeforeSignAtomicSwapAtBobSide(data string, user *bean.User) (retData interface{}, err error) {
	reqData := &bean.AtomicSwapRequest{}
	err = json.Unmarshal([]byte(data), reqData)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	swapInfo := &dao.AtomicSwapInfo{}
	//check if have send the same info
	err = user.Db.Select(
		q.Eq("TransactionId", reqData.TransactionId),
		q.Eq("ChannelIdFrom", reqData.ChannelIdFrom),
		q.Eq("ChannelIdTo", reqData.ChannelIdTo),
		q.Eq("PropertySent", reqData.PropertySent),
		q.Eq("PropertyReceived", reqData.PropertyReceived),
		q.Eq("CreateBy", user.PeerId),
	).First(swapInfo)

	swapInfo.LatestEditAt = time.Now()
	swapInfo.AtomicSwapRequest = *reqData
	if swapInfo.Id > 0 {
		err = user.Db.Update(swapInfo)
	} else {
		swapInfo.CreateBy = user.PeerId
		swapInfo.CreateAt = time.Now()
		err = user.Db.Save(swapInfo)
	}
	if err != nil {
		log.Println(err)
	}

	return reqData, nil
}

//MsgType_Atomic_Swap_Accept_N81 可以理解为发货凭证
func (this *atomicSwapManager) AtomicSwapAccepted(msg bean.RequestMessage, user bean.User) (outData interface{}, err error) {
	if tool.CheckIsString(&msg.Data) == false {
		return nil, errors.New("empty json data")
	}
	reqData := &bean.AtomicSwapAccepted{}
	err = json.Unmarshal([]byte(msg.Data), reqData)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	if tool.CheckIsString(&reqData.RecipientUserPeerId) == false {
		return nil, errors.New("error recipient_user_peer_id")
	}

	if reqData.RecipientUserPeerId == user.PeerId {
		return nil, errors.New("you should not send msg to yourself")
	}

	if msg.RecipientUserPeerId != reqData.RecipientUserPeerId {
		return nil, errors.New("wrong recipient_user_peer_id")
	}

	err = findUserIsOnline(msg.RecipientNodePeerId, reqData.RecipientUserPeerId)
	if err != nil {
		return nil, err
	}

	if reqData.TimeLocker < 10 {
		return nil, errors.New("error time_locker")
	}

	if tool.CheckIsString(&reqData.ChannelIdFrom) == false {
		return nil, errors.New("error channel_id_from")
	}

	_, err = conn2tracker.OmniGetProperty(reqData.PropertySent)
	if err != nil {
		log.Println(err)
		return nil, errors.New("error property_sent")
	}

	err = user.Db.Select(
		q.Eq("ChannelId", reqData.ChannelIdFrom),
		q.Eq("CurrState", bean.ChannelState_HtlcTx),
		q.Eq("PropertyId", reqData.PropertySent),
		q.Or(
			q.Eq("PeerIdA", user.PeerId),
			q.Eq("PeerIdB", user.PeerId))).
		First(&dao.ChannelInfo{})
	if err != nil {
		return nil, errors.New("not found this channel of channel_id_from")
	}

	if tool.CheckIsString(&reqData.ChannelIdTo) == false {
		return nil, errors.New("error channel_id_to")
	}

	_, err = conn2tracker.OmniGetProperty(reqData.PropertyReceived)
	if err != nil {
		log.Println(err)
		return nil, errors.New("error property_received")
	}

	if reqData.ExchangeRate < 0 {
		return nil, errors.New("error exchange_rate")
	}
	if tool.CheckIsString(&reqData.TransactionId) == false {
		return nil, errors.New("error transaction_id")
	}

	err = user.Db.Select(
		q.Eq("CurrHash", reqData.TransactionId),
		q.Eq("TxType", dao.CommitmentTransactionType_Htlc),
		q.Eq("CurrState", dao.TxInfoState_Htlc_GetH),
		q.Eq("ChannelId", reqData.ChannelIdFrom),
		q.Eq("Owner", user.PeerId)).
		First(&dao.CommitmentTransaction{})
	if err != nil {
		return nil, errors.New("error transaction_id")
	}

	if tool.CheckIsString(&reqData.TargetTransactionId) == false {
		return nil, errors.New("error target_transaction_id")
	}

	flag := conn2tracker.GetChannelState(reqData.ChannelIdTo)
	if flag == 0 {
		return nil, errors.New("not found this channel_id_to")
	}

	targetTx := &dao.AtomicSwapInfo{}
	err = user.Db.Select(
		q.Eq("TransactionId", reqData.TargetTransactionId),
		q.Eq("RecipientUserPeerId", user.PeerId),
	).First(targetTx)
	if err != nil {
		return nil, errors.New("not found the target swap transaction")
	}

	swapInfo := &dao.AtomicSwapAcceptedInfo{}
	err = user.Db.Select(
		q.Eq("TransactionId", reqData.TransactionId),
		q.Eq("ChannelIdFrom", reqData.ChannelIdFrom),
		q.Eq("ChannelIdTo", reqData.ChannelIdTo),
		q.Eq("PropertySent", reqData.PropertySent),
		q.Eq("PropertyReceived", reqData.PropertyReceived),
		q.Eq("TargetTransactionId", reqData.TargetTransactionId),
		q.Eq("CreateBy", user.PeerId),
	).First(swapInfo)

	swapInfo.AtomicSwapAccepted = *reqData
	swapInfo.LatestEditAt = time.Now()
	if swapInfo.Id > 0 {
		err = user.Db.Update(swapInfo)
	} else {
		swapInfo.CreateBy = user.PeerId
		swapInfo.CreateAt = time.Now()
		err = user.Db.Save(swapInfo)
	}

	if err != nil {
		log.Println(err)
		return nil, errors.New("fail to save db,try again")
	}

	return reqData, nil
}

//81的信息到达接受者的obd节点的处理
func (this *atomicSwapManager) BeforeSignAtomicSwapAcceptedAtAliceSide(data string, user *bean.User) (retData interface{}, err error) {
	reqData := &bean.AtomicSwapAccepted{}
	err = json.Unmarshal([]byte(data), reqData)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	swapInfo := &dao.AtomicSwapAcceptedInfo{}
	err = user.Db.Select(
		q.Eq("TransactionId", reqData.TransactionId),
		q.Eq("ChannelIdFrom", reqData.ChannelIdFrom),
		q.Eq("ChannelIdTo", reqData.ChannelIdTo),
		q.Eq("PropertySent", reqData.PropertySent),
		q.Eq("PropertyReceived", reqData.PropertyReceived),
		q.Eq("TargetTransactionId", reqData.TargetTransactionId),
		q.Eq("CreateBy", user.PeerId),
	).First(swapInfo)

	swapInfo.AtomicSwapAccepted = *reqData
	swapInfo.LatestEditAt = time.Now()
	if swapInfo.Id > 0 {
		err = user.Db.Update(swapInfo)
	} else {
		swapInfo.CreateBy = user.PeerId
		swapInfo.CreateAt = time.Now()
		err = user.Db.Save(swapInfo)
	}
	if err != nil {
		log.Println(err)
	}

	return reqData, nil
}


<|start_filename|>proxy/rpc/rpc.go<|end_filename|>
package rpc

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/proxy/pb"
	"github.com/omnilaboratory/obd/service"
	"log"
)

type RpcServer struct{}

// for testing
func (r *RpcServer) Hello(ctx context.Context,
	in *pb.HelloRequest) (*pb.HelloResponse, error) {

	log.Println("hello " + in.GetSayhi())
	resp, err := Hello(in.Sayhi)
	if err != nil {
		return nil, err
	}

	return &pb.HelloResponse{Resp: resp}, nil
}

// for testing
func Hello(sayhi string) (string, error) {
	returnMsg := "You sent: [" + sayhi + "]. We're testing proxy mode of OBD."
	return returnMsg, nil
}

func (s *RpcServer) ConnectPeer(ctx context.Context, in *pb.ConnectPeerRequest) (resp *pb.ConnectPeerResponse, err error) {
	log.Println("ConnectPeer")

	if len(in.Addr) == 0 {
		return nil, errors.New("wrong addr")
	}
	input := make(map[string]interface{})
	input["remote_node_address"] = in.Addr
	marshal, _ := json.Marshal(input)
	requestMessage := bean.RequestMessage{
		Type: enum.MsgType_p2p_ConnectPeer_2003,
		Data: string(marshal)}
	_, bytes, status := obcClient.UserModule(requestMessage)
	data := string(bytes)
	if status == false {
		return nil, errors.New(data)
	}
	resp = &pb.ConnectPeerResponse{}
	return resp, nil
}
func (s *RpcServer) DisconnectPeer(ctx context.Context, in *pb.DisconnectPeerRequest) (resp *pb.DisconnectPeerResponse, err error) {
	log.Println("ConnectPeer")

	if len(in.Addr) == 0 {
		return nil, errors.New("wrong addr")
	}
	input := make(map[string]interface{})
	input["remote_node_address"] = in.Addr
	marshal, _ := json.Marshal(input)
	requestMessage := bean.RequestMessage{
		Type: enum.MsgType_p2p_DisconnectPeer_2010,
		Data: string(marshal)}
	_, bytes, status := obcClient.UserModule(requestMessage)
	data := string(bytes)
	if status == false {
		return nil, errors.New(data)
	}
	resp = &pb.DisconnectPeerResponse{}
	return resp, nil
}

func (s *RpcServer) PendingChannels(ctx context.Context, in *pb.PendingChannelsRequest) (resp *pb.ListChannelsResponse, err error) {
	log.Println("PendingChannels")

	user, err := checkLogin()
	if err != nil {
		return nil, err
	}

	inputData := make(map[string]interface{})
	inputData["is_pending"] = true
	inputData["page_size"] = in.PageSize
	inputData["page_index"] = in.PageIndex
	marshal, _ := json.Marshal(inputData)
	respData, err := service.ChannelService.AllItem(string(marshal), *user)
	if err != nil {
		return nil, err
	}
	resp = &pb.ListChannelsResponse{}
	list := respData.Data.([]service.ChannelVO)
	for _, item := range list {
		if len(item.ChannelId) == 0 {
			continue
		}
		node := &pb.Channel{}
		node.ChanId = item.ChannelId
		node.Private = item.IsPrivate
		node.Active = true
		if item.CurrState == bean.ChannelState_Close {
			node.Active = false
		}
		node.PropertyId = item.PropertyId
		node.Capacity = int64(item.AssetAmount * 100000000)
		node.Initiator = false
		if user.PeerId == item.PeerIdA {
			node.Initiator = true
		}
		node.LocalBalance = int64(item.BalanceA * 100000000)
		node.RemoteBalance = int64(item.BalanceB * 100000000)
		node.NumUpdates = item.NumUpdates
		resp.Channels = append(resp.Channels, node)
	}
	return resp, nil
}
func (s *RpcServer) ListChannels(ctx context.Context, in *pb.ListChannelsRequest) (resp *pb.ListChannelsResponse, err error) {
	log.Println("ListChannels")
	user, err := checkLogin()
	if err != nil {
		return nil, err
	}
	marshal, _ := json.Marshal(in)
	respData, err := service.ChannelService.AllItem(string(marshal), *user)
	if err != nil {
		return nil, err
	}
	resp = &pb.ListChannelsResponse{}
	list := respData.Data.([]service.ChannelVO)
	for _, item := range list {
		if len(item.ChannelId) == 0 {
			continue
		}
		node := &pb.Channel{}
		node.ChanId = item.ChannelId
		node.Private = item.IsPrivate
		node.Active = true
		if item.CurrState == bean.ChannelState_Close {
			node.Active = false
		}
		node.PropertyId = item.PropertyId
		node.Capacity = int64(item.AssetAmount * 100000000)
		node.Initiator = false
		if user.PeerId == item.PeerIdA {
			node.Initiator = true
		}
		node.LocalBalance = int64(item.BalanceA * 100000000)
		node.RemoteBalance = int64(item.BalanceB * 100000000)
		node.NumUpdates = item.NumUpdates
		resp.Channels = append(resp.Channels, node)
	}
	return resp, err
}

func (s *RpcServer) LatestTransaction(ctx context.Context, in *pb.LatestTransactionRequest) (*pb.Transaction, error) {
	log.Println("LatestRsmcTx")

	if len(in.ChannelId) == 0 {
		return nil, errors.New("wrong channelId")
	}

	user, err := checkLogin()
	if err != nil {
		return nil, err
	}
	marshal, _ := json.Marshal(in)
	respData, err := service.CommitmentTxService.GetLatestCommitmentTxByChannelId(string(marshal), user)
	if err != nil {
		return nil, err
	}
	resp := &pb.Transaction{
		TxHash:    respData.CurrHash,
		ChannelId: respData.ChannelId,
		AmountA:   respData.AmountToRSMC,
		AmountB:   respData.AmountToCounterparty,
		PeerA:     respData.PeerIdA,
		PeerB:     respData.PeerIdB,
		CurrState: int32(respData.CurrState),
		TxType:    int32(respData.TxType),
		H:         respData.HtlcH,
		R:         respData.HtlcR,
	}
	return resp, nil
}

func (s *RpcServer) GetTransactions(ctx context.Context, in *pb.GetTransactionsRequest) (*pb.TransactionDetails, error) {
	log.Println("LatestRsmcTx")

	if len(in.ChannelId) == 0 {
		return nil, errors.New("wrong channelId")
	}

	user, err := checkLogin()
	if err != nil {
		return nil, err
	}
	marshal, _ := json.Marshal(in)
	transactions, count, err := service.CommitmentTxService.GetItemsByChannelId(string(marshal), user)
	log.Println(count)
	log.Println(transactions)
	if err != nil {
		return nil, err
	}
	resp := &pb.TransactionDetails{TotalCount: int32(*count), PageIndex: in.PageIndex, PageSize: in.PageSize}
	for _, item := range transactions {
		node := &pb.Transaction{
			TxHash:     item.CurrHash,
			ChannelId:  item.ChannelId,
			AmountA:    item.AmountToRSMC,
			AmountB:    item.AmountToCounterparty,
			PeerA:      item.PeerIdA,
			PeerB:      item.PeerIdB,
			CurrState:  int32(item.CurrState),
			TxType:     int32(item.TxType),
			H:          item.HtlcH,
			R:          item.HtlcR,
			AmountHtlc: item.AmountToHtlc,
		}
		resp.Transactions = append(resp.Transactions, node)
	}
	return resp, nil
}

func (s *RpcServer) ChannelBalance(ctx context.Context, in *pb.ChannelBalanceRequest) (*pb.ChannelBalanceResponse, error) {
	log.Println("ChannelBalance")

	user, err := checkLogin()
	if err != nil {
		return nil, err
	}
	data, err := service.ChannelService.ChannelBalance(user)
	if err != nil {
		return nil, err
	}

	resp := &pb.ChannelBalanceResponse{
		LocalBalance:             data["local_balance"],
		RemoteBalance:            data["remote_balance"],
		UnsettledLocalBalance:    data["unsettled_local_balance"],
		UnsettledRemoteBalance:   data["unsettled_remote_balance"],
		PendingOpenLocalBalance:  data["pending_open_local_balance"],
		PendingOpenRemoteBalance: data["pending_open_remote_balance"],
	}
	return resp, nil
}

func (s *RpcServer) ClosedChannels(ctx context.Context, in *pb.ClosedChannelsRequest) (resp *pb.ClosedChannelsResponse, err error) {
	log.Println("ClosedChannels")

	user, err := checkLogin()
	if err != nil {
		return nil, err
	}
	inputData := make(map[string]interface{})
	inputData["closed"] = true
	inputData["page_size"] = in.PageSize
	inputData["page_index"] = in.PageIndex
	marshal, _ := json.Marshal(inputData)
	respData, err := service.ChannelService.AllItem(string(marshal), *user)
	if err != nil {
		return nil, err
	}
	resp = &pb.ClosedChannelsResponse{}
	list := respData.Data.([]service.ChannelVO)
	for _, item := range list {
		if len(item.ChannelId) == 0 {
			continue
		}
		node := &pb.Channel{}
		node.ChanId = item.ChannelId
		node.Private = item.IsPrivate
		node.Active = true
		if item.CurrState == bean.ChannelState_Close {
			node.Active = false
		}
		node.PropertyId = item.PropertyId
		node.Capacity = int64(item.AssetAmount * 100000000)
		node.Initiator = false
		if user.PeerId == item.PeerIdA {
			node.Initiator = true
		}
		node.LocalBalance = int64(item.BalanceA * 100000000)
		node.RemoteBalance = int64(item.BalanceB * 100000000)
		node.NumUpdates = item.NumUpdates
		resp.Channels = append(resp.Channels, node)
	}
	return resp, err
}


<|start_filename|>service/addrtool_hdwallet.go<|end_filename|>
package service

import (
	"encoding/hex"
	"errors"
	"github.com/asdine/storm/q"
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcutil"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/config"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/tool"
	"github.com/tyler-smith/go-bip32"
	"github.com/tyler-smith/go-bip39"
	"strings"
)

type Wallet struct {
	Index   int    `json:"index"`
	Address string `json:"address"`
	PubKey  string `json:"pub_key"`
	//PrivateKey    string `json:"private_key"`
	Wif string `json:"wif"`
}

type hdWalletManager struct {
}

var HDWalletService hdWalletManager

func (service *hdWalletManager) GetAddressByIndex(user *bean.User, index uint32) (wallet *Wallet, err error) {

	if user == nil || user.ChangeExtKey == nil {
		return nil, errors.New("error mnemonic")
	}

	changeExtKey := user.ChangeExtKey
	//m/purpose(44)'/coinType(0)'/account(0)'/change(0)/index(0)
	addrIndexExtKey, _ := changeExtKey.NewChildKey(index)

	wallet = &Wallet{}
	wallet.Index = int(index)
	err = getWalletObj(addrIndexExtKey, wallet)
	return wallet, err
}

func getWalletObj(addrIndexExtKey *bip32.Key, wallet *Wallet) (err error) {
	net := tool.GetCoreNet()
	hash160Bytes := btcutil.Hash160(addrIndexExtKey.PublicKey().Key)
	addr, err := btcutil.NewAddressPubKeyHash(hash160Bytes, net)
	if err != nil {
		return err
	}
	wallet.Address = addr.String()

	wallet.PubKey = hex.EncodeToString(addrIndexExtKey.PublicKey().Key)

	privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), addrIndexExtKey.Key)

	//wallet.PrivateKey = hex.EncodeToString(privKey.Serialize())
	wif, _ := btcutil.NewWIF(privKey, net, true)
	//wallet.Wifobj = wif
	//wallet.PrivateKeyObj = privKey
	wallet.Wif = wif.String()

	return nil
}
func (service *hdWalletManager) CreateNewAddress(user *bean.User) (wallet *Wallet, err error) {
	if user == nil || user.ChangeExtKey == nil {
		return nil, errors.New("error mnemonic")
	}

	changeExtKey := user.ChangeExtKey
	//m/purpose(44)'/coinType(0)'/account(0)'/change(0)/index(0)
	user.CurrAddrIndex = user.CurrAddrIndex + 1
	addrIndexExtKey, _ := changeExtKey.NewChildKey(uint32(user.CurrAddrIndex))

	wallet = &Wallet{}
	wallet.Index = user.CurrAddrIndex

	err = getWalletObj(addrIndexExtKey, wallet)
	if err != nil {
		return nil, err
	}

	var node dao.User
	_ = user.Db.Select(q.Eq("PeerId", user.PeerId)).First(&node)
	if node.Id > 0 {
		node.CurrAddrIndex = user.CurrAddrIndex
		_ = user.Db.Update(&node)
	}

	return wallet, nil
}

func (service *hdWalletManager) CreateChangeExtKey(mnemonic string) (changeExtKey *bip32.Key, err error) {
	if tool.CheckIsString(&mnemonic) == false {
		return nil, errors.New("error mnemonic")
	}
	valid := bip39.IsMnemonicValid(mnemonic)
	if valid == false {
		return nil, errors.New("wrong mnemonic")
	}

	seed := bip39.NewSeed(mnemonic, "")
	masterKey, _ := bip32.NewMasterKey(seed)
	//m/purpose'
	purposeExtKey, _ := masterKey.NewChildKey(bip32.FirstHardenedChild + 44)
	//m/purpose'/cointype'
	coinType := 0
	if strings.Contains(config.ChainNodeType, "main") == false {
		coinType = 1
	}

	coinTypeExtKey, err := purposeExtKey.NewChildKey(bip32.FirstHardenedChild + uint32(coinType))
	return coinTypeExtKey, err

	//m/purpose'/cointype'/account'
	accountExtKey, _ := coinTypeExtKey.NewChildKey(bip32.FirstHardenedChild + 0)
	//m/purpose'/cointype'/account'/change
	return accountExtKey.NewChildKey(0)
}


<|start_filename|>proxy/rpc/htlc.go<|end_filename|>
package rpc

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/dao"
	"github.com/omnilaboratory/obd/proxy/pb"
	"github.com/omnilaboratory/obd/service"
	"github.com/omnilaboratory/obd/tool"
	"log"
)

func (s *RpcServer) AddInvoice(ctx context.Context, in *pb.Invoice) (*pb.AddInvoiceResponse, error) {
	log.Println("AddInvoice")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}

	if tool.CheckIsString(&in.CltvExpiry) == false {
		return nil, errors.New("wrong cltv_expiry")
	}
	if in.Value < 0 {
		return nil, errors.New("wrong value")
	}

	if in.PropertyId < 0 {
		return nil, errors.New("wrong property_id")
	}

	request := InvoiceInfo{
		PropertyId:  in.PropertyId,
		Amount:      in.Value,
		Description: in.Memo,
		ExpiryTime:  in.CltvExpiry,
		IsPrivate:   in.Private,
	}

	infoBytes, _ := json.Marshal(request)
	requestMessage := bean.RequestMessage{
		Type:             enum.MsgType_HTLC_Invoice_402,
		SenderNodePeerId: obcClient.User.P2PLocalPeerId,
		SenderUserPeerId: obcClient.User.PeerId,
		Data:             string(infoBytes)}
	_, dataBytes, status := obcClient.HtlcHModule(requestMessage)

	data := string(dataBytes)
	if status == false {
		return nil, errors.New(data)
	}
	dataMap := make(map[string]interface{})
	_ = json.Unmarshal(dataBytes, &dataMap)

	resp := &pb.AddInvoiceResponse{PaymentRequest: data}
	return resp, nil
}

func (s *RpcServer) ParseInvoice(ctx context.Context, in *pb.ParseInvoiceRequest) (*pb.ParseInvoiceResponse, error) {
	log.Println("ParseInvoice")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}

	if tool.CheckIsString(&in.PaymentRequest) == false {
		return nil, errors.New("wrong invoice")
	}

	request := ParseInvoice{
		Invoice: in.PaymentRequest,
	}

	infoBytes, _ := json.Marshal(request)
	requestMessage := bean.RequestMessage{
		Type:             enum.MsgType_HTLC_ParseInvoice_403,
		SenderNodePeerId: obcClient.User.P2PLocalPeerId,
		SenderUserPeerId: obcClient.User.PeerId,
		Data:             string(infoBytes)}
	_, dataBytes, status := obcClient.HtlcHModule(requestMessage)

	data := string(dataBytes)
	if status == false {
		return nil, errors.New(data)
	}

	dataMap := make(map[string]interface{})
	_ = json.Unmarshal(dataBytes, &dataMap)

	resp := &pb.ParseInvoiceResponse{
		Memo:                dataMap["description"].(string),
		PropertyId:          int64(dataMap["property_id"].(float64)),
		Value:               dataMap["amount"].(float64),
		CltvExpiry:          dataMap["expiry_time"].(string),
		H:                   dataMap["h"].(string),
		Private:             dataMap["is_private"].(bool),
		RecipientNodePeerId: dataMap["recipient_node_peer_id"].(string),
		RecipientUserPeerId: dataMap["recipient_user_peer_id"].(string),
	}
	return resp, nil
}
func (s *RpcServer) ListInvoices(ctx context.Context, in *pb.ListInvoiceRequest) (*pb.ListInvoiceResponse, error) {
	log.Println("ParseInvoice")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}

	infoBytes, _ := json.Marshal(in)

	data, err := service.HtlcQueryTxManager.ListInvoices(string(infoBytes), *obcClient.User)
	if err != nil {
		return nil, err
	}

	resp := &pb.ListInvoiceResponse{
		FirstIndexOffset: uint64(data["first_index_offset"].(int64)),
		LastIndexOffset:  uint64(data["last_index_offset"].(int64)),
	}
	invoices := data["invoices"].([]dao.InvoiceInfo)
	for _, item := range invoices {
		invoice := &pb.Invoice{}
		invoice.PropertyId = item.Detail.PropertyId
		invoice.Value = item.Detail.Amount
		invoice.Private = item.Detail.IsPrivate
		invoice.CltvExpiry = item.Detail.ExpiryTime.String()
		invoice.Memo = item.Detail.Description
		invoice.PaymentRequest = item.Invoice
		resp.Invoices = append(resp.Invoices, invoice)
	}
	return resp, nil
}

func (s *RpcServer) SendPayment(ctx context.Context, in *pb.SendRequest) (*pb.SendResponse, error) {
	log.Println("SendPayment")
	_, err := checkLogin()
	if err != nil {
		return nil, err
	}

	if tool.CheckIsString(&in.PaymentRequest) == false {
		return nil, errors.New("wrong payment_request")
	}

	request := bean.HtlcRequestFindPath{
		Invoice: in.PaymentRequest,
	}
	infoBytes, _ := json.Marshal(request)
	requestMessage := bean.RequestMessage{
		Type:             enum.MsgType_HTLC_FindPath_401,
		SenderNodePeerId: obcClient.User.P2PLocalPeerId,
		SenderUserPeerId: obcClient.User.PeerId,
		Data:             string(infoBytes)}
	obcClient.HtlcHModule(requestMessage)

	if obcClient.GrpcChan == nil {
		obcClient.GrpcChan = make(chan []byte)
	}

	message := <-obcClient.GrpcChan

	close(obcClient.GrpcChan)
	obcClient.GrpcChan = nil

	replyMessage := bean.ReplyMessage{}
	_ = json.Unmarshal(message, &replyMessage)
	if replyMessage.Status == false {
		return nil, errors.New(replyMessage.Result.(string))
	}

	dataResult := replyMessage.Result.(map[string]interface{})
	resp := &pb.SendResponse{
		PaymentHash:     dataResult["htlc_routing_packet"].(string),
		PaymentPreimage: dataResult["htlc_h"].(string),
		AmountToRsmc:    dataResult["amount_to_rsmc"].(float64),
		AmountToHtlc:    dataResult["amount_to_htlc"].(float64),
	}
	if dataResult["amount_to_counterparty"] != nil {
		resp.AmountToCounterparty = dataResult["amount_to_counterparty"].(float64)
	}

	return resp, nil
}


<|start_filename|>tracker/router/router.go<|end_filename|>
package router

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/omnilaboratory/obd/tracker/service"
	"github.com/satori/go.uuid"
	"net/http"
	"strings"
)

func InitRouter() *gin.Engine {
	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	router.Use(gin.Logger())
	router.Use(gin.Recovery())
	router.Use(cors())
	go service.ObdNodeManager.TrackerStart()
	router.GET("/ws", wsClientConnect)

	apiv1 := router.Group("/api/v1/")
	{
		apiv1.GET("GetHtlcCurrState", service.HtlcService.GetHtlcCurrState)
		apiv1.GET("getChannelState", service.ChannelService.GetChannelState)
		apiv1.GET("getUserState", service.NodeAccountService.GetUserState)
		apiv1.GET("getUserP2pNodeId", service.NodeAccountService.GetUserP2pNodeId)
		apiv1.GET("getNodeInfoByP2pAddress", service.NodeAccountService.GetNodeInfoByP2pAddress)
	}
	apiv2 := router.Group("/api/common/")
	{
		apiv2.GET("getObdNodes", service.NodeAccountService.GetAllObdNodes)
		apiv2.GET("getUsers", service.NodeAccountService.GetAllUsers)
		apiv2.GET("getChannels", service.ChannelService.GetChannels)
	}

	apiv3 := router.Group("/api/rpc/")
	{
		apiv3.GET("getChainNodeType", service.RpcService.GetChainNodeType)
		apiv3.GET("getBlockCount", service.RpcService.GetBlockCount)
		apiv3.GET("getOmniBalance", service.RpcService.GetOmniBalance)
		apiv3.GET("getBalanceByAddress", service.RpcService.GetBalanceByAddress)
		apiv3.GET("importAddress", service.RpcService.ImportAddress)
		apiv3.GET("listReceivedByAddress", service.RpcService.ListReceivedByAddress)
		apiv3.GET("getTransactionById", service.RpcService.GetTransactionById)
		apiv3.GET("omniGettransaction", service.RpcService.OmniGettransaction)
		apiv3.GET("omniGetProperty", service.RpcService.OmniGetProperty)
		apiv3.POST("createRawTransaction", service.RpcService.CreateRawTransaction)
		apiv3.GET("estimateSmartFee", service.RpcService.EstimateSmartFee)
		apiv3.GET("listUnspent", service.RpcService.ListUnspent)
		apiv3.GET("omniGetAllBalancesForAddress", service.RpcService.OmniGetAllBalancesForAddress)
		apiv3.GET("omniGetBalancesForAddress", service.RpcService.OmniGetBalancesForAddress)
		apiv3.GET("testMemPoolAccept", service.RpcService.TestMemPoolAccept)
		apiv3.GET("sendRawTransaction", service.RpcService.SendRawTransaction)
		apiv3.GET("omniDecodeTransaction", service.RpcService.OmniDecodeTransaction)
		apiv3.GET("omniListTransactions", service.RpcService.OmniListTransactions)
		apiv3.GET("getNewAddress", service.RpcService.GetNewAddress)
		apiv3.GET("omniSend", service.RpcService.OmniSend)
		apiv3.GET("omniListProperties", service.RpcService.OmniListProperties)
		apiv3.GET("omniSendIssuanceFixed", service.RpcService.OmniSendIssuanceFixed)
		apiv3.GET("omniSendIssuanceManaged", service.RpcService.OmniSendIssuanceManaged)
		apiv3.GET("omniSendGrant", service.RpcService.OmniSendGrant)
		apiv3.GET("omniSendRevoke", service.RpcService.OmniSendRevoke)
		apiv3.GET("btcSignRawTransactionFromJson", service.RpcService.BtcSignRawTransactionFromJson)
		apiv3.GET("getMiningInfo", service.RpcService.GetMiningInfo)
		apiv3.GET("getNetworkInfo", service.RpcService.GetNetworkInfo)
	}

	return router
}

//跨域
func cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method               //请求方法
		origin := c.Request.Header.Get("Origin") //请求头部
		var headerKeys []string                  // 声明请求头keys
		for k, _ := range c.Request.Header {
			headerKeys = append(headerKeys, k)
		}
		headerStr := strings.Join(headerKeys, ", ")
		if headerStr != "" {
			headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
		} else {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}
		if origin != "" {
			c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
			c.Header("Access-Control-Allow-Origin", "*")                                       // 这是允许访问所有域
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") //服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
			//  header的类型
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
			//              允许跨域设置                                                                                                      可以返回其他子段
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析
			c.Header("Access-Control-Max-Age", "172800")                                                                                                                                                           // 缓存请求信息 单位为秒
			c.Header("Access-Control-Allow-Credentials", "false")                                                                                                                                                  //  跨域请求是否需要带cookie信息 默认设置为true
			c.Set("content-type", "application/json")                                                                                                                                                              // 设置返回格式是json
		}

		//放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "Options Request!")
		}
		// 处理请求
		c.Next() //  处理请求
	}
}

func wsClientConnect(c *gin.Context) {
	conn, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}).Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		http.NotFound(c.Writer, c.Request)
		return
	}
	uuidStr := uuid.NewV4()
	newClient := &service.ObdNode{
		Id:          uuidStr.String(),
		Socket:      conn,
		SendChannel: make(chan []byte)}
	service.ObdNodeManager.Connected <- newClient
	go newClient.Write()
	go newClient.Read()
}


<|start_filename|>dao/pojo_obd.go<|end_filename|>
package dao

import "time"

type RDTxWaitingSend struct {
	Id                int       `storm:"id,increment" json:"id" `
	TransactionHex    string    `json:"transaction_hex"`
	Type              int       `json:"type"`                   // 0: RD 1000, 1:HT1a  2:htd1b
	HtnxIdAndHtnxRdId []int     `json:"htnx_id_and_htnx_rd_id"` // for ht1a later logic
	IsEnable          bool      `json:"is_enable"`
	CreateAt          time.Time `json:"create_at"`
	FinishAt          time.Time `json:"finish_at"`
}

type ObdConfig struct {
	Id              int    `storm:"id,increment" json:"id" `
	InitHashCode    string `json:"init_hash_code"`
	AdminLoginToken string `json:"admin_login_token"`
}


<|start_filename|>proxy/tests/rpcclient_htlc_test.go<|end_filename|>
package main

import (
	"context"
	"encoding/json"
	proxy "github.com/omnilaboratory/obd/proxy/pb"
	"google.golang.org/grpc"
	"log"
	"testing"
)

func TestAddInvoice(t *testing.T) {

	client, conn := getHtlcClient()
	defer conn.Close()

	invoice, err := client.AddInvoice(context.Background(), &proxy.Invoice{
		CltvExpiry: "2021-08-15",
		Value:      0.001,
		PropertyId: 137,
		Private:    false,
	})
	if err != nil {
		log.Println(err)
		return
	}
	log.Println(invoice.PaymentRequest)
}

func TestListInvoices(t *testing.T) {

	client, conn := getHtlcClient()
	defer conn.Close()

	resp, err := client.ListInvoices(context.Background(), &proxy.ListInvoiceRequest{
		Reversed:       false,
		IndexOffset:    0,
		NumMaxInvoices: 10,
	})

	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(resp)
	log.Println(string(marshal))
}

func TestParseInvoice(t *testing.T) {
	client, conn := getHtlcClient()
	defer conn.Close()
	invoice, err := client.ParseInvoice(context.Background(), &proxy.ParseInvoiceRequest{
		PaymentRequest: "obtb100000s1pqzyfnpwQmccE4s2uhEXrJXE778NChn1ed8NyWNyAHH23mP7f9NM3Luzq63167817c979ade9e42f3204404c1513a4b1b4e9eea654c9498ed9cc920dbb36hzz03a0f341f5df657c288eae6c8f6256871b029489928302541267d4ec2e779983b2xq8ps306yqtqp0dqtdescription3gc",
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(invoice)
	log.Println(string(marshal))
}

func TestSendPayment(t *testing.T) {

	client, conn := getHtlcClient()
	defer conn.Close()

	htlcPayment, err := client.SendPayment(context.Background(), &proxy.SendRequest{
		PaymentRequest: "<KEY>",
		InvoiceDetail: &proxy.ParseInvoiceResponse{
			PropertyId:          137,
			Value:               0.001,
			Memo:                "description",
			CltvExpiry:          "2021-08-15",
			H:                   "03cadca1eaca9fa258e07296cc947a5551c75bb3fd0d5769d603fe7733ded72992",
			RecipientNodePeerId: "QmccE4s2uhEXrJXE778NChn1ed8NyWNyAHH23mP7f9NM3L",
			RecipientUserPeerId: "63167817c979ade9e42f3204404c1513a4b1b4e9eea654c9498ed9cc920dbb36",
		},
	})
	if err != nil {
		log.Println(err)
		return
	}
	marshal, _ := json.Marshal(htlcPayment)
	log.Println(string(marshal))
}

func getHtlcClient() (proxy.HtlcClient, *grpc.ClientConn) {

	opts := grpc.WithInsecure()
	conn, err := grpc.Dial("localhost:50051", opts)
	if err != nil {
		log.Println(err)
		return nil, nil
	}
	return proxy.NewHtlcClient(conn), conn
}


<|start_filename|>proxy/rpc/msg_center.go<|end_filename|>
package rpc

import (
	"crypto/x509"
	"encoding/json"
	"github.com/gorilla/websocket"
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/bean/enum"
	"github.com/omnilaboratory/obd/lightclient"
	"log"
	"net/http/httptest"
	"strings"
	"time"
)

var (
	loginChan          = make(chan bean.ReplyMessage)
	logoutChan         = make(chan bean.ReplyMessage)
	changePasswordChan = make(chan bean.ReplyMessage)
	openChannelChan    = make(chan bean.ReplyMessage)
	fundChannelChan    = make(chan bean.ReplyMessage)
	rsmcChan           = make(chan bean.ReplyMessage)
	addInvoiceChan     = make(chan bean.ReplyMessage)
	payInvoiceChan     = make(chan bean.ReplyMessage)
	onceRequestChan    = make(chan bean.ReplyMessage)
)

var obcClient *lightclient.Client

func ConnToObd() (err error) {

	obcClient = &lightclient.Client{IsGRpcRequest: true}

	////u := url.URL{Scheme: "wss", Host: "127.0.0.1:60020", Path: "/ws" + config.ChainNodeType}
	//u := url.URL{Scheme: "ws", Host: "127.0.0.1:60020", Path: "/ws" + config.ChainNodeType}
	//log.Printf("grpc begin to connect to obd: %s", u.String())
	//
	//dailer := websocket.DefaultDialer
	////dailer.TLSClientConfig =&tls.Config{InsecureSkipVerify: true}
	//
	//header := http.Header{}
	//header.Add("session", tool.GetGRpcSession())
	//
	//connObd, _, err = dailer.Dial(u.String(), header)
	//if err != nil {
	//	log.Println("fail to dial obd:", err)
	//	return err
	//}
	//connObd.SetReadLimit(1 << 20)
	//
	//go readDataFromObd()

	return nil
}

func rootCAs(s *httptest.Server) *x509.CertPool {
	certs := x509.NewCertPool()
	for _, c := range s.TLS.Certificates {
		roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1])
		if err != nil {
			log.Println("error parsing server's root cert: %v", err)
		}
		for _, root := range roots {
			certs.AddCert(root)
		}
	}
	return certs
}

func readDataFromObd() {
	defer func() {
		if connObd != nil {
			_ = connObd.Close()
		}
		ConnToObd()
	}()

	go func() {
		for {
			log.Println("waiting message...")
			_, message, err := connObd.ReadMessage()
			log.Println(string(message))
			if err != nil {
				log.Println(err)
				return
			}
			replyMessage := bean.ReplyMessage{}
			_ = json.Unmarshal(message, &replyMessage)

			if currUserInfo != nil {
				if strings.Contains(replyMessage.To, currUserInfo.UserPeerId) == false {
					continue
				}
			}

			switch replyMessage.Type {
			case enum.MsgType_GetMnemonic_2004:
				onceRequestChan <- replyMessage
			case enum.MsgType_UserLogin_2001:
				if strings.Contains(replyMessage.From, replyMessage.To) {
					loginChan <- replyMessage
				}
			case enum.MsgType_User_UpdateAdminToken_2008:
				changePasswordChan <- replyMessage
			case enum.MsgType_UserLogout_2002:
				logoutChan <- replyMessage

			case enum.MsgType_SendChannelOpen_32:
				openChannelChan <- replyMessage
			case enum.MsgType_RecvChannelAccept_33:
				openChannelChan <- replyMessage

			case enum.MsgType_Funding_134:
				fundChannelChan <- replyMessage
			case enum.MsgType_FundingCreate_SendBtcFundingCreated_340:
				fundChannelChan <- replyMessage
			case enum.MsgType_FundingSign_RecvBtcSign_350:
				fundChannelChan <- replyMessage
			case enum.MsgType_ClientSign_AssetFunding_AliceSignRD_1134:
				fundChannelChan <- replyMessage

			case enum.MsgType_CommitmentTx_SendCommitmentTransactionCreated_351:
				if replyMessage.Status == false {
					rsmcChan <- replyMessage
				}
				break
			case enum.MsgType_ClientSign_CommitmentTx_AliceSignC2a_360:
				rsmcChan <- replyMessage

			case enum.MsgType_HTLC_Invoice_402:
				addInvoiceChan <- replyMessage

			case enum.MsgType_HTLC_ParseInvoice_403:
				onceRequestChan <- replyMessage

			case enum.MsgType_HTLC_FindPath_401:
				if replyMessage.Status == false {
					payInvoiceChan <- replyMessage
				}
				break
			case enum.MsgType_HTLC_FinishTransferH_43:
				payInvoiceChan <- replyMessage
			default:
				continue
			}
		}
	}()

	ticker := time.NewTicker(time.Minute * 2)
	defer ticker.Stop()

	defer func(ticker *time.Ticker) {
		if r := recover(); r != nil {
			log.Println("grpc server goroutine recover")
			ticker.Stop()
			connObd = nil
		}
	}(ticker)

	for {
		select {
		case t := <-ticker.C:
			if connObd != nil {
				info := make(map[string]interface{})
				info["type"] = enum.MsgType_HeartBeat_2007
				info["data"] = t.String()
				bytes, err := json.Marshal(info)
				err = connObd.WriteMessage(websocket.TextMessage, bytes)
				if err != nil {
					connObd = nil
					return
				}
			} else {
				return
			}
		}
	}
}

func sendMsgToObd(info interface{}, RecipientNodePeerId, RecipientUserPeerId string, msgType enum.MsgType) {
	if connObd == nil {
		ConnToObd()
	}
	var infoBytes []byte
	if info != nil {
		infoBytes, _ = json.Marshal(info)
	}
	requestMessage := bean.RequestMessage{Data: string(infoBytes), Type: msgType}
	requestMessage.RecipientNodePeerId = RecipientNodePeerId
	requestMessage.RecipientUserPeerId = RecipientUserPeerId
	msg, _ := json.Marshal(requestMessage)

	err := connObd.WriteMessage(websocket.TextMessage, msg)
	if err != nil {
		connObd.Close()
		ConnToObd()
		sendMsgToObd(info, RecipientNodePeerId, RecipientUserPeerId, msgType)
		return
	}
}


<|start_filename|>omnicore/local_script_tool_test.go<|end_filename|>
package omnicore

import (
	"github.com/omnilaboratory/obd/bean"
	"github.com/omnilaboratory/obd/tool"
	"log"
	"testing"
)

func TestCreateMultiSig(t *testing.T) {
	htlcPathArr := []string{"a", "b", "c"}
	for i := len(htlcPathArr) - 1; i >= 0; i-- {
		log.Println(htlcPathArr[i])
	}

	//s, i, i2 := CreateMultiSigAddr("02c57b02d24356e1d31d34d2e3a09f7d68a4bdec6c0556595bb6391ce5d6d4fc66", "032dedba91b8ed7fb32dec1e2270bd451dee3521d1d9f53059a05830b4aa0d635b", tool.GetCoreNet())
	//log.Println(s)
	//log.Println(i)
	//log.Println(i2)
}

func TestVerifyOmniTxHex(t *testing.T) {
	log.Println("")
	hex1 := "02000000014a70d07e31d14d38784e682e0f6e3030761e958f7e8921be7965c7ea7cfd3c570000000000ffffffff03d6b69a3b000000001976a9147f0e0a2d415ce772724256f37863be77b539c87388ac0000000000000000166a146f6d6e6900000000000000030000000005f5e100220200000000000017a9143bc71ced09cb087c2916cd5bbcf6f41bb7a721bb8700000000"
	transaction := DecodeRawTransaction(hex1, tool.GetCoreNet())
	log.Println(transaction)
	log.Println("omnicore 签名结果")

}

func TestSign(t *testing.T) {
	redeemhex := "0200000002acbd057ae190cd8fdad4c989fc8216cd9137814620eaf48bc0ff919888e534f30000000000e8030000acbd057ae190cd8fdad4c989fc8216cd9137814620eaf48bc0ff919888e534f30200000000e8030000034a140000000000001976a914928f34815d1a8f54afe239ad68391fcddb505a6588ac0000000000000000166a146f6d6e6900000000000000890000000005f5e10022020000000000001976a914928f34815d1a8f54afe239ad68391fcddb505a6588ac00000000"
	inputs := []bean.RawTxInputItem{}

	item := bean.RawTxInputItem{}
	item.ScriptPubKey = "a9143833fc9817cadba3088022c6cc3687fdda33558687"
	redeemScript := "522103af0e670036b6365494a3ca0ed1bccbfd810f71ac3a119903d514af79c17b33a02102a488048de367beb56aff7768c34d976c5b59c37c5faf009f6ae5a469f0c9e6e452ae"
	item.RedeemScript = redeemScript
	inputs = append(inputs, item)

	item = bean.RawTxInputItem{}
	item.ScriptPubKey = "a9143833fc9817cadba3088022c6cc3687fdda33558687"
	redeemScript = "522103af0e670036b6365494a3ca0ed1bccbfd810f71ac3a119903d514af79c17b33a02102a488048de367beb56aff7768c34d976c5b59c37c5faf009f6ae5a469f0c9e6e452ae"
	item.RedeemScript = redeemScript
	inputs = append(inputs, item)

	privkey := "<KEY>"
	sign, err := SignRawHex(inputs, redeemhex, privkey, 2)
	log.Println(err)
	transaction := DecodeRawTransaction(sign, tool.GetCoreNet())
	log.Println("第一次 完成", sign)
	log.Println("第一次 完成", transaction)

	redeemhex = sign
	privkey = "<KEY>"
	sign, err = SignRawHex(inputs, redeemhex, privkey, 1)
	transaction = DecodeRawTransaction(sign, tool.GetCoreNet())
	log.Println("第二次 完成", sign)
	log.Println("第二次 完成", transaction)
}


<|start_filename|>tests/integration/Dockerfile<|end_filename|>
FROM ubuntu

RUN apt-get update && apt-get install -y python3.9 python3-pip

WORKDIR /test
COPY  reqs.txt .
RUN python3.9 -m pip install -r reqs.txt

COPY omnibolt.py .
COPY omnicore_connection.py .
COPY runner.py .
COPY test.py .
COPY bitcoin.conf .
COPY conf.tracker.ini .

ENV OMNI_BOLT_ALICE=omnibolt_alice:60020
ENV OMNI_BOLT_BOB=omnibolt_bob:60020
ENV BITCOIN_CONF=/test/bitcoin.conf

ENTRYPOINT [ "python3.9", "-m", "pytest", "test.py" ]
