@@ -14,6 +14,7 @@ import {
14
14
} from '@ethersproject/abstract-provider' ;
15
15
import { AcalaEvmTX , checkSignatureType , parseTransaction } from '@acala-network/eth-transactions' ;
16
16
import { AccessList , accessListify } from 'ethers/lib/utils' ;
17
+ import { ApiDecoration , SubmittableExtrinsic } from '@polkadot/api/types' ;
17
18
import { ApiPromise } from '@polkadot/api' ;
18
19
import { AsyncAction } from 'rxjs/internal/scheduler/AsyncAction' ;
19
20
import { AsyncScheduler } from 'rxjs/internal/scheduler/AsyncScheduler' ;
@@ -26,7 +27,6 @@ import { Logger } from '@ethersproject/logger';
26
27
import { ModuleEvmModuleAccountInfo } from '@polkadot/types/lookup' ;
27
28
import { Network } from '@ethersproject/networks' ;
28
29
import { Observable , ReplaySubject , Subscription , firstValueFrom , throwError } from 'rxjs' ;
29
- import { SubmittableExtrinsic } from '@polkadot/api/types' ;
30
30
import { filter , first , timeout } from 'rxjs/operators' ;
31
31
import { getAddress } from '@ethersproject/address' ;
32
32
import { hexDataLength , hexValue , hexZeroPad , hexlify , isHexString , joinSignature } from '@ethersproject/bytes' ;
@@ -304,6 +304,7 @@ export abstract class BaseProvider extends AbstractProvider {
304
304
readonly verbose : boolean ;
305
305
readonly maxBlockCacheSize : number ;
306
306
readonly queryCache : LRUCache < string , any > ;
307
+ readonly apiCache : LRUCache < string , ApiDecoration < 'promise' > > ;
307
308
readonly blockCache : BlockCache ;
308
309
readonly finalizedBlockHashes : MaxSizeSet ;
309
310
@@ -341,6 +342,7 @@ export abstract class BaseProvider extends AbstractProvider {
341
342
this . verbose = verbose ;
342
343
this . maxBlockCacheSize = maxBlockCacheSize ;
343
344
this . queryCache = new LRUCache ( { max : storageCacheSize } ) ;
345
+ this . apiCache = new LRUCache ( { max : storageCacheSize } ) ;
344
346
this . blockCache = new BlockCache ( this . maxBlockCacheSize ) ;
345
347
this . finalizedBlockHashes = new MaxSizeSet ( this . maxBlockCacheSize ) ;
346
348
@@ -571,6 +573,16 @@ export abstract class BaseProvider extends AbstractProvider {
571
573
await this . api . disconnect ( ) ;
572
574
} ;
573
575
576
+ getApiAt = async ( blockHash : string ) : Promise < ApiDecoration < 'promise' > > => {
577
+ const cached = this . apiCache . get ( blockHash ) ;
578
+ if ( cached ) return cached ;
579
+
580
+ const apiAt = await this . getApiAt ( blockHash ) ;
581
+ this . apiCache . set ( blockHash , apiAt ) ; // cache key is blockhash, so no need to check for finalization
582
+
583
+ return apiAt ;
584
+ } ;
585
+
574
586
getNetwork = async ( ) : Promise < Network > => {
575
587
await this . isReady ( ) ;
576
588
@@ -678,7 +690,7 @@ export abstract class BaseProvider extends AbstractProvider {
678
690
679
691
const substrateAddress = await this . getSubstrateAddress ( address , blockHash ) ;
680
692
681
- const apiAt = await this . api . at ( blockHash ) ;
693
+ const apiAt = await this . getApiAt ( blockHash ) ;
682
694
const accountInfo = await apiAt . query . system . account ( substrateAddress ) ;
683
695
684
696
return nativeToEthDecimal ( accountInfo . data . free . toBigInt ( ) ) ;
@@ -720,7 +732,7 @@ export abstract class BaseProvider extends AbstractProvider {
720
732
const contractInfo = evmAccountInfo ?. contractInfo . unwrapOr ( null ) ;
721
733
if ( ! contractInfo ) { return '0x' ; }
722
734
723
- const apiAt = await this . api . at ( blockHash ) ;
735
+ const apiAt = await this . getApiAt ( blockHash ) ;
724
736
const code = await apiAt . query . evm . codes ( contractInfo . codeHash ) ;
725
737
726
738
return code . toHex ( ) ;
@@ -818,7 +830,7 @@ export abstract class BaseProvider extends AbstractProvider {
818
830
Promise . resolve ( position ) . then ( hexValue ) ,
819
831
] ) ;
820
832
821
- const apiAt = await this . api . at ( blockHash ) ;
833
+ const apiAt = await this . getApiAt ( blockHash ) ;
822
834
const code = await apiAt . query . evm . accountStorages ( address , hexZeroPad ( resolvedPosition , 32 ) ) ;
823
835
824
836
return code . toHex ( ) ;
@@ -1102,7 +1114,7 @@ export abstract class BaseProvider extends AbstractProvider {
1102
1114
1103
1115
getSubstrateAddress = async ( address : string , blockTag ?: BlockTag ) : Promise < string > => {
1104
1116
const blockHash = await this . _getBlockHash ( blockTag ) ;
1105
- const apiAt = await this . api . at ( blockHash ) ;
1117
+ const apiAt = await this . getApiAt ( blockHash ) ;
1106
1118
const substrateAccount = await apiAt . query . evmAccounts . accounts ( address ) ;
1107
1119
1108
1120
return substrateAccount . isEmpty
@@ -1112,7 +1124,7 @@ export abstract class BaseProvider extends AbstractProvider {
1112
1124
1113
1125
getEvmAddress = async ( substrateAddress : string , blockTag ?: BlockTag ) : Promise < string > => {
1114
1126
const blockHash = await this . _getBlockHash ( blockTag ) ;
1115
- const apiAt = await this . api . at ( blockHash ) ;
1127
+ const apiAt = await this . getApiAt ( blockHash ) ;
1116
1128
const evmAddress = await apiAt . query . evmAccounts . evmAddresses ( substrateAddress ) ;
1117
1129
1118
1130
return getAddress ( evmAddress . isEmpty ? computeDefaultEvmAddress ( substrateAddress ) : evmAddress . toString ( ) ) ;
@@ -1129,7 +1141,7 @@ export abstract class BaseProvider extends AbstractProvider {
1129
1141
this . _getBlockHash ( blockTag ) ,
1130
1142
] ) ;
1131
1143
1132
- const apiAt = await this . api . at ( blockHash ) ;
1144
+ const apiAt = await this . getApiAt ( blockHash ) ;
1133
1145
const accountInfo = await apiAt . query . evm . accounts ( address ) ;
1134
1146
1135
1147
return accountInfo . unwrapOr ( null ) ;
@@ -1474,11 +1486,12 @@ export abstract class BaseProvider extends AbstractProvider {
1474
1486
}
1475
1487
}
1476
1488
1477
- // TODO: test header not found should throw
1478
- const blockHash = ( await this . api . rpc . chain . getBlockHash ( blockNumber . toBigInt ( ) ) ) . toHex ( ) ;
1479
- // if (_blockHash.isEmpty) {
1480
- // return logger.throwError('header not found', Logger.errors.CALL_EXCEPTION, { blockNumber });
1481
- // }
1489
+ const _blockHash = await this . api . rpc . chain . getBlockHash ( blockNumber . toBigInt ( ) ) ;
1490
+ if ( _blockHash . isEmpty ) {
1491
+ //@ts -ignore
1492
+ return logger . throwError ( 'header not found' , PROVIDER_ERRORS . HEADER_NOT_FOUND , { blockNumber } ) ;
1493
+ }
1494
+ const blockHash = _blockHash . toHex ( ) ;
1482
1495
1483
1496
if ( isFinalized ) {
1484
1497
this . queryCache . set ( cacheKey , blockHash ) ;
@@ -1501,6 +1514,9 @@ export abstract class BaseProvider extends AbstractProvider {
1501
1514
1502
1515
const blockNumber = _blockNumber ?? ( await this . _getBlockNumber ( blockHash ) ) ;
1503
1516
const canonicalHash = await this . api . rpc . chain . getBlockHash ( blockNumber ) ;
1517
+ if ( canonicalHash . isEmpty ) {
1518
+ return logger . throwError ( 'header not found' , Logger . errors . CALL_EXCEPTION , { blockNumber } ) ;
1519
+ }
1504
1520
1505
1521
return canonicalHash . toString ( ) === blockHash ;
1506
1522
} ;
0 commit comments