@@ -8,6 +8,7 @@ import { GanacheLevelUp } from "../database";
8
8
9
9
export default class BlockLogManager extends Manager < BlockLogs > {
10
10
#blockchain: Blockchain ;
11
+
11
12
constructor ( base : GanacheLevelUp , blockchain : Blockchain ) {
12
13
super ( base , BlockLogs ) ;
13
14
this . #blockchain = blockchain ;
@@ -19,11 +20,13 @@ export default class BlockLogManager extends Manager<BlockLogs> {
19
20
log . blockNumber = Quantity . from ( key ) ;
20
21
} else if ( this . #blockchain. fallback ) {
21
22
const block = Quantity . from ( key ) ;
22
- const res = await this . #blockchain. fallback . request < any [ ] | null > (
23
- "eth_getLogs" ,
24
- [ { fromBlock : block , toBlock : block } ]
25
- ) ;
26
- return BlockLogs . fromJSON ( res ) ;
23
+ if ( this . #blockchain. fallback . isValidForkBlockNumber ( block ) ) {
24
+ const res = await this . #blockchain. fallback . request < any [ ] | null > (
25
+ "eth_getLogs" ,
26
+ [ { fromBlock : block , toBlock : block } ]
27
+ ) ;
28
+ return BlockLogs . fromJSON ( res ) ;
29
+ }
27
30
}
28
31
return log ;
29
32
}
@@ -35,42 +38,90 @@ export default class BlockLogManager extends Manager<BlockLogs> {
35
38
const blockNumber = await blockchain . blocks . getNumberFromHash (
36
39
filter . blockHash
37
40
) ;
38
- if ( ! blockNumber ) return [ ] ;
39
-
40
- const logs = await this . get ( blockNumber ) ;
41
+ if ( ! blockNumber ) {
42
+ return [ ] ;
43
+ }
44
+ const logs = await this . get ( blockNumber . toBuffer ( ) ) ;
41
45
return logs ? [ ...logs . filter ( addresses , topics ) ] : [ ] ;
42
- } else {
43
- const { addresses, topics, fromBlock, toBlockNumber } = parseFilter (
44
- filter ,
45
- blockchain
46
+ }
47
+ const { fromBlock, toBlock } = parseFilter ( filter , blockchain ) ;
48
+ if ( fromBlock . toBigInt ( ) > toBlock . toBigInt ( ) ) {
49
+ throw new Error (
50
+ "One of the blocks specified in filter (fromBlock, toBlock or blockHash) cannot be found."
46
51
) ;
52
+ }
47
53
48
- const pendingLogsPromises : Promise < BlockLogs > [ ] = [
49
- this . get ( fromBlock . toBuffer ( ) )
50
- ] ;
51
-
52
- const fromBlockNumber = fromBlock . toNumber ( ) ;
53
- // if we have a range of blocks to search, do that here:
54
- if ( fromBlockNumber !== toBlockNumber ) {
55
- // fetch all the blockLogs in-between `fromBlock` and `toBlock` (excluding
56
- // from, because we already started fetching that one)
57
- for ( let i = fromBlockNumber + 1 , l = toBlockNumber + 1 ; i < l ; i ++ ) {
58
- pendingLogsPromises . push ( this . get ( Quantity . toBuffer ( i ) ) ) ;
59
- }
60
- }
54
+ const fork = this . #blockchain. fallback ;
55
+ if ( ! fork ) {
56
+ return await this . getLocal (
57
+ fromBlock . toNumber ( ) ,
58
+ toBlock . toNumber ( ) ,
59
+ filter
60
+ ) ;
61
+ }
62
+ const from = Quantity . min ( fromBlock , toBlock ) ;
63
+ const ret : Ethereum . Logs = [ ] ;
64
+ if ( fork . isValidForkBlockNumber ( from ) ) {
65
+ ret . push (
66
+ ...( await this . getFromFork (
67
+ from ,
68
+ Quantity . min ( toBlock , fork . blockNumber ) ,
69
+ filter
70
+ ) )
71
+ ) ;
72
+ }
73
+ if ( ! fork . isValidForkBlockNumber ( toBlock ) ) {
74
+ ret . push (
75
+ ...( await this . getLocal (
76
+ Math . max ( from . toNumber ( ) , fork . blockNumber . toNumber ( ) + 1 ) ,
77
+ toBlock . toNumber ( ) ,
78
+ filter
79
+ ) )
80
+ ) ;
81
+ }
82
+ return ret ;
83
+ }
61
84
62
- // now filter and compute all the blocks' blockLogs (in block order)
63
- return Promise . all ( pendingLogsPromises ) . then ( blockLogsRange => {
64
- const filteredBlockLogs : Ethereum . Logs = [ ] ;
65
- blockLogsRange . forEach ( blockLogs => {
66
- // TODO(perf): this loops over all addresses for every block.
67
- // Maybe make it loop only once?
68
- // Issue: https://github.com/trufflesuite/ganache/issues/3482
69
- if ( blockLogs )
70
- filteredBlockLogs . push ( ...blockLogs . filter ( addresses , topics ) ) ;
71
- } ) ;
72
- return filteredBlockLogs ;
85
+ getLocal (
86
+ from : number ,
87
+ to : number ,
88
+ filter : FilterArgs
89
+ ) : Promise < Ethereum . Logs > {
90
+ const { addresses, topics } = parseFilterDetails ( filter ) ;
91
+ const pendingLogsPromises : Promise < BlockLogs > [ ] = [ ] ;
92
+ for ( let i = from ; i <= to ; i ++ ) {
93
+ pendingLogsPromises . push ( this . get ( Quantity . toBuffer ( i ) ) ) ;
94
+ }
95
+ return Promise . all ( pendingLogsPromises ) . then ( blockLogsRange => {
96
+ const filteredBlockLogs : Ethereum . Logs = [ ] ;
97
+ blockLogsRange . forEach ( blockLogs => {
98
+ // TODO(perf): this loops over all addresses for every block.
99
+ // Maybe make it loop only once?
100
+ // Issue: https://github.com/trufflesuite/ganache/issues/3482
101
+ if ( blockLogs )
102
+ filteredBlockLogs . push ( ...blockLogs . filter ( addresses , topics ) ) ;
73
103
} ) ;
104
+ return filteredBlockLogs ;
105
+ } ) ;
106
+ }
107
+
108
+ async getFromFork (
109
+ from : Quantity ,
110
+ to : Quantity ,
111
+ filter : FilterArgs
112
+ ) : Promise < Ethereum . Logs > {
113
+ const { addresses, topics } = parseFilterDetails ( filter ) ;
114
+ const f = this . #blockchain. fallback ;
115
+ if ( ! f || ! f . isValidForkBlockNumber ( from ) ) {
116
+ return [ ] ;
74
117
}
118
+ return await f . request < Ethereum . Logs | null > ( "eth_getLogs" , [
119
+ {
120
+ fromBlock : from ,
121
+ toBlock : f . selectValidForkBlockNumber ( to ) ,
122
+ address : addresses ,
123
+ topics
124
+ }
125
+ ] ) ;
75
126
}
76
127
}
0 commit comments