Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
cb859238
Commit
cb859238
authored
Feb 13, 2016
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2205 from obscuren/pending-filters
eth/filters:
✨
pending logs
✨
parents
770b29fd
987c1a59
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
143 additions
and
52 deletions
+143
-52
blockchain.go
core/blockchain.go
+1
-1
blockchain_test.go
core/blockchain_test.go
+2
-2
events.go
core/events.go
+6
-1
api.go
eth/filters/api.go
+22
-7
filter.go
eth/filters/filter.go
+3
-0
filter_system.go
eth/filters/filter_system.go
+74
-27
filter_system_test.go
eth/filters/filter_system_test.go
+20
-6
worker.go
miner/worker.go
+15
-8
No files found.
core/blockchain.go
View file @
cb859238
...
...
@@ -1358,7 +1358,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
go
self
.
eventMux
.
Post
(
RemovedTransactionEvent
{
diff
})
}
if
len
(
deletedLogs
)
>
0
{
go
self
.
eventMux
.
Post
(
RemovedLogEvent
{
deletedLogs
})
go
self
.
eventMux
.
Post
(
RemovedLog
s
Event
{
deletedLogs
})
}
return
nil
...
...
core/blockchain_test.go
View file @
cb859238
...
...
@@ -982,7 +982,7 @@ func TestLogReorgs(t *testing.T) {
evmux
:=
&
event
.
TypeMux
{}
blockchain
,
_
:=
NewBlockChain
(
db
,
FakePow
{},
evmux
)
subs
:=
evmux
.
Subscribe
(
RemovedLogEvent
{})
subs
:=
evmux
.
Subscribe
(
RemovedLog
s
Event
{})
chain
,
_
:=
GenerateChain
(
genesis
,
db
,
2
,
func
(
i
int
,
gen
*
BlockGen
)
{
if
i
==
1
{
tx
,
err
:=
types
.
NewContractCreation
(
gen
.
TxNonce
(
addr1
),
new
(
big
.
Int
),
big
.
NewInt
(
1000000
),
new
(
big
.
Int
),
code
)
.
SignECDSA
(
key1
)
...
...
@@ -1002,7 +1002,7 @@ func TestLogReorgs(t *testing.T) {
}
ev
:=
<-
subs
.
Chan
()
if
len
(
ev
.
Data
.
(
RemovedLogEvent
)
.
Logs
)
==
0
{
if
len
(
ev
.
Data
.
(
RemovedLog
s
Event
)
.
Logs
)
==
0
{
t
.
Error
(
"expected logs"
)
}
}
core/events.go
View file @
cb859238
...
...
@@ -30,6 +30,11 @@ type TxPreEvent struct{ Tx *types.Transaction }
// TxPostEvent is posted when a transaction has been processed.
type
TxPostEvent
struct
{
Tx
*
types
.
Transaction
}
// PendingLogsEvent is posted pre mining and notifies of pending logs.
type
PendingLogsEvent
struct
{
Logs
vm
.
Logs
}
// NewBlockEvent is posted when a block has been imported.
type
NewBlockEvent
struct
{
Block
*
types
.
Block
}
...
...
@@ -40,7 +45,7 @@ type NewMinedBlockEvent struct{ Block *types.Block }
type
RemovedTransactionEvent
struct
{
Txs
types
.
Transactions
}
// RemovedLogEvent is posted when a reorg happens
type
RemovedLogEvent
struct
{
Logs
vm
.
Logs
}
type
RemovedLog
s
Event
struct
{
Logs
vm
.
Logs
}
// ChainSplit is posted when a new head is detected
type
ChainSplitEvent
struct
{
...
...
eth/filters/api.go
View file @
cb859238
...
...
@@ -142,7 +142,11 @@ func (s *PublicFilterAPI) NewBlockFilter() (string, error) {
s
.
blockMu
.
Lock
()
filter
:=
New
(
s
.
chainDb
)
id
:=
s
.
filterManager
.
Add
(
filter
)
id
,
err
:=
s
.
filterManager
.
Add
(
filter
,
ChainFilter
)
if
err
!=
nil
{
return
""
,
err
}
s
.
blockQueue
[
id
]
=
&
hashQueue
{
timeout
:
time
.
Now
()}
filter
.
BlockCallback
=
func
(
block
*
types
.
Block
,
logs
vm
.
Logs
)
{
...
...
@@ -174,7 +178,11 @@ func (s *PublicFilterAPI) NewPendingTransactionFilter() (string, error) {
defer
s
.
transactionMu
.
Unlock
()
filter
:=
New
(
s
.
chainDb
)
id
:=
s
.
filterManager
.
Add
(
filter
)
id
,
err
:=
s
.
filterManager
.
Add
(
filter
,
PendingTxFilter
)
if
err
!=
nil
{
return
""
,
err
}
s
.
transactionQueue
[
id
]
=
&
hashQueue
{
timeout
:
time
.
Now
()}
filter
.
TransactionCallback
=
func
(
tx
*
types
.
Transaction
)
{
...
...
@@ -194,12 +202,16 @@ func (s *PublicFilterAPI) NewPendingTransactionFilter() (string, error) {
}
// newLogFilter creates a new log filter.
func
(
s
*
PublicFilterAPI
)
newLogFilter
(
earliest
,
latest
int64
,
addresses
[]
common
.
Address
,
topics
[][]
common
.
Hash
)
int
{
func
(
s
*
PublicFilterAPI
)
newLogFilter
(
earliest
,
latest
int64
,
addresses
[]
common
.
Address
,
topics
[][]
common
.
Hash
)
(
int
,
error
)
{
s
.
logMu
.
Lock
()
defer
s
.
logMu
.
Unlock
()
filter
:=
New
(
s
.
chainDb
)
id
:=
s
.
filterManager
.
Add
(
filter
)
id
,
err
:=
s
.
filterManager
.
Add
(
filter
,
LogFilter
)
if
err
!=
nil
{
return
0
,
err
}
s
.
logQueue
[
id
]
=
&
logQueue
{
timeout
:
time
.
Now
()}
filter
.
SetBeginBlock
(
earliest
)
...
...
@@ -215,7 +227,7 @@ func (s *PublicFilterAPI) newLogFilter(earliest, latest int64, addresses []commo
}
}
return
id
return
id
,
nil
}
// NewFilterArgs represents a request to create a new filter.
...
...
@@ -352,9 +364,12 @@ func (s *PublicFilterAPI) NewFilter(args NewFilterArgs) (string, error) {
var
id
int
if
len
(
args
.
Addresses
)
>
0
{
id
=
s
.
newLogFilter
(
args
.
FromBlock
.
Int64
(),
args
.
ToBlock
.
Int64
(),
args
.
Addresses
,
args
.
Topics
)
id
,
err
=
s
.
newLogFilter
(
args
.
FromBlock
.
Int64
(),
args
.
ToBlock
.
Int64
(),
args
.
Addresses
,
args
.
Topics
)
}
else
{
id
=
s
.
newLogFilter
(
args
.
FromBlock
.
Int64
(),
args
.
ToBlock
.
Int64
(),
nil
,
args
.
Topics
)
id
,
err
=
s
.
newLogFilter
(
args
.
FromBlock
.
Int64
(),
args
.
ToBlock
.
Int64
(),
nil
,
args
.
Topics
)
}
if
err
!=
nil
{
return
""
,
err
}
s
.
filterMapMu
.
Lock
()
...
...
eth/filters/filter.go
View file @
cb859238
...
...
@@ -18,6 +18,7 @@ package filters
import
(
"math"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
...
...
@@ -32,6 +33,8 @@ type AccountChange struct {
// Filtering interface
type
Filter
struct
{
created
time
.
Time
db
ethdb
.
Database
begin
,
end
int64
addresses
[]
common
.
Address
...
...
eth/filters/filter_system.go
View file @
cb859238
...
...
@@ -19,6 +19,7 @@
package
filters
import
(
"fmt"
"sync"
"time"
...
...
@@ -27,26 +28,47 @@ import (
"github.com/ethereum/go-ethereum/event"
)
// FilterType determines the type of filter and is used to put the filter in to
// the correct bucket when added.
type
FilterType
byte
const
(
ChainFilter
FilterType
=
iota
// new block events filter
PendingTxFilter
// pending transaction filter
LogFilter
// new or removed log filter
PendingLogFilter
// pending log filter
)
// FilterSystem manages filters that filter specific events such as
// block, transaction and log events. The Filtering system can be used to listen
// for specific LOG events fired by the EVM (Ethereum Virtual Machine).
type
FilterSystem
struct
{
filterMu
sync
.
RWMutex
filterId
int
filters
map
[
int
]
*
Filter
created
map
[
int
]
time
.
Time
sub
event
.
Subscription
chainFilters
map
[
int
]
*
Filter
pendingTxFilters
map
[
int
]
*
Filter
logFilters
map
[
int
]
*
Filter
pendingLogFilters
map
[
int
]
*
Filter
// generic is an ugly hack for Get
generic
map
[
int
]
*
Filter
sub
event
.
Subscription
}
// NewFilterSystem returns a newly allocated filter manager
func
NewFilterSystem
(
mux
*
event
.
TypeMux
)
*
FilterSystem
{
fs
:=
&
FilterSystem
{
filters
:
make
(
map
[
int
]
*
Filter
),
created
:
make
(
map
[
int
]
time
.
Time
),
chainFilters
:
make
(
map
[
int
]
*
Filter
),
pendingTxFilters
:
make
(
map
[
int
]
*
Filter
),
logFilters
:
make
(
map
[
int
]
*
Filter
),
pendingLogFilters
:
make
(
map
[
int
]
*
Filter
),
generic
:
make
(
map
[
int
]
*
Filter
),
}
fs
.
sub
=
mux
.
Subscribe
(
//core.PendingBlock
Event{},
core
.
RemovedLogEvent
{},
core
.
PendingLogs
Event
{},
core
.
RemovedLog
s
Event
{},
core
.
ChainEvent
{},
core
.
TxPreEvent
{},
vm
.
Logs
(
nil
),
...
...
@@ -61,15 +83,30 @@ func (fs *FilterSystem) Stop() {
}
// Add adds a filter to the filter manager
func
(
fs
*
FilterSystem
)
Add
(
filter
*
Filter
)
(
id
int
)
{
func
(
fs
*
FilterSystem
)
Add
(
filter
*
Filter
,
filterType
FilterType
)
(
int
,
error
)
{
fs
.
filterMu
.
Lock
()
defer
fs
.
filterMu
.
Unlock
()
id
=
fs
.
filterId
fs
.
filters
[
id
]
=
filter
fs
.
created
[
id
]
=
time
.
Now
()
id
:=
fs
.
filterId
filter
.
created
=
time
.
Now
()
switch
filterType
{
case
ChainFilter
:
fs
.
chainFilters
[
id
]
=
filter
case
PendingTxFilter
:
fs
.
pendingTxFilters
[
id
]
=
filter
case
LogFilter
:
fs
.
logFilters
[
id
]
=
filter
case
PendingLogFilter
:
fs
.
pendingLogFilters
[
id
]
=
filter
default
:
return
0
,
fmt
.
Errorf
(
"unknown filter type %v"
,
filterType
)
}
fs
.
generic
[
id
]
=
filter
fs
.
filterId
++
return
id
return
id
,
nil
}
// Remove removes a filter by filter id
...
...
@@ -77,16 +114,18 @@ func (fs *FilterSystem) Remove(id int) {
fs
.
filterMu
.
Lock
()
defer
fs
.
filterMu
.
Unlock
()
delete
(
fs
.
filters
,
id
)
delete
(
fs
.
created
,
id
)
delete
(
fs
.
chainFilters
,
id
)
delete
(
fs
.
pendingTxFilters
,
id
)
delete
(
fs
.
logFilters
,
id
)
delete
(
fs
.
pendingLogFilters
,
id
)
delete
(
fs
.
generic
,
id
)
}
// Get retrieves a filter installed using Add The filter may not be modified.
func
(
fs
*
FilterSystem
)
Get
(
id
int
)
*
Filter
{
fs
.
filterMu
.
RLock
()
defer
fs
.
filterMu
.
RUnlock
()
return
fs
.
filters
[
id
]
return
fs
.
generic
[
id
]
}
// filterLoop waits for specific events from ethereum and fires their handlers
...
...
@@ -96,17 +135,16 @@ func (fs *FilterSystem) filterLoop() {
switch
ev
:=
event
.
Data
.
(
type
)
{
case
core
.
ChainEvent
:
fs
.
filterMu
.
RLock
()
for
id
,
filter
:=
range
fs
.
f
ilters
{
if
filter
.
BlockCallback
!=
nil
&&
!
f
s
.
created
[
id
]
.
After
(
event
.
Time
)
{
for
_
,
filter
:=
range
fs
.
chainF
ilters
{
if
filter
.
BlockCallback
!=
nil
&&
!
f
ilter
.
created
.
After
(
event
.
Time
)
{
filter
.
BlockCallback
(
ev
.
Block
,
ev
.
Logs
)
}
}
fs
.
filterMu
.
RUnlock
()
case
core
.
TxPreEvent
:
fs
.
filterMu
.
RLock
()
for
id
,
filter
:=
range
fs
.
f
ilters
{
if
filter
.
TransactionCallback
!=
nil
&&
!
f
s
.
created
[
id
]
.
After
(
event
.
Time
)
{
for
_
,
filter
:=
range
fs
.
pendingTxF
ilters
{
if
filter
.
TransactionCallback
!=
nil
&&
!
f
ilter
.
created
.
After
(
event
.
Time
)
{
filter
.
TransactionCallback
(
ev
.
Tx
)
}
}
...
...
@@ -114,25 +152,34 @@ func (fs *FilterSystem) filterLoop() {
case
vm
.
Logs
:
fs
.
filterMu
.
RLock
()
for
id
,
filter
:=
range
fs
.
f
ilters
{
if
filter
.
LogCallback
!=
nil
&&
!
f
s
.
created
[
id
]
.
After
(
event
.
Time
)
{
for
_
,
filter
:=
range
fs
.
logF
ilters
{
if
filter
.
LogCallback
!=
nil
&&
!
f
ilter
.
created
.
After
(
event
.
Time
)
{
for
_
,
log
:=
range
filter
.
FilterLogs
(
ev
)
{
filter
.
LogCallback
(
log
,
false
)
}
}
}
fs
.
filterMu
.
RUnlock
()
case
core
.
RemovedLogEvent
:
case
core
.
RemovedLogsEvent
:
fs
.
filterMu
.
RLock
()
for
id
,
filter
:=
range
fs
.
f
ilters
{
if
filter
.
LogCallback
!=
nil
&&
!
f
s
.
created
[
id
]
.
After
(
event
.
Time
)
{
for
_
,
filter
:=
range
fs
.
logF
ilters
{
if
filter
.
LogCallback
!=
nil
&&
!
f
ilter
.
created
.
After
(
event
.
Time
)
{
for
_
,
removedLog
:=
range
ev
.
Logs
{
filter
.
LogCallback
(
removedLog
,
true
)
}
}
}
fs
.
filterMu
.
RUnlock
()
case
core
.
PendingLogsEvent
:
fs
.
filterMu
.
RLock
()
for
_
,
filter
:=
range
fs
.
pendingLogFilters
{
if
filter
.
LogCallback
!=
nil
&&
!
filter
.
created
.
After
(
event
.
Time
)
{
for
_
,
pendingLog
:=
range
ev
.
Logs
{
filter
.
LogCallback
(
pendingLog
,
false
)
}
}
}
fs
.
filterMu
.
RUnlock
()
}
}
}
eth/filters/filter_system_test.go
View file @
cb859238
...
...
@@ -18,6 +18,7 @@ func TestCallbacks(t *testing.T) {
txDone
=
make
(
chan
struct
{})
logDone
=
make
(
chan
struct
{})
removedLogDone
=
make
(
chan
struct
{})
pendingLogDone
=
make
(
chan
struct
{})
)
blockFilter
:=
&
Filter
{
...
...
@@ -37,7 +38,6 @@ func TestCallbacks(t *testing.T) {
}
},
}
removedLogFilter
:=
&
Filter
{
LogCallback
:
func
(
l
*
vm
.
Log
,
oob
bool
)
{
if
oob
{
...
...
@@ -45,16 +45,23 @@ func TestCallbacks(t *testing.T) {
}
},
}
pendingLogFilter
:=
&
Filter
{
LogCallback
:
func
(
*
vm
.
Log
,
bool
)
{
close
(
pendingLogDone
)
},
}
fs
.
Add
(
blockFilter
)
fs
.
Add
(
txFilter
)
fs
.
Add
(
logFilter
)
fs
.
Add
(
removedLogFilter
)
fs
.
Add
(
blockFilter
,
ChainFilter
)
fs
.
Add
(
txFilter
,
PendingTxFilter
)
fs
.
Add
(
logFilter
,
LogFilter
)
fs
.
Add
(
removedLogFilter
,
LogFilter
)
fs
.
Add
(
pendingLogFilter
,
PendingLogFilter
)
mux
.
Post
(
core
.
ChainEvent
{})
mux
.
Post
(
core
.
TxPreEvent
{})
mux
.
Post
(
core
.
RemovedLogEvent
{
vm
.
Logs
{
&
vm
.
Log
{}}})
mux
.
Post
(
vm
.
Logs
{
&
vm
.
Log
{}})
mux
.
Post
(
core
.
RemovedLogsEvent
{
vm
.
Logs
{
&
vm
.
Log
{}}})
mux
.
Post
(
core
.
PendingLogsEvent
{
vm
.
Logs
{
&
vm
.
Log
{}}})
const
dura
=
5
*
time
.
Second
failTimer
:=
time
.
NewTimer
(
dura
)
...
...
@@ -84,4 +91,11 @@ func TestCallbacks(t *testing.T) {
case
<-
failTimer
.
C
:
t
.
Error
(
"removed log filter failed to trigger (timeout)"
)
}
failTimer
.
Reset
(
dura
)
select
{
case
<-
pendingLogDone
:
case
<-
failTimer
.
C
:
t
.
Error
(
"pending log filter failed to trigger (timout)"
)
}
}
miner/worker.go
View file @
cb859238
...
...
@@ -243,7 +243,7 @@ func (self *worker) update() {
// Apply transaction to the pending state if we're not mining
if
atomic
.
LoadInt32
(
&
self
.
mining
)
==
0
{
self
.
currentMu
.
Lock
()
self
.
current
.
commitTransactions
(
types
.
Transactions
{
ev
.
Tx
},
self
.
gasPrice
,
self
.
chain
)
self
.
current
.
commitTransactions
(
self
.
mux
,
types
.
Transactions
{
ev
.
Tx
},
self
.
gasPrice
,
self
.
chain
)
self
.
currentMu
.
Unlock
()
}
}
...
...
@@ -529,7 +529,7 @@ func (self *worker) commitNewWork() {
transactions := append(singleTxOwner, multiTxOwner...)
*/
work
.
commitTransactions
(
transactions
,
self
.
gasPrice
,
self
.
chain
)
work
.
commitTransactions
(
self
.
mux
,
transactions
,
self
.
gasPrice
,
self
.
chain
)
self
.
eth
.
TxPool
()
.
RemoveTransactions
(
work
.
lowGasTxs
)
// compute uncles for the new block.
...
...
@@ -588,8 +588,10 @@ func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
return
nil
}
func
(
env
*
Work
)
commitTransactions
(
transactions
types
.
Transactions
,
gasPrice
*
big
.
Int
,
bc
*
core
.
BlockChain
)
{
func
(
env
*
Work
)
commitTransactions
(
mux
*
event
.
TypeMux
,
transactions
types
.
Transactions
,
gasPrice
*
big
.
Int
,
bc
*
core
.
BlockChain
)
{
gp
:=
new
(
core
.
GasPool
)
.
AddGas
(
env
.
header
.
GasLimit
)
var
coalescedLogs
vm
.
Logs
for
_
,
tx
:=
range
transactions
{
// We can skip err. It has already been validated in the tx pool
from
,
_
:=
tx
.
From
()
...
...
@@ -627,7 +629,7 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b
env
.
state
.
StartRecord
(
tx
.
Hash
(),
common
.
Hash
{},
0
)
err
:=
env
.
commitTransaction
(
tx
,
bc
,
gp
)
err
,
logs
:=
env
.
commitTransaction
(
tx
,
bc
,
gp
)
switch
{
case
core
.
IsGasLimitErr
(
err
)
:
// ignore the transactor so no nonce errors will be thrown for this account
...
...
@@ -643,20 +645,25 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b
}
default
:
env
.
tcount
++
coalescedLogs
=
append
(
coalescedLogs
,
logs
...
)
}
}
if
len
(
coalescedLogs
)
>
0
{
go
mux
.
Post
(
core
.
PendingLogsEvent
{
Logs
:
coalescedLogs
})
}
}
func
(
env
*
Work
)
commitTransaction
(
tx
*
types
.
Transaction
,
bc
*
core
.
BlockChain
,
gp
*
core
.
GasPool
)
error
{
func
(
env
*
Work
)
commitTransaction
(
tx
*
types
.
Transaction
,
bc
*
core
.
BlockChain
,
gp
*
core
.
GasPool
)
(
error
,
vm
.
Logs
)
{
snap
:=
env
.
state
.
Copy
()
receipt
,
_
,
_
,
err
:=
core
.
ApplyTransaction
(
bc
,
gp
,
env
.
state
,
env
.
header
,
tx
,
env
.
header
.
GasUsed
)
receipt
,
logs
,
_
,
err
:=
core
.
ApplyTransaction
(
bc
,
gp
,
env
.
state
,
env
.
header
,
tx
,
env
.
header
.
GasUsed
)
if
err
!=
nil
{
env
.
state
.
Set
(
snap
)
return
err
return
err
,
nil
}
env
.
txs
=
append
(
env
.
txs
,
tx
)
env
.
receipts
=
append
(
env
.
receipts
,
receipt
)
return
nil
return
nil
,
logs
}
// TODO: remove or use
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment