Implement apiSendTx and apiEstimateFee
This commit is contained in:
parent
db35a51dde
commit
d1176e17d1
@ -9,6 +9,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -128,6 +129,8 @@ func (s *PublicServer) ConnectFullPublicInterface() {
|
|||||||
serveMux.HandleFunc(path+"api/tx-specific/", s.jsonHandler(s.apiTxSpecific))
|
serveMux.HandleFunc(path+"api/tx-specific/", s.jsonHandler(s.apiTxSpecific))
|
||||||
serveMux.HandleFunc(path+"api/address/", s.jsonHandler(s.apiAddress))
|
serveMux.HandleFunc(path+"api/address/", s.jsonHandler(s.apiAddress))
|
||||||
serveMux.HandleFunc(path+"api/block/", s.jsonHandler(s.apiBlock))
|
serveMux.HandleFunc(path+"api/block/", s.jsonHandler(s.apiBlock))
|
||||||
|
serveMux.HandleFunc(path+"api/sendtx/", s.jsonHandler(s.apiSendTx))
|
||||||
|
serveMux.HandleFunc(path+"api/estimatefee/", s.jsonHandler(s.apiEstimateFee))
|
||||||
// socket.io interface
|
// socket.io interface
|
||||||
serveMux.Handle(path+"socket.io/", s.socketio.GetHandler())
|
serveMux.Handle(path+"socket.io/", s.socketio.GetHandler())
|
||||||
}
|
}
|
||||||
@ -217,7 +220,11 @@ func (s *PublicServer) jsonHandler(handler func(r *http.Request) (interface{}, e
|
|||||||
glog.Error(getFunctionName(handler), " error: ", err)
|
glog.Error(getFunctionName(handler), " error: ", err)
|
||||||
}
|
}
|
||||||
if s.debug {
|
if s.debug {
|
||||||
data = jsonError{fmt.Sprintf("Internal server error: %v, data %+v", err, data)}
|
if data != nil {
|
||||||
|
data = jsonError{fmt.Sprintf("Internal server error: %v, data %+v", err, data)}
|
||||||
|
} else {
|
||||||
|
data = jsonError{fmt.Sprintf("Internal server error: %v", err)}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
data = jsonError{"Internal server error"}
|
data = jsonError{"Internal server error"}
|
||||||
}
|
}
|
||||||
@ -537,7 +544,7 @@ func (s *PublicServer) explorerSendTx(w http.ResponseWriter, r *http.Request) (t
|
|||||||
data.Error = &api.ApiError{Text: err.Error(), Public: true}
|
data.Error = &api.ApiError{Text: err.Error(), Public: true}
|
||||||
return sendTransactionTpl, data, nil
|
return sendTransactionTpl, data, nil
|
||||||
}
|
}
|
||||||
data.Status = "Transaction sent " + res
|
data.Status = "Transaction sent, result " + res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sendTransactionTpl, data, nil
|
return sendTransactionTpl, data, nil
|
||||||
@ -677,3 +684,60 @@ func (s *PublicServer) apiBlock(r *http.Request) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
return block, err
|
return block, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type resultSendTransaction struct {
|
||||||
|
Result string `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PublicServer) apiSendTx(r *http.Request) (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
var res resultSendTransaction
|
||||||
|
s.metrics.ExplorerViews.With(common.Labels{"action": "api-sendtx"}).Inc()
|
||||||
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
|
hex := r.URL.Path[i+1:]
|
||||||
|
if len(hex) > 0 {
|
||||||
|
if len(hex) > 0 {
|
||||||
|
res.Result, err = s.chain.SendRawTransaction(hex)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, api.NewApiError("Missing tx blob", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
type resultEstimateFeeAsString struct {
|
||||||
|
Result string `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PublicServer) apiEstimateFee(r *http.Request) (interface{}, error) {
|
||||||
|
var res resultEstimateFeeAsString
|
||||||
|
s.metrics.ExplorerViews.With(common.Labels{"action": "api-estimatefee"}).Inc()
|
||||||
|
if i := strings.LastIndexByte(r.URL.Path, '/'); i > 0 {
|
||||||
|
b := r.URL.Path[i+1:]
|
||||||
|
if len(b) > 0 {
|
||||||
|
blocks, err := strconv.Atoi(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, api.NewApiError("Parameter 'number of blocks' is not a number", true)
|
||||||
|
}
|
||||||
|
conservative := true
|
||||||
|
c := r.URL.Query().Get("conservative")
|
||||||
|
if len(c) > 0 {
|
||||||
|
conservative, err = strconv.ParseBool(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, api.NewApiError("Parameter 'conservative' cannot be converted to boolean", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fee big.Int
|
||||||
|
fee, err = s.chain.EstimateSmartFee(blocks, conservative)
|
||||||
|
if err != nil {
|
||||||
|
fee, err = s.chain.EstimateFee(blocks)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.Result = s.chainParser.AmountToDecimalString(&fee)
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, api.NewApiError("Missing parameter 'number of blocks'", true)
|
||||||
|
}
|
||||||
|
|||||||
@ -338,7 +338,7 @@ func httpTests(t *testing.T, ts *httptest.Server) {
|
|||||||
`<a href="/" class="nav-link">Fake Coin Explorer</a>`,
|
`<a href="/" class="nav-link">Fake Coin Explorer</a>`,
|
||||||
`<h1>Send Raw Transaction</h1>`,
|
`<h1>Send Raw Transaction</h1>`,
|
||||||
`<textarea class="form-control" rows="8" name="hex">12341234</textarea>`,
|
`<textarea class="form-control" rows="8" name="hex">12341234</textarea>`,
|
||||||
`<div class="alert alert-danger">Not implemented</div></div>`,
|
`<div class="alert alert-danger">Invalid data</div>`,
|
||||||
`</html>`,
|
`</html>`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -400,12 +400,21 @@ func httpTests(t *testing.T, ts *httptest.Server) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "apiBlock",
|
name: "apiSendTx",
|
||||||
r: newGetRequest(ts.URL + "/api/block/225493"),
|
r: newGetRequest(ts.URL + "/api/sendtx/123456"),
|
||||||
status: http.StatusOK,
|
status: http.StatusOK,
|
||||||
contentType: "application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
body: []string{
|
body: []string{
|
||||||
`{"page":1,"totalPages":1,"itemsOnPage":1000,"hash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","previousblockhash":"","nextblockhash":"","height":225493,"confirmations":2,"size":1234567,"time":1534858021,"version":0,"merkleroot":"","nonce":0,"bits":"","difficulty":0,"TxCount":2,"txs":[{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vin":[],"vout":[{"value":"1","n":0,"scriptPubKey":{"hex":"","addresses":["mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti"]}},{"value":"0.00012345","n":1,"scriptPubKey":{"hex":"","addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"]}}],"blockhash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockheight":225493,"confirmations":2,"time":1534858021,"blocktime":1534858021,"valueOut":"1.00012345","valueIn":"0","fees":"0","hex":""},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"12345.67890123","n":0,"scriptPubKey":{"hex":"","addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"]}},{"value":"0.00000001","n":1,"scriptPubKey":{"hex":"","addresses":["2Mz1CYoppGGsLNUGF2YDhTif6J661JitALS"]}},{"value":"0.00009876","n":2,"scriptPubKey":{"hex":"","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"]}}],"blockhash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockheight":225493,"confirmations":2,"time":1534858021,"blocktime":1534858021,"valueOut":"12345.679","valueIn":"0","fees":"0","hex":""}]}`,
|
`{"result":"9876"}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "apiEstimateFee",
|
||||||
|
r: newGetRequest(ts.URL + "/api/estimatefee/123?conservative=false"),
|
||||||
|
status: http.StatusOK,
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
body: []string{
|
||||||
|
`{"result":"0.00012299"}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -522,7 +531,7 @@ func socketioTests(t *testing.T, ts *httptest.Server) {
|
|||||||
{
|
{
|
||||||
name: "sendTransaction",
|
name: "sendTransaction",
|
||||||
req: socketioReq{"sendTransaction", []interface{}{"010000000001019d64f0c72a0d206001decbffaa722eb1044534c"}},
|
req: socketioReq{"sendTransaction", []interface{}{"010000000001019d64f0c72a0d206001decbffaa722eb1044534c"}},
|
||||||
want: `{"error":{"message":"Not implemented"}}`,
|
want: `{"error":{"message":"Invalid data"}}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -635,10 +635,6 @@ func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetai
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type resultSendTransaction struct {
|
|
||||||
Result string `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SocketIoServer) sendTransaction(tx string) (res resultSendTransaction, err error) {
|
func (s *SocketIoServer) sendTransaction(tx string) (res resultSendTransaction, err error) {
|
||||||
txid, err := s.chain.SendRawTransaction(tx)
|
txid, err := s.chain.SendRawTransaction(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -158,7 +158,11 @@ func (c *fakeBlockChain) GetTransactionForMempool(txid string) (v *bchain.Tx, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) EstimateSmartFee(blocks int, conservative bool) (v big.Int, err error) {
|
func (c *fakeBlockChain) EstimateSmartFee(blocks int, conservative bool) (v big.Int, err error) {
|
||||||
v.SetInt64(int64(blocks) * 100)
|
if conservative == false {
|
||||||
|
v.SetInt64(int64(blocks)*100 - 1)
|
||||||
|
} else {
|
||||||
|
v.SetInt64(int64(blocks) * 100)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +172,10 @@ func (c *fakeBlockChain) EstimateFee(blocks int) (v big.Int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) SendRawTransaction(tx string) (v string, err error) {
|
func (c *fakeBlockChain) SendRawTransaction(tx string) (v string, err error) {
|
||||||
return "", errors.New("Not implemented")
|
if tx == "123456" {
|
||||||
|
return "9876", nil
|
||||||
|
}
|
||||||
|
return "", errors.New("Invalid data")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeBlockChain) ResyncMempool(onNewTxAddr bchain.OnNewTxAddrFunc) (count int, err error) {
|
func (c *fakeBlockChain) ResyncMempool(onNewTxAddr bchain.OnNewTxAddrFunc) (count int, err error) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user