Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
whqwjb
go-ethereum
提交
7f79d249
G
go-ethereum
项目概览
whqwjb
/
go-ethereum
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
go-ethereum
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
7f79d249
编写于
12月 05, 2016
作者:
F
Felix Lange
提交者:
GitHub
12月 05, 2016
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #3402 from fjl/ethclient-api-fixes
eth/filters, ethclient, ethereum: API improvements
上级
2dcf75a7
f1383740
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
327 addition
and
190 deletion
+327
-190
core/blockchain.go
core/blockchain.go
+15
-14
core/events.go
core/events.go
+0
-1
core/vm/log.go
core/vm/log.go
+103
-39
core/vm/log_test.go
core/vm/log_test.go
+71
-2
eth/filters/api.go
eth/filters/api.go
+10
-9
eth/filters/filter.go
eth/filters/filter.go
+12
-15
eth/filters/filter_system.go
eth/filters/filter_system.go
+16
-60
eth/filters/filter_system_test.go
eth/filters/filter_system_test.go
+25
-25
ethclient/ethclient.go
ethclient/ethclient.go
+39
-17
ethclient/ethclient_test.go
ethclient/ethclient_test.go
+1
-1
interfaces.go
interfaces.go
+33
-6
mobile/ethclient.go
mobile/ethclient.go
+2
-1
未找到文件。
core/blockchain.go
浏览文件 @
7f79d249
...
...
@@ -988,7 +988,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
glog
.
Infof
(
"inserted forked block #%d [%x…] (TD=%v) in %9v: %3d txs %d uncles."
,
block
.
Number
(),
block
.
Hash
()
.
Bytes
()[
0
:
4
],
block
.
Difficulty
(),
common
.
PrettyDuration
(
time
.
Since
(
bstart
)),
len
(
block
.
Transactions
()),
len
(
block
.
Uncles
()))
}
blockInsertTimer
.
UpdateSince
(
bstart
)
events
=
append
(
events
,
ChainSideEvent
{
block
,
logs
})
events
=
append
(
events
,
ChainSideEvent
{
block
})
case
SplitStatTy
:
events
=
append
(
events
,
ChainSplitEvent
{
block
,
logs
})
...
...
@@ -1062,24 +1062,25 @@ func countTransactions(chain []*types.Block) (c int) {
// event about them
func
(
self
*
BlockChain
)
reorg
(
oldBlock
,
newBlock
*
types
.
Block
)
error
{
var
(
newChain
types
.
Blocks
oldChain
types
.
Blocks
commonBlock
*
types
.
Block
oldStart
=
oldBlock
newStart
=
newBlock
deletedTxs
types
.
Transactions
deletedLogs
vm
.
Logs
deletedLogsByHash
=
make
(
map
[
common
.
Hash
]
vm
.
Logs
)
newChain
types
.
Blocks
oldChain
types
.
Blocks
commonBlock
*
types
.
Block
oldStart
=
oldBlock
newStart
=
newBlock
deletedTxs
types
.
Transactions
deletedLogs
vm
.
Logs
// collectLogs collects the logs that were generated during the
// processing of the block that corresponds with the given hash.
// These logs are later announced as deleted.
collectLogs
=
func
(
h
common
.
Hash
)
{
// Coalesce logs
// Coalesce logs
and set 'Removed'.
receipts
:=
GetBlockReceipts
(
self
.
chainDb
,
h
,
self
.
hc
.
GetBlockNumber
(
h
))
for
_
,
receipt
:=
range
receipts
{
deletedLogs
=
append
(
deletedLogs
,
receipt
.
Logs
...
)
deletedLogsByHash
[
h
]
=
receipt
.
Logs
for
_
,
log
:=
range
receipt
.
Logs
{
del
:=
*
log
del
.
Removed
=
true
deletedLogs
=
append
(
deletedLogs
,
&
del
)
}
}
}
)
...
...
@@ -1173,7 +1174,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
if
len
(
oldChain
)
>
0
{
go
func
()
{
for
_
,
block
:=
range
oldChain
{
self
.
eventMux
.
Post
(
ChainSideEvent
{
Block
:
block
,
Logs
:
deletedLogsByHash
[
block
.
Hash
()]
})
self
.
eventMux
.
Post
(
ChainSideEvent
{
Block
:
block
})
}
}()
}
...
...
core/events.go
浏览文件 @
7f79d249
...
...
@@ -61,7 +61,6 @@ type ChainEvent struct {
type
ChainSideEvent
struct
{
Block
*
types
.
Block
Logs
vm
.
Logs
}
type
PendingBlockEvent
struct
{
...
...
core/vm/log.go
浏览文件 @
7f79d249
...
...
@@ -29,20 +29,42 @@ import (
var
errMissingLogFields
=
errors
.
New
(
"missing required JSON log fields"
)
// Log represents a contract log event. These events are generated by the LOG
//
opcode and
stored/indexed by the node.
// Log represents a contract log event. These events are generated by the LOG
opcode and
// stored/indexed by the node.
type
Log
struct
{
// Consensus fields.
Address
common
.
Address
// address of the contract that generated the event
Topics
[]
common
.
Hash
// list of topics provided by the contract.
Data
[]
byte
// supplied by the contract, usually ABI-encoded
// Derived fields (don't reorder!).
// Derived fields. These fields are filled in by the node
// but not secured by consensus.
BlockNumber
uint64
// block in which the transaction was included
TxHash
common
.
Hash
// hash of the transaction
TxIndex
uint
// index of the transaction in the block
BlockHash
common
.
Hash
// hash of the block in which the transaction was included
Index
uint
// index of the log in the receipt
// The Removed field is true if this log was reverted due to a chain reorganisation.
// You must pay attention to this field if you receive logs through a filter query.
Removed
bool
}
type
rlpLog
struct
{
Address
common
.
Address
Topics
[]
common
.
Hash
Data
[]
byte
}
type
rlpStorageLog
struct
{
Address
common
.
Address
Topics
[]
common
.
Hash
Data
[]
byte
BlockNumber
uint64
TxHash
common
.
Hash
TxIndex
uint
BlockHash
common
.
Hash
Index
uint
}
type
jsonLog
struct
{
...
...
@@ -54,27 +76,26 @@ type jsonLog struct {
TxHash
*
common
.
Hash
`json:"transactionHash"`
BlockHash
*
common
.
Hash
`json:"blockHash"`
Index
*
hexutil
.
Uint
`json:"logIndex"`
Removed
bool
`json:"removed"`
}
func
NewLog
(
address
common
.
Address
,
topics
[]
common
.
Hash
,
data
[]
byte
,
number
uint64
)
*
Log
{
return
&
Log
{
Address
:
address
,
Topics
:
topics
,
Data
:
data
,
BlockNumber
:
number
}
}
// EncodeRLP implements rlp.Encoder.
func
(
l
*
Log
)
EncodeRLP
(
w
io
.
Writer
)
error
{
return
rlp
.
Encode
(
w
,
[]
interface
{}{
l
.
Address
,
l
.
Topics
,
l
.
Data
})
return
rlp
.
Encode
(
w
,
rlpLog
{
Address
:
l
.
Address
,
Topics
:
l
.
Topics
,
Data
:
l
.
Data
})
}
// DecodeRLP implements rlp.Decoder.
func
(
l
*
Log
)
DecodeRLP
(
s
*
rlp
.
Stream
)
error
{
var
log
struct
{
Address
common
.
Address
Topics
[]
common
.
Hash
Data
[]
byte
var
dec
rlpLog
err
:=
s
.
Decode
(
&
dec
)
if
err
==
nil
{
l
.
Address
,
l
.
Topics
,
l
.
Data
=
dec
.
Address
,
dec
.
Topics
,
dec
.
Data
}
if
err
:=
s
.
Decode
(
&
log
);
err
!=
nil
{
return
err
}
l
.
Address
,
l
.
Topics
,
l
.
Data
=
log
.
Address
,
log
.
Topics
,
log
.
Data
return
nil
return
err
}
func
(
l
*
Log
)
String
()
string
{
...
...
@@ -82,45 +103,88 @@ func (l *Log) String() string {
}
// MarshalJSON implements json.Marshaler.
func
(
r
*
Log
)
MarshalJSON
()
([]
byte
,
error
)
{
return
json
.
Marshal
(
&
jsonLog
{
Address
:
&
r
.
Address
,
Topics
:
&
r
.
Topics
,
Data
:
(
*
hexutil
.
Bytes
)(
&
r
.
Data
),
BlockNumber
:
(
*
hexutil
.
Uint64
)(
&
r
.
BlockNumber
),
TxIndex
:
(
*
hexutil
.
Uint
)(
&
r
.
TxIndex
),
TxHash
:
&
r
.
TxHash
,
BlockHash
:
&
r
.
BlockHash
,
Index
:
(
*
hexutil
.
Uint
)(
&
r
.
Index
),
})
func
(
l
*
Log
)
MarshalJSON
()
([]
byte
,
error
)
{
jslog
:=
&
jsonLog
{
Address
:
&
l
.
Address
,
Topics
:
&
l
.
Topics
,
Data
:
(
*
hexutil
.
Bytes
)(
&
l
.
Data
),
TxIndex
:
(
*
hexutil
.
Uint
)(
&
l
.
TxIndex
),
TxHash
:
&
l
.
TxHash
,
Index
:
(
*
hexutil
.
Uint
)(
&
l
.
Index
),
Removed
:
l
.
Removed
,
}
// Set block information for mined logs.
if
(
l
.
BlockHash
!=
common
.
Hash
{})
{
jslog
.
BlockHash
=
&
l
.
BlockHash
jslog
.
BlockNumber
=
(
*
hexutil
.
Uint64
)(
&
l
.
BlockNumber
)
}
return
json
.
Marshal
(
jslog
)
}
// UnmarshalJSON implements json.Umarshaler.
func
(
r
*
Log
)
UnmarshalJSON
(
input
[]
byte
)
error
{
func
(
l
*
Log
)
UnmarshalJSON
(
input
[]
byte
)
error
{
var
dec
jsonLog
if
err
:=
json
.
Unmarshal
(
input
,
&
dec
);
err
!=
nil
{
return
err
}
if
dec
.
Address
==
nil
||
dec
.
Topics
==
nil
||
dec
.
Data
==
nil
||
dec
.
BlockNumber
==
nil
||
dec
.
TxIndex
==
nil
||
dec
.
TxHash
==
nil
||
dec
.
BlockHash
==
nil
||
dec
.
Index
==
nil
{
if
dec
.
Address
==
nil
||
dec
.
Topics
==
nil
||
dec
.
Data
==
nil
||
dec
.
TxIndex
==
nil
||
dec
.
TxHash
==
nil
||
dec
.
Index
==
nil
{
return
errMissingLogFields
}
*
r
=
Log
{
Address
:
*
dec
.
Address
,
Topics
:
*
dec
.
Topics
,
Data
:
*
dec
.
Data
,
BlockNumber
:
uint64
(
*
dec
.
BlockNumber
),
TxHash
:
*
dec
.
TxHash
,
TxIndex
:
uint
(
*
dec
.
TxIndex
),
BlockHash
:
*
dec
.
BlockHash
,
Index
:
uint
(
*
dec
.
Index
),
declog
:=
Log
{
Address
:
*
dec
.
Address
,
Topics
:
*
dec
.
Topics
,
Data
:
*
dec
.
Data
,
TxHash
:
*
dec
.
TxHash
,
TxIndex
:
uint
(
*
dec
.
TxIndex
),
Index
:
uint
(
*
dec
.
Index
),
Removed
:
dec
.
Removed
,
}
// Block information may be missing if the log is received through
// the pending log filter, so it's handled specially here.
if
dec
.
BlockHash
!=
nil
&&
dec
.
BlockNumber
!=
nil
{
declog
.
BlockHash
=
*
dec
.
BlockHash
declog
.
BlockNumber
=
uint64
(
*
dec
.
BlockNumber
)
}
*
l
=
declog
return
nil
}
type
Logs
[]
*
Log
// LogForStorage is a wrapper around a Log that flattens and parses the entire
// content of a log, as opposed to only the consensus fields originally (by hiding
// the rlp interface methods).
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
// a log including non-consensus fields.
type
LogForStorage
Log
// EncodeRLP implements rlp.Encoder.
func
(
l
*
LogForStorage
)
EncodeRLP
(
w
io
.
Writer
)
error
{
return
rlp
.
Encode
(
w
,
rlpStorageLog
{
Address
:
l
.
Address
,
Topics
:
l
.
Topics
,
Data
:
l
.
Data
,
BlockNumber
:
l
.
BlockNumber
,
TxHash
:
l
.
TxHash
,
TxIndex
:
l
.
TxIndex
,
BlockHash
:
l
.
BlockHash
,
Index
:
l
.
Index
,
})
}
// DecodeRLP implements rlp.Decoder.
func
(
l
*
LogForStorage
)
DecodeRLP
(
s
*
rlp
.
Stream
)
error
{
var
dec
rlpStorageLog
err
:=
s
.
Decode
(
&
dec
)
if
err
==
nil
{
*
l
=
LogForStorage
{
Address
:
dec
.
Address
,
Topics
:
dec
.
Topics
,
Data
:
dec
.
Data
,
BlockNumber
:
dec
.
BlockNumber
,
TxHash
:
dec
.
TxHash
,
TxIndex
:
dec
.
TxIndex
,
BlockHash
:
dec
.
BlockHash
,
Index
:
dec
.
Index
,
}
}
return
err
}
core/vm/log_test.go
浏览文件 @
7f79d249
...
...
@@ -18,18 +18,81 @@ package vm
import
(
"encoding/json"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var
unmarshalLogTests
=
map
[
string
]
struct
{
input
string
want
*
Log
wantError
error
}{
"ok"
:
{
input
:
`{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`
,
input
:
`{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`
,
want
:
&
Log
{
Address
:
common
.
HexToAddress
(
"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"
),
BlockHash
:
common
.
HexToHash
(
"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"
),
BlockNumber
:
2019236
,
Data
:
hexutil
.
MustDecode
(
"0x000000000000000000000000000000000000000000000001a055690d9db80000"
),
Index
:
2
,
TxIndex
:
3
,
TxHash
:
common
.
HexToHash
(
"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"
),
Topics
:
[]
common
.
Hash
{
common
.
HexToHash
(
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
),
common
.
HexToHash
(
"0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"
),
},
},
},
"empty data"
:
{
input
:
`{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`
,
input
:
`{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`
,
want
:
&
Log
{
Address
:
common
.
HexToAddress
(
"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"
),
BlockHash
:
common
.
HexToHash
(
"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"
),
BlockNumber
:
2019236
,
Data
:
[]
byte
{},
Index
:
2
,
TxIndex
:
3
,
TxHash
:
common
.
HexToHash
(
"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"
),
Topics
:
[]
common
.
Hash
{
common
.
HexToHash
(
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
),
common
.
HexToHash
(
"0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"
),
},
},
},
"missing block fields (pending logs)"
:
{
input
:
`{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","data":"0x","logIndex":"0x0","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`
,
want
:
&
Log
{
Address
:
common
.
HexToAddress
(
"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"
),
BlockHash
:
common
.
Hash
{},
BlockNumber
:
0
,
Data
:
[]
byte
{},
Index
:
0
,
TxIndex
:
3
,
TxHash
:
common
.
HexToHash
(
"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"
),
Topics
:
[]
common
.
Hash
{
common
.
HexToHash
(
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
),
},
},
},
"Removed: true"
:
{
input
:
`{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3","removed":true}`
,
want
:
&
Log
{
Address
:
common
.
HexToAddress
(
"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"
),
BlockHash
:
common
.
HexToHash
(
"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"
),
BlockNumber
:
2019236
,
Data
:
[]
byte
{},
Index
:
2
,
TxIndex
:
3
,
TxHash
:
common
.
HexToHash
(
"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"
),
Topics
:
[]
common
.
Hash
{
common
.
HexToHash
(
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
),
},
Removed
:
true
,
},
},
"missing data"
:
{
input
:
`{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`
,
...
...
@@ -38,10 +101,16 @@ var unmarshalLogTests = map[string]struct {
}
func
TestUnmarshalLog
(
t
*
testing
.
T
)
{
dumper
:=
spew
.
ConfigState
{
DisableMethods
:
true
,
Indent
:
" "
}
for
name
,
test
:=
range
unmarshalLogTests
{
var
log
*
Log
err
:=
json
.
Unmarshal
([]
byte
(
test
.
input
),
&
log
)
checkError
(
t
,
name
,
err
,
test
.
wantError
)
if
test
.
wantError
==
nil
&&
err
==
nil
{
if
!
reflect
.
DeepEqual
(
log
,
test
.
want
)
{
t
.
Errorf
(
"test %q:
\n
GOT %sWANT %s"
,
name
,
dumper
.
Sdump
(
log
),
dumper
.
Sdump
(
test
.
want
))
}
}
}
}
...
...
eth/filters/api.go
浏览文件 @
7f79d249
...
...
@@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
...
...
@@ -45,7 +46,7 @@ type filter struct {
deadline
*
time
.
Timer
// filter is inactiv when deadline triggers
hashes
[]
common
.
Hash
crit
FilterCriteria
logs
[]
Log
logs
[]
*
vm
.
Log
s
*
Subscription
// associated subscription in event system
}
...
...
@@ -241,7 +242,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc
var
(
rpcSub
=
notifier
.
CreateSubscription
()
matchedLogs
=
make
(
chan
[]
Log
)
matchedLogs
=
make
(
chan
[]
*
vm
.
Log
)
)
logsSub
,
err
:=
api
.
events
.
SubscribeLogs
(
crit
,
matchedLogs
)
...
...
@@ -292,14 +293,14 @@ type FilterCriteria struct {
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter
func
(
api
*
PublicFilterAPI
)
NewFilter
(
crit
FilterCriteria
)
(
rpc
.
ID
,
error
)
{
logs
:=
make
(
chan
[]
Log
)
logs
:=
make
(
chan
[]
*
vm
.
Log
)
logsSub
,
err
:=
api
.
events
.
SubscribeLogs
(
crit
,
logs
)
if
err
!=
nil
{
return
rpc
.
ID
(
""
),
err
}
api
.
filtersMu
.
Lock
()
api
.
filters
[
logsSub
.
ID
]
=
&
filter
{
typ
:
LogsSubscription
,
crit
:
crit
,
deadline
:
time
.
NewTimer
(
deadline
),
logs
:
make
([]
Log
,
0
),
s
:
logsSub
}
api
.
filters
[
logsSub
.
ID
]
=
&
filter
{
typ
:
LogsSubscription
,
crit
:
crit
,
deadline
:
time
.
NewTimer
(
deadline
),
logs
:
make
([]
*
vm
.
Log
,
0
),
s
:
logsSub
}
api
.
filtersMu
.
Unlock
()
go
func
()
{
...
...
@@ -326,7 +327,7 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
// GetLogs returns logs matching the given argument that are stored within the state.
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
func
(
api
*
PublicFilterAPI
)
GetLogs
(
ctx
context
.
Context
,
crit
FilterCriteria
)
([]
Log
,
error
)
{
func
(
api
*
PublicFilterAPI
)
GetLogs
(
ctx
context
.
Context
,
crit
FilterCriteria
)
([]
*
vm
.
Log
,
error
)
{
if
crit
.
FromBlock
==
nil
{
crit
.
FromBlock
=
big
.
NewInt
(
rpc
.
LatestBlockNumber
.
Int64
())
}
...
...
@@ -365,7 +366,7 @@ func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool {
// If the filter could not be found an empty array of logs is returned.
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterlogs
func
(
api
*
PublicFilterAPI
)
GetFilterLogs
(
ctx
context
.
Context
,
id
rpc
.
ID
)
([]
Log
,
error
)
{
func
(
api
*
PublicFilterAPI
)
GetFilterLogs
(
ctx
context
.
Context
,
id
rpc
.
ID
)
([]
*
vm
.
Log
,
error
)
{
api
.
filtersMu
.
Lock
()
f
,
found
:=
api
.
filters
[
id
]
api
.
filtersMu
.
Unlock
()
...
...
@@ -388,7 +389,7 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]Log
filter
.
SetAddresses
(
f
.
crit
.
Addresses
)
filter
.
SetTopics
(
f
.
crit
.
Topics
)
logs
,
err
:=
filter
.
Find
(
ctx
)
logs
,
err
:=
filter
.
Find
(
ctx
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -440,9 +441,9 @@ func returnHashes(hashes []common.Hash) []common.Hash {
// returnLogs is a helper that will return an empty log array in case the given logs array is nil,
// otherwise the given logs array is returned.
func
returnLogs
(
logs
[]
Log
)
[]
Log
{
func
returnLogs
(
logs
[]
*
vm
.
Log
)
[]
*
vm
.
Log
{
if
logs
==
nil
{
return
[]
Log
{}
return
[]
*
vm
.
Log
{}
}
return
logs
}
...
...
eth/filters/filter.go
浏览文件 @
7f79d249
...
...
@@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
...
...
@@ -38,7 +39,7 @@ type Backend interface {
GetReceipts
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
types
.
Receipts
,
error
)
}
// Filter can be used to retrieve and filter logs
// Filter can be used to retrieve and filter logs
.
type
Filter
struct
{
backend
Backend
useMipMap
bool
...
...
@@ -85,7 +86,7 @@ func (f *Filter) SetTopics(topics [][]common.Hash) {
}
// Run filters logs with the current parameters set
func
(
f
*
Filter
)
Find
(
ctx
context
.
Context
)
([]
Log
,
error
)
{
func
(
f
*
Filter
)
Find
(
ctx
context
.
Context
)
([]
*
vm
.
Log
,
error
)
{
head
,
_
:=
f
.
backend
.
HeaderByNumber
(
ctx
,
rpc
.
LatestBlockNumber
)
if
head
==
nil
{
return
nil
,
nil
...
...
@@ -110,7 +111,7 @@ func (f *Filter) Find(ctx context.Context) ([]Log, error) {
return
f
.
mipFind
(
beginBlockNo
,
endBlockNo
,
0
),
nil
}
func
(
f
*
Filter
)
mipFind
(
start
,
end
uint64
,
depth
int
)
(
logs
[]
Log
)
{
func
(
f
*
Filter
)
mipFind
(
start
,
end
uint64
,
depth
int
)
(
logs
[]
*
vm
.
Log
)
{
level
:=
core
.
MIPMapLevels
[
depth
]
// normalise numerator so we can work in level specific batches and
// work with the proper range checks
...
...
@@ -141,7 +142,7 @@ func (f *Filter) mipFind(start, end uint64, depth int) (logs []Log) {
return
logs
}
func
(
f
*
Filter
)
getLogs
(
ctx
context
.
Context
,
start
,
end
uint64
)
(
logs
[]
Log
,
err
error
)
{
func
(
f
*
Filter
)
getLogs
(
ctx
context
.
Context
,
start
,
end
uint64
)
(
logs
[]
*
vm
.
Log
,
err
error
)
{
for
i
:=
start
;
i
<=
end
;
i
++
{
header
,
err
:=
f
.
backend
.
HeaderByNumber
(
ctx
,
rpc
.
BlockNumber
(
i
))
if
header
==
nil
||
err
!=
nil
{
...
...
@@ -156,13 +157,9 @@ func (f *Filter) getLogs(ctx context.Context, start, end uint64) (logs []Log, er
if
err
!=
nil
{
return
nil
,
err
}
var
unfiltered
[]
Log
var
unfiltered
[]
*
vm
.
Log
for
_
,
receipt
:=
range
receipts
{
rl
:=
make
([]
Log
,
len
(
receipt
.
Logs
))
for
i
,
l
:=
range
receipt
.
Logs
{
rl
[
i
]
=
Log
{
l
,
false
}
}
unfiltered
=
append
(
unfiltered
,
rl
...
)
unfiltered
=
append
(
unfiltered
,
([]
*
vm
.
Log
)(
receipt
.
Logs
)
...
)
}
logs
=
append
(
logs
,
filterLogs
(
unfiltered
,
nil
,
nil
,
f
.
addresses
,
f
.
topics
)
...
)
}
...
...
@@ -181,15 +178,15 @@ func includes(addresses []common.Address, a common.Address) bool {
return
false
}
func
filterLogs
(
logs
[]
Log
,
fromBlock
,
toBlock
*
big
.
Int
,
addresses
[]
common
.
Address
,
topics
[][]
common
.
Hash
)
[]
Log
{
var
ret
[]
Log
// Filter the logs for interesting stuff
// filterLogs creates a slice of logs matching the given criteria.
func
filterLogs
(
logs
[]
*
vm
.
Log
,
fromBlock
,
toBlock
*
big
.
Int
,
addresses
[]
common
.
Address
,
topics
[][]
common
.
Hash
)
[]
*
vm
.
Log
{
var
ret
[]
*
vm
.
Log
Logs
:
for
_
,
log
:=
range
logs
{
if
fromBlock
!=
nil
&&
fromBlock
.
Int64
()
>=
0
&&
uint64
(
fromBlock
.
Int64
()
)
>
log
.
BlockNumber
{
if
fromBlock
!=
nil
&&
fromBlock
.
Int64
()
>=
0
&&
fromBlock
.
Uint64
(
)
>
log
.
BlockNumber
{
continue
}
if
toBlock
!=
nil
&&
toBlock
.
Int64
()
>=
0
&&
uint64
(
toBlock
.
Int64
()
)
<
log
.
BlockNumber
{
if
toBlock
!=
nil
&&
toBlock
.
Int64
()
>=
0
&&
toBlock
.
Uint64
(
)
<
log
.
BlockNumber
{
continue
}
...
...
eth/filters/filter_system.go
浏览文件 @
7f79d249
...
...
@@ -19,7 +19,6 @@
package
filters
import
(
"encoding/json"
"errors"
"fmt"
"sync"
...
...
@@ -60,42 +59,12 @@ var (
ErrInvalidSubscriptionID
=
errors
.
New
(
"invalid id"
)
)
// Log is a helper that can hold additional information about vm.Log
// necessary for the RPC interface.
type
Log
struct
{
*
vm
.
Log
Removed
bool
`json:"removed"`
}
// MarshalJSON returns *l as the JSON encoding of l.
func
(
l
*
Log
)
MarshalJSON
()
([]
byte
,
error
)
{
fields
:=
map
[
string
]
interface
{}{
"address"
:
l
.
Address
,
"data"
:
fmt
.
Sprintf
(
"0x%x"
,
l
.
Data
),
"blockNumber"
:
nil
,
"logIndex"
:
fmt
.
Sprintf
(
"%#x"
,
l
.
Index
),
"blockHash"
:
nil
,
"transactionHash"
:
l
.
TxHash
,
"transactionIndex"
:
fmt
.
Sprintf
(
"%#x"
,
l
.
TxIndex
),
"topics"
:
l
.
Topics
,
"removed"
:
l
.
Removed
,
}
// mined logs
if
l
.
BlockHash
!=
(
common
.
Hash
{})
{
fields
[
"blockNumber"
]
=
fmt
.
Sprintf
(
"%#x"
,
l
.
BlockNumber
)
fields
[
"blockHash"
]
=
l
.
BlockHash
}
return
json
.
Marshal
(
fields
)
}
type
subscription
struct
{
id
rpc
.
ID
typ
Type
created
time
.
Time
logsCrit
FilterCriteria
logs
chan
[]
Log
logs
chan
[]
*
vm
.
Log
hashes
chan
common
.
Hash
headers
chan
*
types
.
Header
installed
chan
struct
{}
// closed when the filter is installed
...
...
@@ -182,7 +151,7 @@ func (es *EventSystem) subscribe(sub *subscription) *Subscription {
// SubscribeLogs creates a subscription that will write all logs matching the
// given criteria to the given logs channel. Default value for the from and to
// block is "latest". If the fromBlock > toBlock an error is returned.
func
(
es
*
EventSystem
)
SubscribeLogs
(
crit
FilterCriteria
,
logs
chan
[]
Log
)
(
*
Subscription
,
error
)
{
func
(
es
*
EventSystem
)
SubscribeLogs
(
crit
FilterCriteria
,
logs
chan
[]
*
vm
.
Log
)
(
*
Subscription
,
error
)
{
var
from
,
to
rpc
.
BlockNumber
if
crit
.
FromBlock
==
nil
{
from
=
rpc
.
LatestBlockNumber
...
...
@@ -220,7 +189,7 @@ func (es *EventSystem) SubscribeLogs(crit FilterCriteria, logs chan []Log) (*Sub
// subscribeMinedPendingLogs creates a subscription that returned mined and
// pending logs that match the given criteria.
func
(
es
*
EventSystem
)
subscribeMinedPendingLogs
(
crit
FilterCriteria
,
logs
chan
[]
Log
)
*
Subscription
{
func
(
es
*
EventSystem
)
subscribeMinedPendingLogs
(
crit
FilterCriteria
,
logs
chan
[]
*
vm
.
Log
)
*
Subscription
{
sub
:=
&
subscription
{
id
:
rpc
.
NewID
(),
typ
:
MinedAndPendingLogsSubscription
,
...
...
@@ -238,7 +207,7 @@ func (es *EventSystem) subscribeMinedPendingLogs(crit FilterCriteria, logs chan
// subscribeLogs creates a subscription that will write all logs matching the
// given criteria to the given logs channel.
func
(
es
*
EventSystem
)
subscribeLogs
(
crit
FilterCriteria
,
logs
chan
[]
Log
)
*
Subscription
{
func
(
es
*
EventSystem
)
subscribeLogs
(
crit
FilterCriteria
,
logs
chan
[]
*
vm
.
Log
)
*
Subscription
{
sub
:=
&
subscription
{
id
:
rpc
.
NewID
(),
typ
:
LogsSubscription
,
...
...
@@ -256,7 +225,7 @@ func (es *EventSystem) subscribeLogs(crit FilterCriteria, logs chan []Log) *Subs
// subscribePendingLogs creates a subscription that writes transaction hashes for
// transactions that enter the transaction pool.
func
(
es
*
EventSystem
)
subscribePendingLogs
(
crit
FilterCriteria
,
logs
chan
[]
Log
)
*
Subscription
{
func
(
es
*
EventSystem
)
subscribePendingLogs
(
crit
FilterCriteria
,
logs
chan
[]
*
vm
.
Log
)
*
Subscription
{
sub
:=
&
subscription
{
id
:
rpc
.
NewID
(),
typ
:
PendingLogsSubscription
,
...
...
@@ -279,7 +248,7 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti
id
:
rpc
.
NewID
(),
typ
:
BlocksSubscription
,
created
:
time
.
Now
(),
logs
:
make
(
chan
[]
Log
),
logs
:
make
(
chan
[]
*
vm
.
Log
),
hashes
:
make
(
chan
common
.
Hash
),
headers
:
headers
,
installed
:
make
(
chan
struct
{}),
...
...
@@ -296,7 +265,7 @@ func (es *EventSystem) SubscribePendingTxEvents(hashes chan common.Hash) *Subscr
id
:
rpc
.
NewID
(),
typ
:
PendingTransactionsSubscription
,
created
:
time
.
Now
(),
logs
:
make
(
chan
[]
Log
),
logs
:
make
(
chan
[]
*
vm
.
Log
),
hashes
:
hashes
,
headers
:
make
(
chan
*
types
.
Header
),
installed
:
make
(
chan
struct
{}),
...
...
@@ -319,7 +288,7 @@ func (es *EventSystem) broadcast(filters filterIndex, ev *event.Event) {
if
len
(
e
)
>
0
{
for
_
,
f
:=
range
filters
[
LogsSubscription
]
{
if
ev
.
Time
.
After
(
f
.
created
)
{
if
matchedLogs
:=
filterLogs
(
convertLogs
(
e
,
false
)
,
f
.
logsCrit
.
FromBlock
,
f
.
logsCrit
.
ToBlock
,
f
.
logsCrit
.
Addresses
,
f
.
logsCrit
.
Topics
);
len
(
matchedLogs
)
>
0
{
if
matchedLogs
:=
filterLogs
(
e
,
f
.
logsCrit
.
FromBlock
,
f
.
logsCrit
.
ToBlock
,
f
.
logsCrit
.
Addresses
,
f
.
logsCrit
.
Topics
);
len
(
matchedLogs
)
>
0
{
f
.
logs
<-
matchedLogs
}
}
...
...
@@ -328,7 +297,7 @@ func (es *EventSystem) broadcast(filters filterIndex, ev *event.Event) {
case
core
.
RemovedLogsEvent
:
for
_
,
f
:=
range
filters
[
LogsSubscription
]
{
if
ev
.
Time
.
After
(
f
.
created
)
{
if
matchedLogs
:=
filterLogs
(
convertLogs
(
e
.
Logs
,
true
)
,
f
.
logsCrit
.
FromBlock
,
f
.
logsCrit
.
ToBlock
,
f
.
logsCrit
.
Addresses
,
f
.
logsCrit
.
Topics
);
len
(
matchedLogs
)
>
0
{
if
matchedLogs
:=
filterLogs
(
e
.
Logs
,
f
.
logsCrit
.
FromBlock
,
f
.
logsCrit
.
ToBlock
,
f
.
logsCrit
.
Addresses
,
f
.
logsCrit
.
Topics
);
len
(
matchedLogs
)
>
0
{
f
.
logs
<-
matchedLogs
}
}
...
...
@@ -336,7 +305,7 @@ func (es *EventSystem) broadcast(filters filterIndex, ev *event.Event) {
case
core
.
PendingLogsEvent
:
for
_
,
f
:=
range
filters
[
PendingLogsSubscription
]
{
if
ev
.
Time
.
After
(
f
.
created
)
{
if
matchedLogs
:=
filterLogs
(
convertLogs
(
e
.
Logs
,
false
)
,
nil
,
f
.
logsCrit
.
ToBlock
,
f
.
logsCrit
.
Addresses
,
f
.
logsCrit
.
Topics
);
len
(
matchedLogs
)
>
0
{
if
matchedLogs
:=
filterLogs
(
e
.
Logs
,
nil
,
f
.
logsCrit
.
ToBlock
,
f
.
logsCrit
.
Addresses
,
f
.
logsCrit
.
Topics
);
len
(
matchedLogs
)
>
0
{
f
.
logs
<-
matchedLogs
}
}
...
...
@@ -401,25 +370,22 @@ func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func
}
// filter logs of a single header in light client mode
func
(
es
*
EventSystem
)
lightFilterLogs
(
header
*
types
.
Header
,
addresses
[]
common
.
Address
,
topics
[][]
common
.
Hash
,
remove
bool
)
[]
Log
{
//fmt.Println("lightFilterLogs", header.Number.Uint64(), remove)
func
(
es
*
EventSystem
)
lightFilterLogs
(
header
*
types
.
Header
,
addresses
[]
common
.
Address
,
topics
[][]
common
.
Hash
,
remove
bool
)
[]
*
vm
.
Log
{
if
bloomFilter
(
header
.
Bloom
,
addresses
,
topics
)
{
//fmt.Println("bloom match")
// Get the logs of the block
ctx
,
_
:=
context
.
WithTimeout
(
context
.
Background
(),
time
.
Second
*
5
)
receipts
,
err
:=
es
.
backend
.
GetReceipts
(
ctx
,
header
.
Hash
())
if
err
!=
nil
{
return
nil
}
var
unfiltered
[]
Log
var
unfiltered
[]
*
vm
.
Log
for
_
,
receipt
:=
range
receipts
{
rl
:=
make
([]
Log
,
len
(
receipt
.
Logs
))
for
i
,
l
:=
range
receipt
.
Logs
{
rl
[
i
]
=
Log
{
l
,
remove
}
for
_
,
log
:=
range
receipt
.
Logs
{
logcopy
:=
*
log
logcopy
.
Removed
=
remove
unfiltered
=
append
(
unfiltered
,
&
logcopy
)
}
unfiltered
=
append
(
unfiltered
,
rl
...
)
}
logs
:=
filterLogs
(
unfiltered
,
nil
,
nil
,
addresses
,
topics
)
return
logs
}
...
...
@@ -465,13 +431,3 @@ func (es *EventSystem) eventLoop() {
}
}
}
// convertLogs is a helper utility that converts vm.Logs to []filter.Log.
func
convertLogs
(
in
vm
.
Logs
,
removed
bool
)
[]
Log
{
logs
:=
make
([]
Log
,
len
(
in
))
for
i
,
l
:=
range
in
{
logs
[
i
]
=
Log
{
l
,
removed
}
}
return
logs
}
eth/filters/filter_system_test.go
浏览文件 @
7f79d249
...
...
@@ -74,10 +74,10 @@ func TestBlockSubscription(t *testing.T) {
t
.
Parallel
()
var
(
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
backend
=
&
testBackend
{
mux
,
db
}
api
=
NewPublicFilterAPI
(
backend
,
false
)
api
=
NewPublicFilterAPI
(
backend
,
false
)
genesis
=
core
.
WriteGenesisBlockForTesting
(
db
)
chain
,
_
=
core
.
GenerateChain
(
params
.
TestChainConfig
,
genesis
,
db
,
10
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{})
...
...
@@ -128,10 +128,10 @@ func TestPendingTxFilter(t *testing.T) {
t
.
Parallel
()
var
(
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
backend
=
&
testBackend
{
mux
,
db
}
api
=
NewPublicFilterAPI
(
backend
,
false
)
api
=
NewPublicFilterAPI
(
backend
,
false
)
transactions
=
[]
*
types
.
Transaction
{
types
.
NewTransaction
(
0
,
common
.
HexToAddress
(
"0xb794f5ea0ba39494ce83a213fffba74279579268"
),
new
(
big
.
Int
),
new
(
big
.
Int
),
new
(
big
.
Int
),
nil
),
...
...
@@ -178,10 +178,10 @@ func TestPendingTxFilter(t *testing.T) {
// If not it must return an error.
func
TestLogFilterCreation
(
t
*
testing
.
T
)
{
var
(
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
backend
=
&
testBackend
{
mux
,
db
}
api
=
NewPublicFilterAPI
(
backend
,
false
)
api
=
NewPublicFilterAPI
(
backend
,
false
)
testCases
=
[]
struct
{
crit
FilterCriteria
...
...
@@ -223,10 +223,10 @@ func TestInvalidLogFilterCreation(t *testing.T) {
t
.
Parallel
()
var
(
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
backend
=
&
testBackend
{
mux
,
db
}
api
=
NewPublicFilterAPI
(
backend
,
false
)
api
=
NewPublicFilterAPI
(
backend
,
false
)
)
// different situations where log filter creation should fail.
...
...
@@ -249,10 +249,10 @@ func TestLogFilter(t *testing.T) {
t
.
Parallel
()
var
(
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
backend
=
&
testBackend
{
mux
,
db
}
api
=
NewPublicFilterAPI
(
backend
,
false
)
api
=
NewPublicFilterAPI
(
backend
,
false
)
firstAddr
=
common
.
HexToAddress
(
"0x1111111111111111111111111111111111111111"
)
secondAddr
=
common
.
HexToAddress
(
"0x2222222222222222222222222222222222222222"
)
...
...
@@ -321,14 +321,14 @@ func TestLogFilter(t *testing.T) {
}
for
i
,
tt
:=
range
testCases
{
var
fetched
[]
Log
var
fetched
[]
*
vm
.
Log
for
{
// fetch all expected logs
results
,
err
:=
api
.
GetFilterChanges
(
tt
.
id
)
if
err
!=
nil
{
t
.
Fatalf
(
"Unable to fetch logs: %v"
,
err
)
}
fetched
=
append
(
fetched
,
results
.
([]
Log
)
...
)
fetched
=
append
(
fetched
,
results
.
([]
*
vm
.
Log
)
...
)
if
len
(
fetched
)
>=
len
(
tt
.
expected
)
{
break
}
...
...
@@ -345,7 +345,7 @@ func TestLogFilter(t *testing.T) {
if
fetched
[
l
]
.
Removed
{
t
.
Errorf
(
"expected log not to be removed for log %d in case %d"
,
l
,
i
)
}
if
!
reflect
.
DeepEqual
(
fetched
[
l
]
.
Log
,
tt
.
expected
[
l
])
{
if
!
reflect
.
DeepEqual
(
fetched
[
l
],
tt
.
expected
[
l
])
{
t
.
Errorf
(
"invalid log on index %d for case %d"
,
l
,
i
)
}
}
...
...
@@ -357,10 +357,10 @@ func TestPendingLogsSubscription(t *testing.T) {
t
.
Parallel
()
var
(
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
mux
=
new
(
event
.
TypeMux
)
db
,
_
=
ethdb
.
NewMemDatabase
()
backend
=
&
testBackend
{
mux
,
db
}
api
=
NewPublicFilterAPI
(
backend
,
false
)
api
=
NewPublicFilterAPI
(
backend
,
false
)
firstAddr
=
common
.
HexToAddress
(
"0x1111111111111111111111111111111111111111"
)
secondAddr
=
common
.
HexToAddress
(
"0x2222222222222222222222222222222222222222"
)
...
...
@@ -397,7 +397,7 @@ func TestPendingLogsSubscription(t *testing.T) {
testCases
=
[]
struct
{
crit
FilterCriteria
expected
vm
.
Logs
c
chan
[]
Log
c
chan
[]
*
vm
.
Log
sub
*
Subscription
}{
// match all
...
...
@@ -423,7 +423,7 @@ func TestPendingLogsSubscription(t *testing.T) {
// on slow machines this could otherwise lead to missing events when the subscription is created after
// (some) events are posted.
for
i
:=
range
testCases
{
testCases
[
i
]
.
c
=
make
(
chan
[]
Log
)
testCases
[
i
]
.
c
=
make
(
chan
[]
*
vm
.
Log
)
testCases
[
i
]
.
sub
,
_
=
api
.
events
.
SubscribeLogs
(
testCases
[
i
]
.
crit
,
testCases
[
i
]
.
c
)
}
...
...
@@ -431,7 +431,7 @@ func TestPendingLogsSubscription(t *testing.T) {
i
:=
n
tt
:=
test
go
func
()
{
var
fetched
[]
Log
var
fetched
[]
*
vm
.
Log
fetchLoop
:
for
{
logs
:=
<-
tt
.
c
...
...
@@ -449,7 +449,7 @@ func TestPendingLogsSubscription(t *testing.T) {
if
fetched
[
l
]
.
Removed
{
t
.
Errorf
(
"expected log not to be removed for log %d in case %d"
,
l
,
i
)
}
if
!
reflect
.
DeepEqual
(
fetched
[
l
]
.
Log
,
tt
.
expected
[
l
])
{
if
!
reflect
.
DeepEqual
(
fetched
[
l
],
tt
.
expected
[
l
])
{
t
.
Errorf
(
"invalid log on index %d for case %d"
,
l
,
i
)
}
}
...
...
ethclient/ethclient.go
浏览文件 @
7f79d249
...
...
@@ -81,6 +81,8 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
err
:=
ec
.
c
.
CallContext
(
ctx
,
&
raw
,
method
,
args
...
)
if
err
!=
nil
{
return
nil
,
err
}
else
if
len
(
raw
)
==
0
{
return
nil
,
ethereum
.
NotFound
}
// Decode header and transactions.
var
head
*
types
.
Header
...
...
@@ -112,7 +114,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
for
i
:=
range
reqs
{
reqs
[
i
]
=
rpc
.
BatchElem
{
Method
:
"eth_getUncleByBlockHashAndIndex"
,
Args
:
[]
interface
{}{
body
.
Hash
,
fmt
.
Sprintf
(
"%#x"
,
i
)},
Args
:
[]
interface
{}{
body
.
Hash
,
hexutil
.
EncodeUint64
(
uint64
(
i
)
)},
Result
:
&
uncles
[
i
],
}
}
...
...
@@ -123,6 +125,9 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
if
reqs
[
i
]
.
Error
!=
nil
{
return
nil
,
reqs
[
i
]
.
Error
}
if
uncles
[
i
]
==
nil
{
return
nil
,
fmt
.
Errorf
(
"got null header for uncle %d of block %x"
,
i
,
body
.
Hash
[
:
])
}
}
}
return
types
.
NewBlockWithHeader
(
head
)
.
WithBody
(
body
.
Transactions
,
uncles
),
nil
...
...
@@ -132,6 +137,9 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
func
(
ec
*
Client
)
HeaderByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
types
.
Header
,
error
)
{
var
head
*
types
.
Header
err
:=
ec
.
c
.
CallContext
(
ctx
,
&
head
,
"eth_getBlockByHash"
,
hash
,
false
)
if
err
==
nil
&&
head
==
nil
{
err
=
ethereum
.
NotFound
}
return
head
,
err
}
...
...
@@ -140,19 +148,31 @@ func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.He
func
(
ec
*
Client
)
HeaderByNumber
(
ctx
context
.
Context
,
number
*
big
.
Int
)
(
*
types
.
Header
,
error
)
{
var
head
*
types
.
Header
err
:=
ec
.
c
.
CallContext
(
ctx
,
&
head
,
"eth_getBlockByNumber"
,
toBlockNumArg
(
number
),
false
)
if
err
==
nil
&&
head
==
nil
{
err
=
ethereum
.
NotFound
}
return
head
,
err
}
// TransactionByHash returns the transaction with the given hash.
func
(
ec
*
Client
)
TransactionByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
types
.
Transaction
,
error
)
{
var
tx
*
types
.
Transaction
err
:=
ec
.
c
.
CallContext
(
ctx
,
&
tx
,
"eth_getTransactionByHash"
,
hash
)
if
err
=
=
nil
{
if
_
,
r
,
_
:=
tx
.
RawSignatureValues
();
r
==
nil
{
return
nil
,
fmt
.
Errorf
(
"server returned transaction without signature"
)
}
func
(
ec
*
Client
)
TransactionByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
tx
*
types
.
Transaction
,
isPending
bool
,
err
error
)
{
var
raw
json
.
RawMessage
err
=
ec
.
c
.
CallContext
(
ctx
,
&
raw
,
"eth_getTransactionByHash"
,
hash
)
if
err
!
=
nil
{
return
nil
,
false
,
err
}
else
if
len
(
raw
)
==
0
{
return
nil
,
false
,
ethereum
.
NotFound
}
return
tx
,
err
if
err
:=
json
.
Unmarshal
(
raw
,
tx
);
err
!=
nil
{
return
nil
,
false
,
err
}
else
if
_
,
r
,
_
:=
tx
.
RawSignatureValues
();
r
==
nil
{
return
nil
,
false
,
fmt
.
Errorf
(
"server returned transaction without signature"
)
}
var
block
struct
{
BlockHash
*
common
.
Hash
}
if
err
:=
json
.
Unmarshal
(
raw
,
&
block
);
err
!=
nil
{
return
nil
,
false
,
err
}
return
tx
,
block
.
BlockHash
==
nil
,
nil
}
// TransactionCount returns the total number of transactions in the given block.
...
...
@@ -167,11 +187,9 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
var
tx
*
types
.
Transaction
err
:=
ec
.
c
.
CallContext
(
ctx
,
&
tx
,
"eth_getTransactionByBlockHashAndIndex"
,
blockHash
,
index
)
if
err
==
nil
{
var
signer
types
.
Signer
=
types
.
HomesteadSigner
{}
if
tx
.
Protected
()
{
signer
=
types
.
NewEIP155Signer
(
tx
.
ChainId
())
}
if
_
,
r
,
_
:=
types
.
SignatureValues
(
signer
,
tx
);
r
==
nil
{
if
tx
==
nil
{
return
nil
,
ethereum
.
NotFound
}
else
if
_
,
r
,
_
:=
tx
.
RawSignatureValues
();
r
==
nil
{
return
nil
,
fmt
.
Errorf
(
"server returned transaction without signature"
)
}
}
...
...
@@ -183,8 +201,12 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
func
(
ec
*
Client
)
TransactionReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
var
r
*
types
.
Receipt
err
:=
ec
.
c
.
CallContext
(
ctx
,
&
r
,
"eth_getTransactionReceipt"
,
txHash
)
if
err
==
nil
&&
r
!=
nil
&&
len
(
r
.
PostState
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"server returned receipt without post state"
)
if
err
==
nil
{
if
r
==
nil
{
return
nil
,
ethereum
.
NotFound
}
else
if
len
(
r
.
PostState
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"server returned receipt without post state"
)
}
}
return
r
,
err
}
...
...
@@ -193,7 +215,7 @@ func toBlockNumArg(number *big.Int) string {
if
number
==
nil
{
return
"latest"
}
return
fmt
.
Sprintf
(
"%#x"
,
number
)
return
hexutil
.
EncodeBig
(
number
)
}
type
rpcProgress
struct
{
...
...
ethclient/ethclient_test.go
浏览文件 @
7f79d249
...
...
@@ -21,9 +21,9 @@ import "github.com/ethereum/go-ethereum"
// Verify that Client implements the ethereum interfaces.
var
(
_
=
ethereum
.
ChainReader
(
&
Client
{})
_
=
ethereum
.
TransactionReader
(
&
Client
{})
_
=
ethereum
.
ChainStateReader
(
&
Client
{})
_
=
ethereum
.
ChainSyncReader
(
&
Client
{})
_
=
ethereum
.
ChainHeadEventer
(
&
Client
{})
_
=
ethereum
.
ContractCaller
(
&
Client
{})
_
=
ethereum
.
GasEstimator
(
&
Client
{})
_
=
ethereum
.
GasPricer
(
&
Client
{})
...
...
interfaces.go
浏览文件 @
7f79d249
...
...
@@ -18,6 +18,7 @@
package
ethereum
import
(
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -26,6 +27,9 @@ import (
"golang.org/x/net/context"
)
// NotFound is returned by API methods if the requested item does not exist.
var
NotFound
=
errors
.
New
(
"not found"
)
// TODO: move subscription to package event
// Subscription represents an event subscription where events are
...
...
@@ -46,6 +50,8 @@ type Subscription interface {
// blockchain fork that was previously downloaded and processed by the node. The block
// number argument can be nil to select the latest canonical block. Reading block headers
// should be preferred over full blocks whenever possible.
//
// The returned error is NotFound if the requested item does not exist.
type
ChainReader
interface
{
BlockByHash
(
ctx
context
.
Context
,
hash
common
.
Hash
)
(
*
types
.
Block
,
error
)
BlockByNumber
(
ctx
context
.
Context
,
number
*
big
.
Int
)
(
*
types
.
Block
,
error
)
...
...
@@ -53,7 +59,30 @@ type ChainReader interface {
HeaderByNumber
(
ctx
context
.
Context
,
number
*
big
.
Int
)
(
*
types
.
Header
,
error
)
TransactionCount
(
ctx
context
.
Context
,
blockHash
common
.
Hash
)
(
uint
,
error
)
TransactionInBlock
(
ctx
context
.
Context
,
blockHash
common
.
Hash
,
index
uint
)
(
*
types
.
Transaction
,
error
)
TransactionByHash
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Transaction
,
error
)
// This method subscribes to notifications about changes of the head block of
// the canonical chain.
SubscribeNewHead
(
ctx
context
.
Context
,
ch
chan
<-
*
types
.
Header
)
(
Subscription
,
error
)
}
// TransactionReader provides access to past transactions and their receipts.
// Implementations may impose arbitrary restrictions on the transactions and receipts that
// can be retrieved. Historic transactions may not be available.
//
// Avoid relying on this interface if possible. Contract logs (through the LogFilterer
// interface) are more reliable and usually safer in the presence of chain
// reorganisations.
//
// The returned error is NotFound if the requested item does not exist.
type
TransactionReader
interface
{
// TransactionByHash checks the pool of pending transactions in addition to the
// blockchain. The isPending return value indicates whether the transaction has been
// mined yet. Note that the transaction may not be part of the canonical chain even if
// it's not pending.
TransactionByHash
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
tx
*
types
.
Transaction
,
isPending
bool
,
err
error
)
// TransactionReceipt returns the receipt of a mined transaction. Note that the
// transaction may not be included in the current canonical chain even if a receipt
// exists.
TransactionReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
}
...
...
@@ -83,11 +112,6 @@ type ChainSyncReader interface {
SyncProgress
(
ctx
context
.
Context
)
(
*
SyncProgress
,
error
)
}
// A ChainHeadEventer returns notifications whenever the canonical head block is updated.
type
ChainHeadEventer
interface
{
SubscribeNewHead
(
ctx
context
.
Context
,
ch
chan
<-
*
types
.
Header
)
(
Subscription
,
error
)
}
// CallMsg contains parameters for contract calls.
type
CallMsg
struct
{
From
common
.
Address
// the sender of the 'transaction'
...
...
@@ -128,6 +152,9 @@ type FilterQuery struct {
// LogFilterer provides access to contract log events using a one-off query or continuous
// event subscription.
//
// Logs received through a streaming query subscription may have Removed set to true,
// indicating that the log was reverted due to a chain reorganisation.
type
LogFilterer
interface
{
FilterLogs
(
ctx
context
.
Context
,
q
FilterQuery
)
([]
vm
.
Log
,
error
)
SubscribeFilterLogs
(
ctx
context
.
Context
,
q
FilterQuery
,
ch
chan
<-
vm
.
Log
)
(
Subscription
,
error
)
...
...
mobile/ethclient.go
浏览文件 @
7f79d249
...
...
@@ -73,7 +73,8 @@ func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (*Header
// GetTransactionByHash returns the transaction with the given hash.
func
(
ec
*
EthereumClient
)
GetTransactionByHash
(
ctx
*
Context
,
hash
*
Hash
)
(
*
Transaction
,
error
)
{
tx
,
err
:=
ec
.
client
.
TransactionByHash
(
ctx
.
context
,
hash
.
hash
)
// TODO(karalabe): handle isPending
tx
,
_
,
err
:=
ec
.
client
.
TransactionByHash
(
ctx
.
context
,
hash
.
hash
)
return
&
Transaction
{
tx
},
err
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录