consensus: rename (*PeerState).ToJSON to MarshalJSON#524
Merged
mergify[bot] merged 6 commits intocometbft:mainfrom Mar 14, 2023
Merged
consensus: rename (*PeerState).ToJSON to MarshalJSON#524mergify[bot] merged 6 commits intocometbft:mainfrom
mergify[bot] merged 6 commits intocometbft:mainfrom
Conversation
In (*PeerState).PickSendVote, there is a Debug-level log that includes the PeerState value as a logging field. By default, zerolog json-encodes a struct passed as a log field (when the struct doesn't implement zerolog.LogObjectMarshaler). Because PeerState didn't have a MarshalJSON method, the JSON encoder fell back to reflection to encode the PeerState value. Reflection did not acquire the lock, and there were data races resulting from an unsynchronized read while logging the PeerState, and concurrent (locked) writes at least during (*PeerState).SetHasProposal and (*PeerState).SetHasVote. Given that there was only one call to (*PeerState).ToJSON in the cometbft repo, it seemed appropriate to just rename ToJSON to MarshalJSON, as opposed to leaving ToJSON for backwards compatibility. Any third party calls to ToJSON should be able to easily change the method being called.
cason
approved these changes
Mar 14, 2023
cason
left a comment
There was a problem hiding this comment.
Great find.
It appears that the renamed method is not used anywhere else, except in the RPC code addressed by this PR. So I would say that is not a breaking change.
Contributor
Author
thanethomson
approved these changes
Mar 14, 2023
Contributor
thanethomson
left a comment
There was a problem hiding this comment.
Thanks for this @mark-rushakoff! I'd say that this should probably be safe to backport to v0.37 and v0.34, given the scope of the change. If folks complain about it, we could always introduce a shim ToJSON method that just implicitly calls MarshalJSON.
mergify bot
pushed a commit
that referenced
this pull request
Mar 14, 2023
In (*PeerState).PickSendVote, there is a Debug-level log that includes the PeerState value as a logging field. By default, zerolog json-encodes a struct passed as a log field (when the struct doesn't implement zerolog.LogObjectMarshaler).
Because PeerState didn't have a MarshalJSON method, the JSON encoder fell back to reflection to encode the PeerState value. Reflection did not acquire the lock, and there were data races resulting from an unsynchronized read while logging the PeerState, and concurrent (locked) writes at least during (*PeerState).SetHasProposal and (*PeerState).SetHasVote.
Given that there was only one call to (*PeerState).ToJSON in the cometbft repo, it seemed appropriate to just rename ToJSON to MarshalJSON, as opposed to leaving ToJSON for backwards compatibility. Any third party calls to ToJSON should be able to easily change the method being called.
Example data race (which is no longer reproducible with this change):
```
==================
WARNING: DATA RACE
Read at 0x00c0004a4870 by goroutine 131:
reflect.Value.Bool()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/reflect/value.go:288 +0x7c
encoding/json.boolEncoder()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:539 +0x88
encoding/json.structEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc
encoding/json.structEncoder.encode-fm()
<autogenerated>:1 +0x94
encoding/json.structEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc
encoding/json.structEncoder.encode-fm()
<autogenerated>:1 +0x94
encoding/json.ptrEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:943 +0x2a4
encoding/json.ptrEncoder.encode-fm()
<autogenerated>:1 +0x6c
encoding/json.(*encodeState).reflectValue()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:358 +0x74
encoding/json.(*encodeState).marshal()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:330 +0x1a0
encoding/json.Marshal()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:161 +0xa0
github.com/rs/zerolog.init.1.func1()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/encoder_json.go:21 +0x4c
github.com/rs/zerolog/internal/json.Encoder.AppendInterface()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/internal/json/types.go:366 +0x5c
github.com/rs/zerolog.appendFieldList()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:273 +0x2b8c
github.com/rs/zerolog.appendFields()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:21 +0x160
github.com/rs/zerolog.(*Event).Fields()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/event.go:165 +0x90
cosmossdk.io/log.zeroLogWrapper.Debug()
/Users/hh/go/pkg/mod/cosmossdk.io/log@v0.0.0-20230313123454-0fe816b71a62/logger.go:89 +0x18
github.com/cosmos/cosmos-sdk/server/log.(*CometZeroLogWrapper).Debug()
<autogenerated>:1 +0x74
github.com/cometbft/cometbft/consensus.(*PeerState).PickSendVote()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1138 +0x1bc
github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesForHeight()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:794 +0x260
github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:724 +0x2cc
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func2()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x58
Previous write at 0x00c0004a4870 by goroutine 130:
github.com/cometbft/cometbft/consensus.(*PeerState).SetHasProposal()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1096 +0x118
github.com/cometbft/cometbft/consensus.(*Reactor).gossipDataRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:617 +0xab8
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x58
Goroutine 131 (running) created at:
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x240
github.com/cometbft/cometbft/p2p.(*Switch).addPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4
github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704
github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34
Goroutine 130 (running) created at:
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x164
github.com/cometbft/cometbft/p2p.(*Switch).addPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4
github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704
github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34
==================
```
---
#### PR checklist
- [ ] Tests written/updated
- [x] Changelog entry added in `.changelog` (we use [unclog](https://github.com/informalsystems/unclog) to manage our changelog)
- [ ] Updated relevant documentation (`docs/` or `spec/`) and code comments
(cherry picked from commit 587bc0b)
mergify bot
pushed a commit
that referenced
this pull request
Mar 14, 2023
In (*PeerState).PickSendVote, there is a Debug-level log that includes the PeerState value as a logging field. By default, zerolog json-encodes a struct passed as a log field (when the struct doesn't implement zerolog.LogObjectMarshaler).
Because PeerState didn't have a MarshalJSON method, the JSON encoder fell back to reflection to encode the PeerState value. Reflection did not acquire the lock, and there were data races resulting from an unsynchronized read while logging the PeerState, and concurrent (locked) writes at least during (*PeerState).SetHasProposal and (*PeerState).SetHasVote.
Given that there was only one call to (*PeerState).ToJSON in the cometbft repo, it seemed appropriate to just rename ToJSON to MarshalJSON, as opposed to leaving ToJSON for backwards compatibility. Any third party calls to ToJSON should be able to easily change the method being called.
Example data race (which is no longer reproducible with this change):
```
==================
WARNING: DATA RACE
Read at 0x00c0004a4870 by goroutine 131:
reflect.Value.Bool()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/reflect/value.go:288 +0x7c
encoding/json.boolEncoder()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:539 +0x88
encoding/json.structEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc
encoding/json.structEncoder.encode-fm()
<autogenerated>:1 +0x94
encoding/json.structEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc
encoding/json.structEncoder.encode-fm()
<autogenerated>:1 +0x94
encoding/json.ptrEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:943 +0x2a4
encoding/json.ptrEncoder.encode-fm()
<autogenerated>:1 +0x6c
encoding/json.(*encodeState).reflectValue()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:358 +0x74
encoding/json.(*encodeState).marshal()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:330 +0x1a0
encoding/json.Marshal()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:161 +0xa0
github.com/rs/zerolog.init.1.func1()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/encoder_json.go:21 +0x4c
github.com/rs/zerolog/internal/json.Encoder.AppendInterface()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/internal/json/types.go:366 +0x5c
github.com/rs/zerolog.appendFieldList()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:273 +0x2b8c
github.com/rs/zerolog.appendFields()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:21 +0x160
github.com/rs/zerolog.(*Event).Fields()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/event.go:165 +0x90
cosmossdk.io/log.zeroLogWrapper.Debug()
/Users/hh/go/pkg/mod/cosmossdk.io/log@v0.0.0-20230313123454-0fe816b71a62/logger.go:89 +0x18
github.com/cosmos/cosmos-sdk/server/log.(*CometZeroLogWrapper).Debug()
<autogenerated>:1 +0x74
github.com/cometbft/cometbft/consensus.(*PeerState).PickSendVote()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1138 +0x1bc
github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesForHeight()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:794 +0x260
github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:724 +0x2cc
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func2()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x58
Previous write at 0x00c0004a4870 by goroutine 130:
github.com/cometbft/cometbft/consensus.(*PeerState).SetHasProposal()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1096 +0x118
github.com/cometbft/cometbft/consensus.(*Reactor).gossipDataRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:617 +0xab8
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x58
Goroutine 131 (running) created at:
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x240
github.com/cometbft/cometbft/p2p.(*Switch).addPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4
github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704
github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34
Goroutine 130 (running) created at:
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x164
github.com/cometbft/cometbft/p2p.(*Switch).addPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4
github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704
github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34
==================
```
---
#### PR checklist
- [ ] Tests written/updated
- [x] Changelog entry added in `.changelog` (we use [unclog](https://github.com/informalsystems/unclog) to manage our changelog)
- [ ] Updated relevant documentation (`docs/` or `spec/`) and code comments
(cherry picked from commit 587bc0b)
# Conflicts:
# .changelog/v0.37.0/bug-fixes/524-rename-peerstate-tojson.md
This was referenced Mar 14, 2023
thanethomson
added a commit
that referenced
this pull request
Mar 15, 2023
…532) * consensus: rename (*PeerState).ToJSON to MarshalJSON (#524) In (*PeerState).PickSendVote, there is a Debug-level log that includes the PeerState value as a logging field. By default, zerolog json-encodes a struct passed as a log field (when the struct doesn't implement zerolog.LogObjectMarshaler). Because PeerState didn't have a MarshalJSON method, the JSON encoder fell back to reflection to encode the PeerState value. Reflection did not acquire the lock, and there were data races resulting from an unsynchronized read while logging the PeerState, and concurrent (locked) writes at least during (*PeerState).SetHasProposal and (*PeerState).SetHasVote. Given that there was only one call to (*PeerState).ToJSON in the cometbft repo, it seemed appropriate to just rename ToJSON to MarshalJSON, as opposed to leaving ToJSON for backwards compatibility. Any third party calls to ToJSON should be able to easily change the method being called. Example data race (which is no longer reproducible with this change): ``` ================== WARNING: DATA RACE Read at 0x00c0004a4870 by goroutine 131: reflect.Value.Bool() /opt/homebrew/Cellar/go/1.20.1/libexec/src/reflect/value.go:288 +0x7c encoding/json.boolEncoder() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:539 +0x88 encoding/json.structEncoder.encode() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc encoding/json.structEncoder.encode-fm() <autogenerated>:1 +0x94 encoding/json.structEncoder.encode() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc encoding/json.structEncoder.encode-fm() <autogenerated>:1 +0x94 encoding/json.ptrEncoder.encode() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:943 +0x2a4 encoding/json.ptrEncoder.encode-fm() <autogenerated>:1 +0x6c encoding/json.(*encodeState).reflectValue() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:358 +0x74 encoding/json.(*encodeState).marshal() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:330 +0x1a0 encoding/json.Marshal() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:161 +0xa0 github.com/rs/zerolog.init.1.func1() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/encoder_json.go:21 +0x4c github.com/rs/zerolog/internal/json.Encoder.AppendInterface() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/internal/json/types.go:366 +0x5c github.com/rs/zerolog.appendFieldList() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:273 +0x2b8c github.com/rs/zerolog.appendFields() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:21 +0x160 github.com/rs/zerolog.(*Event).Fields() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/event.go:165 +0x90 cosmossdk.io/log.zeroLogWrapper.Debug() /Users/hh/go/pkg/mod/cosmossdk.io/log@v0.0.0-20230313123454-0fe816b71a62/logger.go:89 +0x18 github.com/cosmos/cosmos-sdk/server/log.(*CometZeroLogWrapper).Debug() <autogenerated>:1 +0x74 github.com/cometbft/cometbft/consensus.(*PeerState).PickSendVote() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1138 +0x1bc github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesForHeight() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:794 +0x260 github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesRoutine() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:724 +0x2cc github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func2() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x58 Previous write at 0x00c0004a4870 by goroutine 130: github.com/cometbft/cometbft/consensus.(*PeerState).SetHasProposal() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1096 +0x118 github.com/cometbft/cometbft/consensus.(*Reactor).gossipDataRoutine() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:617 +0xab8 github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func1() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x58 Goroutine 131 (running) created at: github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x240 github.com/cometbft/cometbft/p2p.(*Switch).addPeer() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4 github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704 github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34 Goroutine 130 (running) created at: github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x164 github.com/cometbft/cometbft/p2p.(*Switch).addPeer() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4 github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704 github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34 ================== ``` --- #### PR checklist - [ ] Tests written/updated - [x] Changelog entry added in `.changelog` (we use [unclog](https://github.com/informalsystems/unclog) to manage our changelog) - [ ] Updated relevant documentation (`docs/` or `spec/`) and code comments (cherry picked from commit 587bc0b) # Conflicts: # .changelog/v0.37.0/bug-fixes/524-rename-peerstate-tojson.md * Move changelog entry to correct folder Signed-off-by: Thane Thomson <connect@thanethomson.com> --------- Signed-off-by: Thane Thomson <connect@thanethomson.com> Co-authored-by: Mark Rushakoff <mark.rushakoff@gmail.com> Co-authored-by: Thane Thomson <connect@thanethomson.com>
thanethomson
added a commit
that referenced
this pull request
Mar 16, 2023
In (*PeerState).PickSendVote, there is a Debug-level log that includes the PeerState value as a logging field. By default, zerolog json-encodes a struct passed as a log field (when the struct doesn't implement zerolog.LogObjectMarshaler).
Because PeerState didn't have a MarshalJSON method, the JSON encoder fell back to reflection to encode the PeerState value. Reflection did not acquire the lock, and there were data races resulting from an unsynchronized read while logging the PeerState, and concurrent (locked) writes at least during (*PeerState).SetHasProposal and (*PeerState).SetHasVote.
Given that there was only one call to (*PeerState).ToJSON in the cometbft repo, it seemed appropriate to just rename ToJSON to MarshalJSON, as opposed to leaving ToJSON for backwards compatibility. Any third party calls to ToJSON should be able to easily change the method being called.
Example data race (which is no longer reproducible with this change):
```
==================
WARNING: DATA RACE
Read at 0x00c0004a4870 by goroutine 131:
reflect.Value.Bool()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/reflect/value.go:288 +0x7c
encoding/json.boolEncoder()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:539 +0x88
encoding/json.structEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc
encoding/json.structEncoder.encode-fm()
<autogenerated>:1 +0x94
encoding/json.structEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc
encoding/json.structEncoder.encode-fm()
<autogenerated>:1 +0x94
encoding/json.ptrEncoder.encode()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:943 +0x2a4
encoding/json.ptrEncoder.encode-fm()
<autogenerated>:1 +0x6c
encoding/json.(*encodeState).reflectValue()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:358 +0x74
encoding/json.(*encodeState).marshal()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:330 +0x1a0
encoding/json.Marshal()
/opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:161 +0xa0
github.com/rs/zerolog.init.1.func1()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/encoder_json.go:21 +0x4c
github.com/rs/zerolog/internal/json.Encoder.AppendInterface()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/internal/json/types.go:366 +0x5c
github.com/rs/zerolog.appendFieldList()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:273 +0x2b8c
github.com/rs/zerolog.appendFields()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:21 +0x160
github.com/rs/zerolog.(*Event).Fields()
/Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/event.go:165 +0x90
cosmossdk.io/log.zeroLogWrapper.Debug()
/Users/hh/go/pkg/mod/cosmossdk.io/log@v0.0.0-20230313123454-0fe816b71a62/logger.go:89 +0x18
github.com/cosmos/cosmos-sdk/server/log.(*CometZeroLogWrapper).Debug()
<autogenerated>:1 +0x74
github.com/cometbft/cometbft/consensus.(*PeerState).PickSendVote()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1138 +0x1bc
github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesForHeight()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:794 +0x260
github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:724 +0x2cc
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func2()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x58
Previous write at 0x00c0004a4870 by goroutine 130:
github.com/cometbft/cometbft/consensus.(*PeerState).SetHasProposal()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1096 +0x118
github.com/cometbft/cometbft/consensus.(*Reactor).gossipDataRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:617 +0xab8
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x58
Goroutine 131 (running) created at:
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x240
github.com/cometbft/cometbft/p2p.(*Switch).addPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4
github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704
github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34
Goroutine 130 (running) created at:
github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x164
github.com/cometbft/cometbft/p2p.(*Switch).addPeer()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4
github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704
github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1()
/Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34
==================
```
---
#### PR checklist
- [ ] Tests written/updated
- [x] Changelog entry added in `.changelog` (we use [unclog](https://github.com/informalsystems/unclog) to manage our changelog)
- [ ] Updated relevant documentation (`docs/` or `spec/`) and code comments
(cherry picked from commit 587bc0b)
Co-authored-by: Mark Rushakoff <mark.rushakoff@gmail.com>
Co-authored-by: Thane Thomson <connect@thanethomson.com>
|
Hey, this fix potentially introduced this problem: #865 |
3 tasks
roy-dydx
pushed a commit
to dydxprotocol/cometbft
that referenced
this pull request
Jul 11, 2023
…ft#524) (cometbft#532) * consensus: rename (*PeerState).ToJSON to MarshalJSON (cometbft#524) In (*PeerState).PickSendVote, there is a Debug-level log that includes the PeerState value as a logging field. By default, zerolog json-encodes a struct passed as a log field (when the struct doesn't implement zerolog.LogObjectMarshaler). Because PeerState didn't have a MarshalJSON method, the JSON encoder fell back to reflection to encode the PeerState value. Reflection did not acquire the lock, and there were data races resulting from an unsynchronized read while logging the PeerState, and concurrent (locked) writes at least during (*PeerState).SetHasProposal and (*PeerState).SetHasVote. Given that there was only one call to (*PeerState).ToJSON in the cometbft repo, it seemed appropriate to just rename ToJSON to MarshalJSON, as opposed to leaving ToJSON for backwards compatibility. Any third party calls to ToJSON should be able to easily change the method being called. Example data race (which is no longer reproducible with this change): ``` ================== WARNING: DATA RACE Read at 0x00c0004a4870 by goroutine 131: reflect.Value.Bool() /opt/homebrew/Cellar/go/1.20.1/libexec/src/reflect/value.go:288 +0x7c encoding/json.boolEncoder() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:539 +0x88 encoding/json.structEncoder.encode() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc encoding/json.structEncoder.encode-fm() <autogenerated>:1 +0x94 encoding/json.structEncoder.encode() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:759 +0x1bc encoding/json.structEncoder.encode-fm() <autogenerated>:1 +0x94 encoding/json.ptrEncoder.encode() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:943 +0x2a4 encoding/json.ptrEncoder.encode-fm() <autogenerated>:1 +0x6c encoding/json.(*encodeState).reflectValue() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:358 +0x74 encoding/json.(*encodeState).marshal() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:330 +0x1a0 encoding/json.Marshal() /opt/homebrew/Cellar/go/1.20.1/libexec/src/encoding/json/encode.go:161 +0xa0 github.com/rs/zerolog.init.1.func1() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/encoder_json.go:21 +0x4c github.com/rs/zerolog/internal/json.Encoder.AppendInterface() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/internal/json/types.go:366 +0x5c github.com/rs/zerolog.appendFieldList() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:273 +0x2b8c github.com/rs/zerolog.appendFields() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/fields.go:21 +0x160 github.com/rs/zerolog.(*Event).Fields() /Users/hh/go/pkg/mod/github.com/rs/zerolog@v1.29.0/event.go:165 +0x90 cosmossdk.io/log.zeroLogWrapper.Debug() /Users/hh/go/pkg/mod/cosmossdk.io/log@v0.0.0-20230313123454-0fe816b71a62/logger.go:89 +0x18 github.com/cosmos/cosmos-sdk/server/log.(*CometZeroLogWrapper).Debug() <autogenerated>:1 +0x74 github.com/cometbft/cometbft/consensus.(*PeerState).PickSendVote() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1138 +0x1bc github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesForHeight() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:794 +0x260 github.com/cometbft/cometbft/consensus.(*Reactor).gossipVotesRoutine() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:724 +0x2cc github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func2() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x58 Previous write at 0x00c0004a4870 by goroutine 130: github.com/cometbft/cometbft/consensus.(*PeerState).SetHasProposal() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:1096 +0x118 github.com/cometbft/cometbft/consensus.(*Reactor).gossipDataRoutine() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:617 +0xab8 github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer.func1() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x58 Goroutine 131 (running) created at: github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:199 +0x240 github.com/cometbft/cometbft/p2p.(*Switch).addPeer() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4 github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704 github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34 Goroutine 130 (running) created at: github.com/cometbft/cometbft/consensus.(*Reactor).AddPeer() /Users/hh/go/src/github.com/cometbft/cometbft/consensus/reactor.go:198 +0x164 github.com/cometbft/cometbft/p2p.(*Switch).addPeer() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:855 +0x7b4 github.com/cometbft/cometbft/p2p.(*Switch).acceptRoutine() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:707 +0x704 github.com/cometbft/cometbft/p2p.(*Switch).OnStart.func1() /Users/hh/go/src/github.com/cometbft/cometbft/p2p/switch.go:241 +0x34 ================== ``` --- #### PR checklist - [ ] Tests written/updated - [x] Changelog entry added in `.changelog` (we use [unclog](https://github.com/informalsystems/unclog) to manage our changelog) - [ ] Updated relevant documentation (`docs/` or `spec/`) and code comments (cherry picked from commit 587bc0b) # Conflicts: # .changelog/v0.37.0/bug-fixes/524-rename-peerstate-tojson.md * Move changelog entry to correct folder Signed-off-by: Thane Thomson <connect@thanethomson.com> --------- Signed-off-by: Thane Thomson <connect@thanethomson.com> Co-authored-by: Mark Rushakoff <mark.rushakoff@gmail.com> Co-authored-by: Thane Thomson <connect@thanethomson.com>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
In (*PeerState).PickSendVote, there is a Debug-level log that includes the PeerState value as a logging field. By default, zerolog json-encodes a struct passed as a log field (when the struct doesn't implement zerolog.LogObjectMarshaler).
Because PeerState didn't have a MarshalJSON method, the JSON encoder fell back to reflection to encode the PeerState value. Reflection did not acquire the lock, and there were data races resulting from an unsynchronized read while logging the PeerState, and concurrent (locked) writes at least during (*PeerState).SetHasProposal and (*PeerState).SetHasVote.
Given that there was only one call to (*PeerState).ToJSON in the cometbft repo, it seemed appropriate to just rename ToJSON to MarshalJSON, as opposed to leaving ToJSON for backwards compatibility. Any third party calls to ToJSON should be able to easily change the method being called.
Example data race (which is no longer reproducible with this change):
PR checklist
.changelog(we use unclog to manage our changelog)docs/orspec/) and code comments