// GetRawTx get raw tx by txid. // mode: GET // url: /api/v1/rawtx?coin_type=[:coin_type]&txid=[:txid] func GetRawTx(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // get coin type cp := r.FormValue("coin_type") if cp == "" { logger.Error("no coin type") rlt = pp.MakeErrRes(errors.New("no coin type")) break } // get txid txid := r.FormValue("txid") if txid == "" { logger.Error("no txid") rlt = pp.MakeErrRes(errors.New("no txid")) break } req := pp.GetRawTxReq{ CoinType: pp.PtrString(cp), Txid: pp.PtrString(txid), } var res pp.GetRawTxRes if err := sknet.EncryGet(se.GetServAddr(), "/get/rawtx", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
func TestGetOutput(t *testing.T) { type args struct { hash string } tests := []struct { name string args args want *pp.Output wantErr error }{ // TODO: Add test cases. { "normal", args{ "a57c038591f862b8fada57e496ef948183b153348d7932921f865a8541a477c5", }, &pp.Output{ Time: pp.PtrUint64(1477037552), SrcBlockSeq: pp.PtrUint64(443), SrcTx: pp.PtrString("b8ca61c0788bd711c89563f9bc60add172ee01b543ea5dcb1955c51bbfcbbaa2"), OwnerAddress: pp.PtrString("cBnu9sUvv12dovBmjQKTtfE4rbjMmf3fzW"), Coins: pp.PtrUint64(1000000), Hours: pp.PtrUint64(7), SpentBlockSeq: pp.PtrUint64(450), SpentTx: pp.PtrString("b1481d614ffcc27408fe2131198d9d2821c78601a0aa23d8e9965b2a5196edc0"), }, nil, }, { "invalid uxhash len", args{ "123", }, nil, errors.New("invalid output hash, encoding/hex: odd length hex string"), }, { "invalid uxhash ", args{ "a57c038591f862b8fada57e496ef948183b153348d7932921f865a8541a477c7", }, nil, errors.New("not found\n"), }, } for _, tt := range tests { got, err := GetOutput("127.0.0.1:6420", tt.args.hash) if !reflect.DeepEqual(err, tt.wantErr) { t.Errorf("%q. GetOutput() error = %v, wantErr %v", tt.name, err, tt.wantErr) continue } if !reflect.DeepEqual(got, tt.want) { t.Errorf("%q. GetOutput() = %v, want %v", tt.name, got, tt.want) } } }
// GetWalletBalance get local wallet balance. // mode: GET // url: /api/v1/wallet/balance?id=[:id] // params: // id: wallet id. func GetWalletBalance(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { id := r.FormValue("id") if id == "" { err := errors.New("id is empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // get addresses in wallet. addrs, err := wallet.GetAddresses(id) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } if len(addrs) == 0 { res := pp.GetAddrBalanceRes{ Result: pp.MakeResult(pp.ErrCode_NotExits, "wallet have no address"), } sendJSON(w, &res) return } cp := strings.Split(id, "_")[0] // get address balance. req := pp.GetAddrBalanceReq{ CoinType: pp.PtrString(cp), Addrs: pp.PtrString(strings.Join(addrs, ",")), } var res pp.GetAddrBalanceRes if err := sknet.EncryGet(se.GetServAddr(), "/get/address/balance", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
func (bn bitcoinCli) BroadcastTx(rawtx string) (string, error) { req := pp.InjectTxnReq{ CoinType: pp.PtrString("bitcoin"), Tx: pp.PtrString(rawtx), } res := pp.InjectTxnRes{} if err := sknet.EncryGet(bn.NodeAddr, "/inject/tx", req, &res); err != nil { return "", err } if !res.Result.GetSuccess() { return "", fmt.Errorf("broadcast tx failed: %v", res.Result.GetReason()) } return res.GetTxid(), nil }
// CreateOrder create order through exchange server. // mode: POST // url: /api/v1/account/order?coin_pair=[:coin_pair]&type=[:type]&price=[:price]&amt=[:amt] // params: // coin_pair: order coin pair. // type: order type, can be bid or ask. // price: price. // amt: amount. func CreateOrder(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { req, err := makeOrderReq(r) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } req.Pubkey = pp.PtrString(a.Pubkey) var res pp.OrderRes if err := sknet.EncryGet(se.GetServAddr(), "/create/order", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
// GetRawTx return rawtx of specifc tx. func GetRawTx(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { var rlt *pp.EmptyRes for { req := pp.GetRawTxReq{} if err := c.BindJSON(&req); err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } coin, err := egn.GetCoin(req.GetCoinType()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } rawtx, err := coin.GetRawTx(req.GetTxid()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } res := pp.GetRawTxRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), CoinType: req.CoinType, Rawtx: pp.PtrString(rawtx), } return c.SendJSON(&res) } return c.Error(rlt) } }
// GetCoins get supported coins from exchange server. func GetCoins(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } req := pp.GetCoinsReq{ Pubkey: pp.PtrString(a.Pubkey), } var res pp.CoinsRes if err := sknet.EncryGet(se.GetServAddr(), "/get/coins", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
// GetTransactionByID gets transaction verbose info by id func (cn coinEx) GetTransactionByID(txid string) (string, error) { req := pp.GetTxReq{ CoinType: pp.PtrString(cn.Name), Txid: pp.PtrString(txid), } res := pp.GetTxRes{} if err := sknet.EncryGet(cn.NodeAddr, "/get/tx", req, &res); err != nil { return "", err } if !res.Result.GetSuccess() { return "", fmt.Errorf("get %s transaction by id failed: %v", cn.Name, res.Result.GetReason()) } d, err := json.Marshal(res.GetTx()) if err != nil { return "", err } return string(d), nil }
func makeOrderReq(r *http.Request) (*pp.OrderReq, error) { // get coin_pair cp := r.FormValue("coin_pair") if cp == "" { return nil, errors.New("coin_pair is empty") } // get order type tp := r.FormValue("type") if tp == "" { return nil, errors.New("type is empty") } // get price pc := r.FormValue("price") if pc == "" { return nil, errors.New("price is empty") } price, err := strconv.ParseUint(pc, 10, 64) if err != nil { return nil, err } // get amount amt := r.FormValue("amt") if amt == "" { return nil, errors.New("amt is empty") } amount, err := strconv.ParseUint(amt, 10, 64) if err != nil { return nil, err } return &pp.OrderReq{ CoinPair: pp.PtrString(cp), Type: pp.PtrString(tp), Price: pp.PtrUint64(price), Amount: pp.PtrUint64(amount), }, nil }
// GetUtxos gets bitcoin utxos of specific addresses. func (btc *Bitcoin) GetUtxos(addrs []string) (interface{}, error) { utxos, err := GetUnspentOutputs(addrs) if err != nil { return nil, err } btcUxs := make([]*pp.BtcUtxo, len(utxos)) for i, u := range utxos { btcUxs[i] = &pp.BtcUtxo{ Address: pp.PtrString(u.GetAddress()), Txid: pp.PtrString(u.GetTxid()), Vout: pp.PtrUint32(u.GetVout()), Amount: pp.PtrUint64(u.GetAmount()), } } var res = pp.GetUtxoRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), BtcUtxos: btcUxs, } return res, nil }
// MakeRequest creates request func MakeRequest(path string, data interface{}) (*Request, error) { r := &Request{} r.Path = pp.PtrString(path) if data == nil { return r, nil } d, err := json.Marshal(data) if err != nil { return nil, err } r.Data = d[:] return r, nil }
// InjectTx broadcast transaction. // mode: POST // url: /api/v1/inject_rawtx?rawtx=[:rawtx]&coin_type=[:coin_type] // params: // rawtx: raw tx that's going to be injected. // coin_type: skycoin or bitcoin. func InjectTx(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // get tx rawtx := r.FormValue("rawtx") if rawtx == "" { err := errors.New("rawtx is empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // get coin type cp := r.FormValue("coin_type") if cp == "" { logger.Error("empty coin type") rlt = pp.MakeErrRes(errors.New("empty coin type")) break } req := pp.InjectTxnReq{ CoinType: pp.PtrString(cp), Tx: pp.PtrString(rawtx), } var res pp.InjectTxnRes if err := sknet.EncryGet(se.GetServAddr(), "/inject/tx", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
// GetDepositAddress get deposit address from exchange server. func GetDepositAddress(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } cp := r.FormValue("coin_type") if cp == "" { err := errors.New("coin type empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } req := pp.GetDepositAddrReq{ Pubkey: pp.PtrString(a.Pubkey), CoinType: pp.PtrString(cp), } var res pp.GetDepositAddrRes if err := sknet.EncryGet(se.GetServAddr(), "/create/deposit_address", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
func (bn bitcoinCli) getOutputs(addrs []string) ([]*pp.BtcUtxo, error) { req := pp.GetUtxoReq{ CoinType: pp.PtrString("bitcoin"), Addresses: addrs, } res := pp.GetUtxoRes{} if err := sknet.EncryGet(bn.NodeAddr, "/get/utxos", req, &res); err != nil { return nil, err } if !res.Result.GetSuccess() { return nil, fmt.Errorf("get utxos failed: %v", res.Result.GetReason()) } return res.BtcUtxos, nil }
func (bn bitcoinCli) GetBalance(addrs []string) (uint64, error) { req := pp.GetUtxoReq{ CoinType: pp.PtrString("bitcoin"), Addresses: addrs, } res := pp.GetUtxoRes{} if err := sknet.EncryGet(bn.NodeAddr, "/get/utxos", req, &res); err != nil { return 0, err } var bal uint64 for _, u := range res.BtcUtxos { bal += u.GetAmount() } return bal, nil }
func getOrders(se Servicer, tp string) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { cp := r.FormValue("coin_pair") st := r.FormValue("start") ed := r.FormValue("end") if cp == "" || st == "" || ed == "" || tp == "" { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } start, err := strconv.ParseInt(st, 10, 64) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } end, err := strconv.ParseInt(ed, 10, 64) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } req := pp.GetOrderReq{ CoinPair: &cp, Type: pp.PtrString(tp), Start: &start, End: &end, } var res pp.GetOrderRes if err := sknet.EncryGet(se.GetServAddr(), "/get/orders", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
func encrypt(r interface{}, pubkey string, seckey string) (*pp.EncryptReq, error) { encData, nonce, err := pp.Encrypt(r, pubkey, seckey) if err != nil { return nil, err } s, err := cipher.SecKeyFromHex(seckey) if err != nil { return nil, err } p := cipher.PubKeyFromSecKey(s) return &pp.EncryptReq{ Pubkey: pp.PtrString(p.Hex()), Nonce: nonce, Encryptdata: encData, }, nil }
// GetUtxos get utxos through exchange server. func GetUtxos(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { cp := r.FormValue("coin_type") if cp == "" { logger.Error("coin type empty") rlt = pp.MakeErrRes(errors.New("coin type empty")) break } addrs := r.FormValue("addrs") if addrs == "" { logger.Error("addrs empty") rlt = pp.MakeErrRes(errors.New("addrs empty")) break } addrArray := strings.Split(addrs, ",") for i, addr := range addrArray { addrArray[i] = strings.Trim(addr, " ") } req := pp.GetUtxoReq{ CoinType: pp.PtrString(cp), Addresses: addrArray, } var res pp.GetUtxoRes if err := sknet.EncryGet(se.GetServAddr(), "/get/utxos", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
// CreateAccount handle the request of creating account. func CreateAccount(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { // generate account pubkey/privkey pair, pubkey is the account id. errRlt := &pp.EmptyRes{} for { a := account.New() r := pp.CreateAccountReq{ Pubkey: pp.PtrString(a.Pubkey), } res := pp.CreateAccountRes{} if err := sknet.EncryGet(se.GetServAddr(), "/create/account", r, &res); err != nil { logger.Error(err.Error()) errRlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } // acntRes := res.(*pp.CreateAccountRes) if !res.GetResult().GetSuccess() { sendJSON(w, res) } else { ret := struct { Result pp.Result `json:"result"` Pubkey string `json:"pubkey"` CreatedAt int64 `json:"created_at"` }{ Result: *res.Result, Pubkey: a.Pubkey, CreatedAt: res.GetCreatedAt(), } account.Set(a) sendJSON(w, &ret) } return } sendJSON(w, errRlt) } }
// InjectTx inject transaction. func InjectTx(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { var rlt *pp.EmptyRes for { req := pp.InjectTxnReq{} if err := c.BindJSON(&req); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } // get coin gateway coin, err := egn.GetCoin(req.GetCoinType()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // inject tx. txid, err := coin.InjectTx(req.GetTx()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } res := pp.InjectTxnRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Txid: pp.PtrString(txid), } return c.SendJSON(&res) } return c.Error(rlt) } }
// AdminUpdateBalance update balance of specific account // mode: PUT // url: /api/v1/admin/account/balance?dst=[:dst]&coin_type=[:coin_type]&amt=[:amt] // params: // dst: the dst account pubkey, whose balance will be updated. // coin_type: skycoin or bitcoin, the coin you want to credit. // amt: balance that will be updated. func AdminUpdateBalance(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // get dst_pubkey dstPk := r.FormValue("dst") if dstPk == "" { err := errors.New("dst pubkey is empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // validate the dst_pubkey if _, err := cipher.PubKeyFromHex(dstPk); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(errors.New("invalid dst pubkey")) break } // get coin type. cp := r.FormValue("coin_type") if cp == "" { err := errors.New("coin_type is empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // get amt amt := r.FormValue("amt") if amt == "" { err := errors.New("amt is empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } amount, err := strconv.ParseUint(amt, 10, 64) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } req := pp.UpdateCreditReq{ Pubkey: pp.PtrString(a.Pubkey), CoinType: pp.PtrString(cp), Amount: pp.PtrUint64(amount), Dst: pp.PtrString(dstPk), } res := pp.UpdateCreditRes{} if err := sknet.EncryGet(se.GetServAddr(), "/admin/update/credit", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }