Refactor ethCall method to rpcCall

This commit is contained in:
Martin Boehm 2024-10-10 00:58:19 +02:00
parent 059086cd3d
commit 76664cdbf3
14 changed files with 57 additions and 57 deletions

View File

@ -77,7 +77,7 @@ func (b *BaseChain) EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor)
return nil, errors.New("not supported") return nil, errors.New("not supported")
} }
// EthereumTypeEthCall calls eth_call with given data and to address // EthereumTypeRpcCall calls eth_call with given data and to address
func (b *BaseChain) EthereumTypeEthCall(data, to, from string) (string, error) { func (b *BaseChain) EthereumTypeRpcCall(data, to, from string) (string, error) {
return "", errors.New("not supported") return "", errors.New("not supported")
} }

View File

@ -342,10 +342,10 @@ func (c *blockChainWithMetrics) EthereumTypeGetStakingPoolsData(addrDesc bchain.
return c.b.EthereumTypeGetStakingPoolsData(addrDesc) return c.b.EthereumTypeGetStakingPoolsData(addrDesc)
} }
// EthereumTypeEthCall calls eth_call with given data and to address // EthereumTypeRpcCall calls eth_call with given data and to address
func (c *blockChainWithMetrics) EthereumTypeEthCall(data, to, from string) (v string, err error) { func (c *blockChainWithMetrics) EthereumTypeRpcCall(data, to, from string) (v string, err error) {
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeEthCall", s, err) }(time.Now()) defer func(s time.Time) { c.observeRPCLatency("EthereumTypeRpcCall", s, err) }(time.Now())
return c.b.EthereumTypeEthCall(data, to, from) return c.b.EthereumTypeRpcCall(data, to, from)
} }
type mempoolWithMetrics struct { type mempoolWithMetrics struct {

View File

@ -273,8 +273,8 @@ func contractGetTransfersFromTx(tx *bchain.RpcTransaction) (bchain.TokenTransfer
return r, nil return r, nil
} }
// EthereumTypeEthCall calls eth_call with given data and to address // EthereumTypeRpcCall calls eth_call with given data and to address
func (b *EthereumRPC) EthereumTypeEthCall(data, to, from string) (string, error) { func (b *EthereumRPC) EthereumTypeRpcCall(data, to, from string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout) ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
defer cancel() defer cancel()
var r string var r string
@ -294,7 +294,7 @@ func (b *EthereumRPC) EthereumTypeEthCall(data, to, from string) (string, error)
func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, error) { func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, error) {
var contract bchain.ContractInfo var contract bchain.ContractInfo
data, err := b.EthereumTypeEthCall(contractNameSignature, address, "") data, err := b.EthereumTypeRpcCall(contractNameSignature, address, "")
if err != nil { if err != nil {
// ignore the error from the eth_call - since geth v1.9.15 they changed the behavior // ignore the error from the eth_call - since geth v1.9.15 they changed the behavior
// and returning error "execution reverted" for some non contract addresses // and returning error "execution reverted" for some non contract addresses
@ -305,14 +305,14 @@ func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, e
} }
name := strings.TrimSpace(parseSimpleStringProperty(data)) name := strings.TrimSpace(parseSimpleStringProperty(data))
if name != "" { if name != "" {
data, err = b.EthereumTypeEthCall(contractSymbolSignature, address, "") data, err = b.EthereumTypeRpcCall(contractSymbolSignature, address, "")
if err != nil { if err != nil {
// glog.Warning(errors.Annotatef(err, "Contract SymbolSignature %v", address)) // glog.Warning(errors.Annotatef(err, "Contract SymbolSignature %v", address))
return nil, nil return nil, nil
// return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address) // return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
} }
symbol := strings.TrimSpace(parseSimpleStringProperty(data)) symbol := strings.TrimSpace(parseSimpleStringProperty(data))
data, _ = b.EthereumTypeEthCall(contractDecimalsSignature, address, "") data, _ = b.EthereumTypeRpcCall(contractDecimalsSignature, address, "")
// if err != nil { // if err != nil {
// glog.Warning(errors.Annotatef(err, "Contract DecimalsSignature %v", address)) // glog.Warning(errors.Annotatef(err, "Contract DecimalsSignature %v", address))
// // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address) // // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
@ -345,7 +345,7 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc
addr := hexutil.Encode(addrDesc)[2:] addr := hexutil.Encode(addrDesc)[2:]
contract := hexutil.Encode(contractDesc) contract := hexutil.Encode(contractDesc)
req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr
data, err := b.EthereumTypeEthCall(req, contract, "") data, err := b.EthereumTypeRpcCall(req, contract, "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -369,7 +369,7 @@ func (b *EthereumRPC) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID
} }
// try ERC721 tokenURI method and ERC1155 uri method // try ERC721 tokenURI method and ERC1155 uri method
for _, method := range []string{erc721TokenURIMethodSignature, erc1155URIMethodSignature} { for _, method := range []string{erc721TokenURIMethodSignature, erc1155URIMethodSignature} {
data, err := b.EthereumTypeEthCall(method+id, address, "") data, err := b.EthereumTypeRpcCall(method+id, address, "")
if err == nil && data != "" { if err == nil && data != "" {
uri := parseSimpleStringProperty(data) uri := parseSimpleStringProperty(data)
// try to sanitize the URI returned from the contract // try to sanitize the URI returned from the contract

View File

@ -61,7 +61,7 @@ func isZeroBigInt(b *big.Int) bool {
func (b *EthereumRPC) everstakeBalanceTypeContractCall(signature, addr, contract string) (string, error) { func (b *EthereumRPC) everstakeBalanceTypeContractCall(signature, addr, contract string) (string, error) {
req := signature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr req := signature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr
return b.EthereumTypeEthCall(req, contract, "") return b.EthereumTypeRpcCall(req, contract, "")
} }
func (b *EthereumRPC) everstakeContractCallSimpleNumeric(signature, addr, contract string) (*big.Int, error) { func (b *EthereumRPC) everstakeContractCallSimpleNumeric(signature, addr, contract string) (*big.Int, error) {

View File

@ -335,7 +335,7 @@ type BlockChain interface {
EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error)
EthereumTypeGetSupportedStakingPools() []string EthereumTypeGetSupportedStakingPools() []string
EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor) ([]StakingPoolData, error) EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor) ([]StakingPoolData, error)
EthereumTypeEthCall(data, to, from string) (string, error) EthereumTypeRpcCall(data, to, from string) (string, error)
GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error) GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error)
} }

View File

@ -448,12 +448,12 @@ export interface WsMempoolFiltersReq {
fromTimestamp: number; fromTimestamp: number;
M?: number; M?: number;
} }
export interface WsEthCallReq { export interface WsRpcCallReq {
from?: string; from?: string;
to: string; to: string;
data: string; data: string;
} }
export interface WsEthCallRes { export interface WsRpcCallRes {
data: string; data: string;
} }
export interface MempoolTxidFilterEntries { export interface MempoolTxidFilterEntries {

View File

@ -60,8 +60,8 @@ func main() {
t.Add(server.WsFiatRatesForTimestampsReq{}) t.Add(server.WsFiatRatesForTimestampsReq{})
t.Add(server.WsFiatRatesTickersListReq{}) t.Add(server.WsFiatRatesTickersListReq{})
t.Add(server.WsMempoolFiltersReq{}) t.Add(server.WsMempoolFiltersReq{})
t.Add(server.WsEthCallReq{}) t.Add(server.WsRpcCallReq{})
t.Add(server.WsEthCallRes{}) t.Add(server.WsRpcCallRes{})
t.Add(bchain.MempoolTxidFilterEntries{}) t.Add(bchain.MempoolTxidFilterEntries{})
err := t.ConvertToFile("blockbook-api.ts") err := t.ConvertToFile("blockbook-api.ts")

View File

@ -8,4 +8,4 @@ Some behavior of Blockbook can be modified by environment variables. The variabl
- `COINGECKO_API_KEY` or `<coin shortcut>_COINGECKO_API_KEY` - API key for making requests to CoinGecko in the paid tier. - `COINGECKO_API_KEY` or `<coin shortcut>_COINGECKO_API_KEY` - API key for making requests to CoinGecko in the paid tier.
- `<coin shortcut>_ALLOWED_ETH_CALL_CONTRACTS` - Contract addresses for which `ethCall` websocket requests can be made, as a comma-separated list. If omitted, `ethCall` is enabled for all addresses. - `<coin shortcut>_ALLOWED_RPC_CALL_TO` - Addresses to which `rpcCall` websocket requests can be made, as a comma-separated list. If omitted, `rpcCall` is enabled for all addresses.

View File

@ -143,10 +143,10 @@ var websocketTestsEthereumType = []websocketTest{
want: `{"id":"0","data":{"name":"Fakecoin","shortcut":"FAKE","network":"FAKE","decimals":18,"version":"unknown","bestHeight":4321001,"bestHash":"0x2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee","block0Hash":"","testnet":true,"backend":{"version":"001001","subversion":"/Fakecoin:0.0.1/"}}}`, want: `{"id":"0","data":{"name":"Fakecoin","shortcut":"FAKE","network":"FAKE","decimals":18,"version":"unknown","bestHeight":4321001,"bestHash":"0x2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee","block0Hash":"","testnet":true,"backend":{"version":"001001","subversion":"/Fakecoin:0.0.1/"}}}`,
}, },
{ {
name: "websocket ethCall", name: "websocket rpcCall",
req: websocketReq{ req: websocketReq{
Method: "ethCall", Method: "rpcCall",
Params: WsEthCallReq{ Params: WsRpcCallReq{
To: "0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9", To: "0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9",
Data: "0x4567", Data: "0x4567",
}, },

View File

@ -1485,10 +1485,10 @@ var websocketTestsBitcoinType = []websocketTest{
want: `{"id":"43","data":{"P":0,"M":1,"zeroedKey":false,"blockFilter":""}}`, want: `{"id":"43","data":{"P":0,"M":1,"zeroedKey":false,"blockFilter":""}}`,
}, },
{ {
name: "websocket ethCall", name: "websocket rpcCall",
req: websocketReq{ req: websocketReq{
Method: "ethCall", Method: "rpcCall",
Params: WsEthCallReq{ Params: WsRpcCallReq{
To: "0x123", To: "0x123",
Data: "0x456", Data: "0x456",
}, },

View File

@ -71,7 +71,7 @@ type WebsocketServer struct {
fiatRatesSubscriptions map[string]map[*websocketChannel]string fiatRatesSubscriptions map[string]map[*websocketChannel]string
fiatRatesTokenSubscriptions map[*websocketChannel][]string fiatRatesTokenSubscriptions map[*websocketChannel][]string
fiatRatesSubscriptionsLock sync.Mutex fiatRatesSubscriptionsLock sync.Mutex
allowedEthCallContracts map[string]struct{} allowedRpcCallTo map[string]struct{}
} }
// NewWebsocketServer creates new websocket interface to blockbook and returns its handle // NewWebsocketServer creates new websocket interface to blockbook and returns its handle
@ -107,13 +107,13 @@ func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.
fiatRatesSubscriptions: make(map[string]map[*websocketChannel]string), fiatRatesSubscriptions: make(map[string]map[*websocketChannel]string),
fiatRatesTokenSubscriptions: make(map[*websocketChannel][]string), fiatRatesTokenSubscriptions: make(map[*websocketChannel][]string),
} }
envEthCall := os.Getenv(strings.ToUpper(is.CoinShortcut) + "_ALLOWED_ETH_CALL_CONTRACTS") envRpcCall := os.Getenv(strings.ToUpper(is.CoinShortcut) + "_ALLOWED_RPC_CALL_TO")
if envEthCall != "" { if envRpcCall != "" {
s.allowedEthCallContracts = make(map[string]struct{}) s.allowedRpcCallTo = make(map[string]struct{})
for _, c := range strings.Split(envEthCall, ",") { for _, c := range strings.Split(envRpcCall, ",") {
s.allowedEthCallContracts[strings.ToLower(c)] = struct{}{} s.allowedRpcCallTo[strings.ToLower(c)] = struct{}{}
} }
glog.Info("Support of ethCall for these contracts: ", envEthCall) glog.Info("Support of rpcCall for these contracts: ", envRpcCall)
} }
return s, nil return s, nil
} }
@ -401,11 +401,11 @@ var requestHandlers = map[string]func(*WebsocketServer, *websocketChannel, *WsRe
} }
return return
}, },
"ethCall": func(s *WebsocketServer, c *websocketChannel, req *WsReq) (rv interface{}, err error) { "rpcCall": func(s *WebsocketServer, c *websocketChannel, req *WsReq) (rv interface{}, err error) {
r := WsEthCallReq{} r := WsRpcCallReq{}
err = json.Unmarshal(req.Params, &r) err = json.Unmarshal(req.Params, &r)
if err == nil { if err == nil {
rv, err = s.ethCall(&r) rv, err = s.rpcCall(&r)
} }
return return
}, },
@ -765,18 +765,18 @@ func (s *WebsocketServer) getBlockFiltersBatch(r *WsBlockFiltersBatchReq) (res i
}, nil }, nil
} }
func (s *WebsocketServer) ethCall(r *WsEthCallReq) (*WsEthCallRes, error) { func (s *WebsocketServer) rpcCall(r *WsRpcCallReq) (*WsRpcCallRes, error) {
if s.allowedEthCallContracts != nil { if s.allowedRpcCallTo != nil {
_, ok := s.allowedEthCallContracts[strings.ToLower(r.To)] _, ok := s.allowedRpcCallTo[strings.ToLower(r.To)]
if !ok { if !ok {
return nil, errors.New("Not supported") return nil, errors.New("Not supported")
} }
} }
data, err := s.chain.EthereumTypeEthCall(r.Data, r.To, r.From) data, err := s.chain.EthereumTypeRpcCall(r.Data, r.To, r.From)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &WsEthCallRes{Data: data}, nil return &WsRpcCallRes{Data: data}, nil
} }
type subscriptionResponse struct { type subscriptionResponse struct {

View File

@ -139,12 +139,12 @@ type WsFiatRatesTickersListReq struct {
Token string `json:"token,omitempty"` Token string `json:"token,omitempty"`
} }
type WsEthCallReq struct { type WsRpcCallReq struct {
From string `json:"from,omitempty"` From string `json:"from,omitempty"`
To string `json:"to"` To string `json:"to"`
Data string `json:"data"` Data string `json:"data"`
} }
type WsEthCallRes struct { type WsRpcCallRes struct {
Data string `json:"data"` Data string `json:"data"`
} }

View File

@ -536,18 +536,18 @@
}); });
} }
function ethCall() { function rpcCall() {
const from = document.getElementById('ethCallFrom').value.trim(); const from = document.getElementById('rpcCallFrom').value.trim();
const to = document.getElementById('ethCallTo').value.trim(); const to = document.getElementById('rpcCallTo').value.trim();
const data = document.getElementById('ethCallData').value.trim(); const data = document.getElementById('rpcCallData').value.trim();
const method = 'ethCall'; const method = 'rpcCall';
const params = { const params = {
from, from,
to, to,
data, data,
}; };
send(method, params, function (result) { send(method, params, function (result) {
document.getElementById('ethCallResult').innerText = JSON.stringify( document.getElementById('rpcCallResult').innerText = JSON.stringify(
result, result,
).replace(/,/g, ', '); ).replace(/,/g, ', ');
}); });
@ -1118,8 +1118,8 @@
<input <input
class="btn btn-secondary" class="btn btn-secondary"
type="button" type="button"
value="ethCall" value="rpcCall"
onclick="ethCall()" onclick="rpcCall()"
/> />
</div> </div>
<div class="col-10"> <div class="col-10">
@ -1127,7 +1127,7 @@
<input <input
type="text" type="text"
class="form-control" class="form-control"
id="ethCallFrom" id="rpcCallFrom"
style="width: 60%; margin-right: 5px" style="width: 60%; margin-right: 5px"
value="" value=""
placeholder="from" placeholder="from"
@ -1135,7 +1135,7 @@
<input <input
type="text" type="text"
class="form-control" class="form-control"
id="ethCallTo" id="rpcCallTo"
style="width: 60%; margin-right: 5px" style="width: 60%; margin-right: 5px"
value="0x624087dd1904ab122a32878ce9e933c7071f53b9" value="0x624087dd1904ab122a32878ce9e933c7071f53b9"
placeholder="to" placeholder="to"
@ -1145,14 +1145,14 @@
class="form-control" class="form-control"
placeholder="data" placeholder="data"
style="width: 100%" style="width: 100%"
id="ethCallData" id="rpcCallData"
value="0x2fec7966000000000000000000000000ce66a9577f4e2589c1d1547b75b7a2b0807ce0ed" value="0x2fec7966000000000000000000000000ce66a9577f4e2589c1d1547b75b7a2b0807ce0ed"
/> />
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col" id="ethCallResult"></div> <div class="col" id="rpcCallResult"></div>
</div> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">

View File

@ -134,8 +134,8 @@ func (c *fakeBlockChainEthereumType) EthereumTypeGetErc20ContractBalance(addrDes
return big.NewInt(1000000000 + int64(addrDesc[0])*1000 + int64(contractDesc[0])), nil return big.NewInt(1000000000 + int64(addrDesc[0])*1000 + int64(contractDesc[0])), nil
} }
// EthereumTypeEthCall calls eth_call with given data and to address // EthereumTypeRpcCall calls eth_call with given data and to address
func (c *fakeBlockChainEthereumType) EthereumTypeEthCall(data, to, from string) (string, error) { func (c *fakeBlockChainEthereumType) EthereumTypeRpcCall(data, to, from string) (string, error) {
return data + "abcd", nil return data + "abcd", nil
} }