feat: apply gateway lookback limit to eth API lookback
This change: 1. Introduces new "limited" API endpoints for EthGetTransactionByHash and EthGetTransactionReceipt that accept lookback-limits. 2. Implements the gateway version of these API endpoints by calling the limited variants with the default message search lookback limit. fixes #10412
This commit is contained in:
parent
4c80e179ae
commit
fee480193e
@ -797,10 +797,12 @@ type FullNode interface {
|
||||
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
||||
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
|
||||
EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) //perm:read
|
||||
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read
|
||||
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read
|
||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read
|
||||
EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error) //perm:read
|
||||
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read
|
||||
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read
|
||||
|
||||
|
@ -1296,6 +1296,21 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionByHash(arg0, arg1 interface
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByHash), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGetTransactionByHashLimited mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionByHashLimited(arg0 context.Context, arg1 *ethtypes.EthHash, arg2 abi.ChainEpoch) (*ethtypes.EthTx, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionByHashLimited", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*ethtypes.EthTx)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetTransactionByHashLimited indicates an expected call of EthGetTransactionByHashLimited.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetTransactionByHashLimited(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByHashLimited", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByHashLimited), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGetTransactionCount mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionCount(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -1341,6 +1356,21 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionReceipt(arg0, arg1 interfac
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionReceipt", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionReceipt), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGetTransactionReceiptLimited mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionReceiptLimited(arg0 context.Context, arg1 ethtypes.EthHash, arg2 abi.ChainEpoch) (*api.EthTxReceipt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionReceiptLimited", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*api.EthTxReceipt)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetTransactionReceiptLimited indicates an expected call of EthGetTransactionReceiptLimited.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetTransactionReceiptLimited(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionReceiptLimited", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionReceiptLimited), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthMaxPriorityFeePerGas mocks base method.
|
||||
func (m *MockFullNode) EthMaxPriorityFeePerGas(arg0 context.Context) (ethtypes.EthBigInt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -290,12 +290,16 @@ type FullNodeMethods struct {
|
||||
|
||||
EthGetTransactionByHash func(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionByHashLimited func(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionReceiptLimited func(p0 context.Context, p1 ethtypes.EthHash, p2 abi.ChainEpoch) (*EthTxReceipt, error) `perm:"read"`
|
||||
|
||||
EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"`
|
||||
|
||||
EthNewBlockFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `perm:"write"`
|
||||
@ -2274,6 +2278,17 @@ func (s *FullNodeStub) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionByHashLimited(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) {
|
||||
if s.Internal.EthGetTransactionByHashLimited == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionByHashLimited(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionByHashLimited(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthGetTransactionCount == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
@ -2307,6 +2322,17 @@ func (s *FullNodeStub) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionReceiptLimited(p0 context.Context, p1 ethtypes.EthHash, p2 abi.ChainEpoch) (*EthTxReceipt, error) {
|
||||
if s.Internal.EthGetTransactionReceiptLimited == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionReceiptLimited(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionReceiptLimited(p0 context.Context, p1 ethtypes.EthHash, p2 abi.ChainEpoch) (*EthTxReceipt, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) {
|
||||
if s.Internal.EthMaxPriorityFeePerGas == nil {
|
||||
return *new(ethtypes.EthBigInt), ErrNotSupported
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -91,9 +91,11 @@
|
||||
* [EthGetTransactionByBlockHashAndIndex](#EthGetTransactionByBlockHashAndIndex)
|
||||
* [EthGetTransactionByBlockNumberAndIndex](#EthGetTransactionByBlockNumberAndIndex)
|
||||
* [EthGetTransactionByHash](#EthGetTransactionByHash)
|
||||
* [EthGetTransactionByHashLimited](#EthGetTransactionByHashLimited)
|
||||
* [EthGetTransactionCount](#EthGetTransactionCount)
|
||||
* [EthGetTransactionHashByCid](#EthGetTransactionHashByCid)
|
||||
* [EthGetTransactionReceipt](#EthGetTransactionReceipt)
|
||||
* [EthGetTransactionReceiptLimited](#EthGetTransactionReceiptLimited)
|
||||
* [EthMaxPriorityFeePerGas](#EthMaxPriorityFeePerGas)
|
||||
* [EthNewBlockFilter](#EthNewBlockFilter)
|
||||
* [EthNewFilter](#EthNewFilter)
|
||||
@ -2810,6 +2812,45 @@ Response:
|
||||
}
|
||||
```
|
||||
|
||||
### EthGetTransactionByHashLimited
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
10101
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"chainId": "0x5",
|
||||
"nonce": "0x5",
|
||||
"hash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
"blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
"blockNumber": "0x5",
|
||||
"transactionIndex": "0x5",
|
||||
"from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"value": "0x0",
|
||||
"type": "0x5",
|
||||
"input": "0x07",
|
||||
"gas": "0x5",
|
||||
"maxFeePerGas": "0x0",
|
||||
"maxPriorityFeePerGas": "0x0",
|
||||
"accessList": [
|
||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||
],
|
||||
"v": "0x0",
|
||||
"r": "0x0",
|
||||
"s": "0x0"
|
||||
}
|
||||
```
|
||||
|
||||
### EthGetTransactionCount
|
||||
|
||||
|
||||
@ -2888,6 +2929,54 @@ Response:
|
||||
}
|
||||
```
|
||||
|
||||
### EthGetTransactionReceiptLimited
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
10101
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
"transactionIndex": "0x5",
|
||||
"blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
"blockNumber": "0x5",
|
||||
"from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"root": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
"status": "0x5",
|
||||
"contractAddress": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"cumulativeGasUsed": "0x5",
|
||||
"gasUsed": "0x5",
|
||||
"effectiveGasPrice": "0x0",
|
||||
"logsBloom": "0x07",
|
||||
"logs": [
|
||||
{
|
||||
"address": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"data": "0x07",
|
||||
"topics": [
|
||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||
],
|
||||
"removed": true,
|
||||
"logIndex": "0x5",
|
||||
"transactionIndex": "0x5",
|
||||
"transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
"blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||
"blockNumber": "0x5"
|
||||
}
|
||||
],
|
||||
"type": "0x5"
|
||||
}
|
||||
```
|
||||
|
||||
### EthMaxPriorityFeePerGas
|
||||
|
||||
|
||||
|
@ -101,11 +101,11 @@ type TargetAPI interface {
|
||||
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error)
|
||||
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error)
|
||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error)
|
||||
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error)
|
||||
EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error)
|
||||
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error)
|
||||
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error)
|
||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error)
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error)
|
||||
EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error)
|
||||
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error)
|
||||
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error)
|
||||
EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error)
|
||||
|
@ -149,7 +149,7 @@ func (gw *Node) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.Et
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gw.target.EthGetTransactionByHash(ctx, txHash)
|
||||
return gw.target.EthGetTransactionByHashLimited(ctx, txHash, gw.stateWaitLookbackLimit)
|
||||
}
|
||||
|
||||
func (gw *Node) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) {
|
||||
@ -185,7 +185,7 @@ func (gw *Node) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.Et
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gw.target.EthGetTransactionReceipt(ctx, txHash)
|
||||
return gw.target.EthGetTransactionReceiptLimited(ctx, txHash, gw.stateWaitLookbackLimit)
|
||||
}
|
||||
|
||||
func (gw *Node) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
@ -57,6 +58,10 @@ func (e *EthModuleDummy) EthGetTransactionByHash(ctx context.Context, txHash *et
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
@ -65,6 +70,10 @@ func (e *EthModuleDummy) EthGetTransactionReceipt(ctx context.Context, txHash et
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
return ethtypes.EthTx{}, ErrModuleDisabled
|
||||
}
|
||||
|
@ -54,10 +54,12 @@ type EthModuleAPI interface {
|
||||
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error)
|
||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error)
|
||||
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error)
|
||||
EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error)
|
||||
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error)
|
||||
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error)
|
||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error)
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error)
|
||||
EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error)
|
||||
EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error)
|
||||
EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error)
|
||||
EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error)
|
||||
@ -89,8 +91,6 @@ type EthEventAPI interface {
|
||||
var (
|
||||
_ EthModuleAPI = *new(api.FullNode)
|
||||
_ EthEventAPI = *new(api.FullNode)
|
||||
|
||||
_ EthModuleAPI = *new(api.Gateway)
|
||||
)
|
||||
|
||||
// EthModule provides the default implementation of the standard Ethereum JSON-RPC API.
|
||||
@ -278,6 +278,11 @@ func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkParam string, fu
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) {
|
||||
return a.EthGetTransactionByHashLimited(ctx, txHash, api.LookbackNoLimit)
|
||||
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) {
|
||||
// Ethereum's behavior is to return null when the txHash is invalid, so we use nil to check if txHash is valid
|
||||
if txHash == nil {
|
||||
return nil, nil
|
||||
@ -409,6 +414,10 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
||||
return a.EthGetTransactionReceiptLimited(ctx, txHash, api.LookbackNoLimit)
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error) {
|
||||
c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(txHash)
|
||||
if err != nil {
|
||||
log.Debug("could not find transaction hash %s in lookup table", txHash.String())
|
||||
|
Loading…
Reference in New Issue
Block a user