Add socketio method getAccountInfo

ethereum
Martin Boehm 2018-12-05 11:41:07 +01:00
parent 3e532e9130
commit 55ae22bab1
6 changed files with 100 additions and 14 deletions

View File

@ -14,10 +14,10 @@ import (
type GetAddressOption int
const (
// ExistOnly - only that address is indexed
ExistOnly GetAddressOption = iota
// BalancesOnly - only balances
BalancesOnly
// Basic - only that address is indexed and some basic info
Basic GetAddressOption = iota
// Balance - only balances
Balance
// TxidHistory - balances and txids, subject to paging
TxidHistory
// TxHistory - balances and full tx data, subject to paging
@ -90,7 +90,9 @@ type Erc20Token struct {
Txs int `json:"txs"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Balance string `json:"balance"`
Decimal int `json:"decimal"`
Balance string `json:"balance,omitempty"`
BalanceSat string `json:"balanceSat,omitempty"`
ContractIndex string `json:"-"`
}
@ -123,7 +125,7 @@ type Tx struct {
ValueInSat big.Int `json:"-"`
Fees string `json:"fees"`
FeesSat big.Int `json:"-"`
Hex string `json:"hex"`
Hex string `json:"hex,omitempty"`
CoinSpecificData interface{} `json:"-"`
CoinSpecificJSON json.RawMessage `json:"-"`
Erc20Transfers []Erc20Transfer `json:"erc20transfers,omitempty"`
@ -132,9 +134,9 @@ type Tx struct {
// Paging contains information about paging for address, blocks and block
type Paging struct {
Page int `json:"page"`
TotalPages int `json:"totalPages"`
ItemsOnPage int `json:"itemsOnPage"`
Page int `json:"page,omitempty"`
TotalPages int `json:"totalPages,omitempty"`
ItemsOnPage int `json:"itemsOnPage,omitempty"`
}
// AddressFilterNone disables filtering of transactions
@ -158,6 +160,7 @@ type Address struct {
TxApperances int `json:"txApperances"`
Transactions []*Tx `json:"txs,omitempty"`
Txids []string `json:"transactions,omitempty"`
Nonce string `json:"nonce,omitempty"`
Erc20Contract *bchain.Erc20Contract `json:"erc20contract,omitempty"`
Erc20Tokens []Erc20Token `json:"erc20tokens,omitempty"`
Filter string `json:"-"`

View File

@ -448,7 +448,7 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
Txs: uint32(ca.EthTxs),
}
// do not read balances etc in case of ExistOnly option
if option != ExistOnly {
if option != Basic {
var b *big.Int
b, err = w.chain.EthereumTypeGetBalance(addrDesc)
if err != nil {
@ -526,7 +526,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetA
}
}
// if only check that the address exist, return if we have the address
if option == ExistOnly && ba != nil {
if option == Basic && ba != nil {
return &Address{AddrStr: address}, nil
}
// convert the address to the format defined by the parser
@ -554,7 +554,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetA
}
txm = UniqueTxidsInReverse(txm)
// check if the address exist
if len(txc)+len(txm) == 0 || option == ExistOnly {
if len(txc)+len(txm) == 0 || option == Basic {
return &Address{
AddrStr: address,
Balance: w.chainParser.AmountToDecimalString(&ba.BalanceSat),

View File

@ -554,7 +554,7 @@ func (s *PublicServer) explorerSearch(w http.ResponseWriter, r *http.Request) (t
http.Redirect(w, r, joinURL("/tx/", tx.Txid), 302)
return noTpl, nil, nil
}
address, err = s.api.GetAddress(q, 0, 1, api.ExistOnly, api.AddressFilterNone)
address, err = s.api.GetAddress(q, 0, 1, api.Basic, api.AddressFilterNone)
if err == nil {
http.Redirect(w, r, joinURL("/address/", address.AddrStr), 302)
return noTpl, nil, nil

View File

@ -103,6 +103,13 @@ var onMessageHandlers = map[string]func(*SocketIoServer, json.RawMessage) (inter
}
return
},
"getAccountInfo": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
req, err := unmarshalGetAccountInfoRequest(params)
if err == nil {
rv, err = s.getAccountInfo(req)
}
return
},
"getBlockHeader": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
height, hash, err := unmarshalGetBlockHeader(params)
if err == nil {
@ -207,6 +214,22 @@ func unmarshalGetAddressRequest(params []byte) (addr []string, opts addrOpts, er
return
}
type accountInfoReq struct {
Descriptor string `json:"descriptor"`
Details string `json:"details"`
PageSize int `json:"pageSize"`
Page int `json:"page"`
}
func unmarshalGetAccountInfoRequest(params []byte) (*accountInfoReq, error) {
var r accountInfoReq
err := json.Unmarshal(params, &r)
if err != nil {
return nil, err
}
return &r, nil
}
type resultAddressTxids struct {
Result []string `json:"result"`
}
@ -661,6 +684,24 @@ func (s *SocketIoServer) getMempoolEntry(txid string) (res resultGetMempoolEntry
return
}
func (s *SocketIoServer) getAccountInfo(req *accountInfoReq) (res *api.Address, err error) {
if s.chainParser.GetChainType() == bchain.ChainEthereumType {
var opt api.GetAddressOption
switch req.Details {
case "balance":
opt = api.Balance
case "txids":
opt = api.TxidHistory
case "txs":
opt = api.TxHistory
default:
opt = api.Basic
}
return s.api.GetAddress(req.Descriptor, req.Page, req.PageSize, opt, api.AddressFilterNone)
}
return nil, errors.New("Not implemented")
}
// onSubscribe expects two event subscriptions based on the req parameter (including the doublequotes):
// "bitcoind/hashblock"
// "bitcoind/addresstxid",["2MzTmvPJLZaLzD9XdN3jMtQA5NexC3rAPww","2NAZRJKr63tSdcTxTN3WaE9ZNDyXy6PgGuv"]

View File

@ -92,7 +92,7 @@
<div class="row h-container">
<h3 class="col-md-6 col-sm-12">Transactions</h3>
<div class="col-md-6 col-sm-12">
<select style="float: left;margin-top: 6px;" onchange="self.location='?filter='+options[selectedIndex].value">
<select style="float: left;margin-top: 6px;max-width: 30%;" onchange="self.location='?filter='+options[selectedIndex].value">
<option>All</option>
<option {{if eq $addr.Filter "inputs" -}} selected{{end}} value="inputs">Inputs</option>
<option {{if eq $addr.Filter "outputs" -}} selected{{end}} value="outputs">Outputs</option>

View File

@ -51,6 +51,26 @@
return socket.send({ method, params }, f);
}
function getAccountInfo() {
const descriptor = document.getElementById('getAccountInfoDescriptor').value.trim();
const selectDetails = document.getElementById('getAccountInfoDetails');
const details = selectDetails.options[selectDetails.selectedIndex].value;
const page = parseInt(document.getElementById("getAccountInfoPage").value);
const pageSize = 10;
const method = 'getAccountInfo';
const params = {
descriptor,
details,
page,
pageSize,
};
socket.send({ method, params}, function (result) {
console.log('getAccountInfo sent successfully');
console.log(result);
document.getElementById('getAccountInfoResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
});
}
function getAddressHistory() {
var addresses = document.getElementById('getAddressHistoryAddresses').value.split(",");
addresses = addresses.map(s => s.trim());
@ -264,6 +284,28 @@
<label id="connectionStatus">not connected</label>
</div>
</div>
<div class="row">
<div class="col">
<input class="btn btn-secondary" type="button" value="getAccountInfo" onclick="getAccountInfo()">
</div>
<div class="col-8">
<div class="row" style="margin: 0;">
<input type="text" style="width: 67.7%" class="form-control" id="getAccountInfoDescriptor" value="0x103262f243e6f67d12d6a4ea0d45302c1fa4bb0a">
<select id="getAccountInfoDetails" style="width: 20%; margin-left: 5px;">
<option value="basic">Basic</option>
<option value="balance">Balance</option>
<option value="txids">Txids</option>
<option value="txs">Transactions</option>
</select>
<input type="text" style="width: 10%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoPage" value="0">
</div>
</div>
<div class="col form-inline"></div>
</div>
<div class="row">
<div class="col" id="getAccountInfoResult">
</div>
</div>
<div class="row">
<div class="col">
<input class="btn btn-secondary" type="button" value="getAddressTxids" onclick="getAddressTxids()">