Skip to content

Commit 7f79d24

Browse files
authored
Merge pull request #3402 from fjl/ethclient-api-fixes
eth/filters, ethclient, ethereum: API improvements
2 parents 2dcf75a + f138374 commit 7f79d24

File tree

12 files changed

+327
-190
lines changed

12 files changed

+327
-190
lines changed

core/blockchain.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
988988
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()))
989989
}
990990
blockInsertTimer.UpdateSince(bstart)
991-
events = append(events, ChainSideEvent{block, logs})
991+
events = append(events, ChainSideEvent{block})
992992

993993
case SplitStatTy:
994994
events = append(events, ChainSplitEvent{block, logs})
@@ -1062,24 +1062,25 @@ func countTransactions(chain []*types.Block) (c int) {
10621062
// event about them
10631063
func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
10641064
var (
1065-
newChain types.Blocks
1066-
oldChain types.Blocks
1067-
commonBlock *types.Block
1068-
oldStart = oldBlock
1069-
newStart = newBlock
1070-
deletedTxs types.Transactions
1071-
deletedLogs vm.Logs
1072-
deletedLogsByHash = make(map[common.Hash]vm.Logs)
1065+
newChain types.Blocks
1066+
oldChain types.Blocks
1067+
commonBlock *types.Block
1068+
oldStart = oldBlock
1069+
newStart = newBlock
1070+
deletedTxs types.Transactions
1071+
deletedLogs vm.Logs
10731072
// collectLogs collects the logs that were generated during the
10741073
// processing of the block that corresponds with the given hash.
10751074
// These logs are later announced as deleted.
10761075
collectLogs = func(h common.Hash) {
1077-
// Coalesce logs
1076+
// Coalesce logs and set 'Removed'.
10781077
receipts := GetBlockReceipts(self.chainDb, h, self.hc.GetBlockNumber(h))
10791078
for _, receipt := range receipts {
1080-
deletedLogs = append(deletedLogs, receipt.Logs...)
1081-
1082-
deletedLogsByHash[h] = receipt.Logs
1079+
for _, log := range receipt.Logs {
1080+
del := *log
1081+
del.Removed = true
1082+
deletedLogs = append(deletedLogs, &del)
1083+
}
10831084
}
10841085
}
10851086
)
@@ -1173,7 +1174,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
11731174
if len(oldChain) > 0 {
11741175
go func() {
11751176
for _, block := range oldChain {
1176-
self.eventMux.Post(ChainSideEvent{Block: block, Logs: deletedLogsByHash[block.Hash()]})
1177+
self.eventMux.Post(ChainSideEvent{Block: block})
11771178
}
11781179
}()
11791180
}

core/events.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ type ChainEvent struct {
6161

6262
type ChainSideEvent struct {
6363
Block *types.Block
64-
Logs vm.Logs
6564
}
6665

6766
type PendingBlockEvent struct {

core/vm/log.go

Lines changed: 103 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,42 @@ import (
2929

3030
var errMissingLogFields = errors.New("missing required JSON log fields")
3131

32-
// Log represents a contract log event. These events are generated by the LOG
33-
// opcode and stored/indexed by the node.
32+
// Log represents a contract log event. These events are generated by the LOG opcode and
33+
// stored/indexed by the node.
3434
type Log struct {
3535
// Consensus fields.
3636
Address common.Address // address of the contract that generated the event
3737
Topics []common.Hash // list of topics provided by the contract.
3838
Data []byte // supplied by the contract, usually ABI-encoded
3939

40-
// Derived fields (don't reorder!).
40+
// Derived fields. These fields are filled in by the node
41+
// but not secured by consensus.
4142
BlockNumber uint64 // block in which the transaction was included
4243
TxHash common.Hash // hash of the transaction
4344
TxIndex uint // index of the transaction in the block
4445
BlockHash common.Hash // hash of the block in which the transaction was included
4546
Index uint // index of the log in the receipt
47+
48+
// The Removed field is true if this log was reverted due to a chain reorganisation.
49+
// You must pay attention to this field if you receive logs through a filter query.
50+
Removed bool
51+
}
52+
53+
type rlpLog struct {
54+
Address common.Address
55+
Topics []common.Hash
56+
Data []byte
57+
}
58+
59+
type rlpStorageLog struct {
60+
Address common.Address
61+
Topics []common.Hash
62+
Data []byte
63+
BlockNumber uint64
64+
TxHash common.Hash
65+
TxIndex uint
66+
BlockHash common.Hash
67+
Index uint
4668
}
4769

4870
type jsonLog struct {
@@ -54,73 +76,115 @@ type jsonLog struct {
5476
TxHash *common.Hash `json:"transactionHash"`
5577
BlockHash *common.Hash `json:"blockHash"`
5678
Index *hexutil.Uint `json:"logIndex"`
79+
Removed bool `json:"removed"`
5780
}
5881

5982
func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *Log {
6083
return &Log{Address: address, Topics: topics, Data: data, BlockNumber: number}
6184
}
6285

86+
// EncodeRLP implements rlp.Encoder.
6387
func (l *Log) EncodeRLP(w io.Writer) error {
64-
return rlp.Encode(w, []interface{}{l.Address, l.Topics, l.Data})
88+
return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
6589
}
6690

91+
// DecodeRLP implements rlp.Decoder.
6792
func (l *Log) DecodeRLP(s *rlp.Stream) error {
68-
var log struct {
69-
Address common.Address
70-
Topics []common.Hash
71-
Data []byte
93+
var dec rlpLog
94+
err := s.Decode(&dec)
95+
if err == nil {
96+
l.Address, l.Topics, l.Data = dec.Address, dec.Topics, dec.Data
7297
}
73-
if err := s.Decode(&log); err != nil {
74-
return err
75-
}
76-
l.Address, l.Topics, l.Data = log.Address, log.Topics, log.Data
77-
return nil
98+
return err
7899
}
79100

80101
func (l *Log) String() string {
81102
return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, l.Address, l.Topics, l.Data, l.TxHash, l.TxIndex, l.BlockHash, l.Index)
82103
}
83104

84105
// MarshalJSON implements json.Marshaler.
85-
func (r *Log) MarshalJSON() ([]byte, error) {
86-
return json.Marshal(&jsonLog{
87-
Address: &r.Address,
88-
Topics: &r.Topics,
89-
Data: (*hexutil.Bytes)(&r.Data),
90-
BlockNumber: (*hexutil.Uint64)(&r.BlockNumber),
91-
TxIndex: (*hexutil.Uint)(&r.TxIndex),
92-
TxHash: &r.TxHash,
93-
BlockHash: &r.BlockHash,
94-
Index: (*hexutil.Uint)(&r.Index),
95-
})
106+
func (l *Log) MarshalJSON() ([]byte, error) {
107+
jslog := &jsonLog{
108+
Address: &l.Address,
109+
Topics: &l.Topics,
110+
Data: (*hexutil.Bytes)(&l.Data),
111+
TxIndex: (*hexutil.Uint)(&l.TxIndex),
112+
TxHash: &l.TxHash,
113+
Index: (*hexutil.Uint)(&l.Index),
114+
Removed: l.Removed,
115+
}
116+
// Set block information for mined logs.
117+
if (l.BlockHash != common.Hash{}) {
118+
jslog.BlockHash = &l.BlockHash
119+
jslog.BlockNumber = (*hexutil.Uint64)(&l.BlockNumber)
120+
}
121+
return json.Marshal(jslog)
96122
}
97123

98124
// UnmarshalJSON implements json.Umarshaler.
99-
func (r *Log) UnmarshalJSON(input []byte) error {
125+
func (l *Log) UnmarshalJSON(input []byte) error {
100126
var dec jsonLog
101127
if err := json.Unmarshal(input, &dec); err != nil {
102128
return err
103129
}
104-
if dec.Address == nil || dec.Topics == nil || dec.Data == nil || dec.BlockNumber == nil ||
105-
dec.TxIndex == nil || dec.TxHash == nil || dec.BlockHash == nil || dec.Index == nil {
130+
if dec.Address == nil || dec.Topics == nil || dec.Data == nil ||
131+
dec.TxIndex == nil || dec.TxHash == nil || dec.Index == nil {
106132
return errMissingLogFields
107133
}
108-
*r = Log{
109-
Address: *dec.Address,
110-
Topics: *dec.Topics,
111-
Data: *dec.Data,
112-
BlockNumber: uint64(*dec.BlockNumber),
113-
TxHash: *dec.TxHash,
114-
TxIndex: uint(*dec.TxIndex),
115-
BlockHash: *dec.BlockHash,
116-
Index: uint(*dec.Index),
134+
declog := Log{
135+
Address: *dec.Address,
136+
Topics: *dec.Topics,
137+
Data: *dec.Data,
138+
TxHash: *dec.TxHash,
139+
TxIndex: uint(*dec.TxIndex),
140+
Index: uint(*dec.Index),
141+
Removed: dec.Removed,
142+
}
143+
// Block information may be missing if the log is received through
144+
// the pending log filter, so it's handled specially here.
145+
if dec.BlockHash != nil && dec.BlockNumber != nil {
146+
declog.BlockHash = *dec.BlockHash
147+
declog.BlockNumber = uint64(*dec.BlockNumber)
117148
}
149+
*l = declog
118150
return nil
119151
}
120152

121153
type Logs []*Log
122154

123-
// LogForStorage is a wrapper around a Log that flattens and parses the entire
124-
// content of a log, as opposed to only the consensus fields originally (by hiding
125-
// the rlp interface methods).
155+
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
156+
// a log including non-consensus fields.
126157
type LogForStorage Log
158+
159+
// EncodeRLP implements rlp.Encoder.
160+
func (l *LogForStorage) EncodeRLP(w io.Writer) error {
161+
return rlp.Encode(w, rlpStorageLog{
162+
Address: l.Address,
163+
Topics: l.Topics,
164+
Data: l.Data,
165+
BlockNumber: l.BlockNumber,
166+
TxHash: l.TxHash,
167+
TxIndex: l.TxIndex,
168+
BlockHash: l.BlockHash,
169+
Index: l.Index,
170+
})
171+
}
172+
173+
// DecodeRLP implements rlp.Decoder.
174+
func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error {
175+
var dec rlpStorageLog
176+
err := s.Decode(&dec)
177+
if err == nil {
178+
*l = LogForStorage{
179+
Address: dec.Address,
180+
Topics: dec.Topics,
181+
Data: dec.Data,
182+
BlockNumber: dec.BlockNumber,
183+
TxHash: dec.TxHash,
184+
TxIndex: dec.TxIndex,
185+
BlockHash: dec.BlockHash,
186+
Index: dec.Index,
187+
}
188+
}
189+
return err
190+
}

core/vm/log_test.go

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,81 @@ package vm
1818

1919
import (
2020
"encoding/json"
21+
"reflect"
2122
"testing"
23+
24+
"github.com/davecgh/go-spew/spew"
25+
"github.com/ethereum/go-ethereum/common"
26+
"github.com/ethereum/go-ethereum/common/hexutil"
2227
)
2328

2429
var unmarshalLogTests = map[string]struct {
2530
input string
31+
want *Log
2632
wantError error
2733
}{
2834
"ok": {
29-
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
35+
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
36+
want: &Log{
37+
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
38+
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
39+
BlockNumber: 2019236,
40+
Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000001a055690d9db80000"),
41+
Index: 2,
42+
TxIndex: 3,
43+
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
44+
Topics: []common.Hash{
45+
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
46+
common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"),
47+
},
48+
},
3049
},
3150
"empty data": {
32-
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
51+
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
52+
want: &Log{
53+
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
54+
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
55+
BlockNumber: 2019236,
56+
Data: []byte{},
57+
Index: 2,
58+
TxIndex: 3,
59+
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
60+
Topics: []common.Hash{
61+
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
62+
common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"),
63+
},
64+
},
65+
},
66+
"missing block fields (pending logs)": {
67+
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","data":"0x","logIndex":"0x0","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
68+
want: &Log{
69+
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
70+
BlockHash: common.Hash{},
71+
BlockNumber: 0,
72+
Data: []byte{},
73+
Index: 0,
74+
TxIndex: 3,
75+
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
76+
Topics: []common.Hash{
77+
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
78+
},
79+
},
80+
},
81+
"Removed: true": {
82+
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3","removed":true}`,
83+
want: &Log{
84+
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
85+
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
86+
BlockNumber: 2019236,
87+
Data: []byte{},
88+
Index: 2,
89+
TxIndex: 3,
90+
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
91+
Topics: []common.Hash{
92+
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
93+
},
94+
Removed: true,
95+
},
3396
},
3497
"missing data": {
3598
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 {
38101
}
39102

40103
func TestUnmarshalLog(t *testing.T) {
104+
dumper := spew.ConfigState{DisableMethods: true, Indent: " "}
41105
for name, test := range unmarshalLogTests {
42106
var log *Log
43107
err := json.Unmarshal([]byte(test.input), &log)
44108
checkError(t, name, err, test.wantError)
109+
if test.wantError == nil && err == nil {
110+
if !reflect.DeepEqual(log, test.want) {
111+
t.Errorf("test %q:\nGOT %sWANT %s", name, dumper.Sdump(log), dumper.Sdump(test.want))
112+
}
113+
}
45114
}
46115
}
47116

0 commit comments

Comments
 (0)