mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-18 21:01:38 +00:00
eth/protocols/eth: add lock protection
This commit is contained in:
parent
74dd001911
commit
b2490e3f20
4 changed files with 43 additions and 26 deletions
|
|
@ -219,7 +219,9 @@ func (p *Peer) dispatcher() {
|
||||||
delete(pending, cancelOp.id)
|
delete(pending, cancelOp.id)
|
||||||
|
|
||||||
// Not sure if the request is about the receipt, but remove it anyway
|
// Not sure if the request is about the receipt, but remove it anyway
|
||||||
|
p.receiptBufferLock.Lock()
|
||||||
delete(p.receiptBuffer, cancelOp.id)
|
delete(p.receiptBuffer, cancelOp.id)
|
||||||
|
p.receiptBufferLock.Unlock()
|
||||||
|
|
||||||
cancelOp.fail <- nil
|
cancelOp.fail <- nil
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -526,20 +526,17 @@ func handleReceipts70(backend Backend, msg Decoder, peer *Peer) error {
|
||||||
if err := msg.Decode(res); err != nil {
|
if err := msg.Decode(res); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := peer.bufferReceiptsPacket(res, backend); err != nil {
|
if err := peer.bufferReceiptsPacket(res, backend); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if res.LastBlockIncomplete {
|
if res.LastBlockIncomplete {
|
||||||
return peer.requestPartialReceipts(res.RequestId)
|
return peer.requestPartialReceipts(res.RequestId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign buffers shared between list elements
|
// Assign buffers shared between list elements
|
||||||
buffers := new(receiptListBuffers)
|
buffers := new(receiptListBuffers)
|
||||||
for i := range res.List {
|
for i := range res.List {
|
||||||
res.List[i].setBuffers(buffers)
|
res.List[i].setBuffers(buffers)
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := func() interface{} {
|
metadata := func() interface{} {
|
||||||
hasher := trie.NewStackTrie(nil)
|
hasher := trie.NewStackTrie(nil)
|
||||||
hashes := make([]common.Hash, len(res.List))
|
hashes := make([]common.Hash, len(res.List))
|
||||||
|
|
@ -548,12 +545,10 @@ func handleReceipts70(backend Backend, msg Decoder, peer *Peer) error {
|
||||||
}
|
}
|
||||||
return hashes
|
return hashes
|
||||||
}
|
}
|
||||||
|
|
||||||
var enc ReceiptsRLPResponse
|
var enc ReceiptsRLPResponse
|
||||||
for i := range res.List {
|
for i := range res.List {
|
||||||
enc = append(enc, res.List[i].EncodeForStorage())
|
enc = append(enc, res.List[i].EncodeForStorage())
|
||||||
}
|
}
|
||||||
|
|
||||||
return peer.dispatchResponse(&Response{
|
return peer.dispatchResponse(&Response{
|
||||||
id: res.RequestId,
|
id: res.RequestId,
|
||||||
code: ReceiptsMsg,
|
code: ReceiptsMsg,
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
mapset "github.com/deckarep/golang-set/v2"
|
mapset "github.com/deckarep/golang-set/v2"
|
||||||
|
|
@ -43,8 +45,9 @@ const (
|
||||||
maxQueuedTxAnns = 4096
|
maxQueuedTxAnns = 4096
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// receiptRequest tracks the state of an in-flight receipt retrieval operation.
|
||||||
type receiptRequest struct {
|
type receiptRequest struct {
|
||||||
request []common.Hash
|
request []common.Hash // block hashes corresponding to the requested receipts
|
||||||
list []*ReceiptList69 // list of partially collected receipts
|
list []*ReceiptList69 // list of partially collected receipts
|
||||||
lastLogSize uint64 // log size of last receipt list
|
lastLogSize uint64 // log size of last receipt list
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +70,8 @@ type Peer struct {
|
||||||
reqCancel chan *cancel // Dispatch channel to cancel pending requests and untrack them
|
reqCancel chan *cancel // Dispatch channel to cancel pending requests and untrack them
|
||||||
resDispatch chan *response // Dispatch channel to fulfil pending requests and untrack them
|
resDispatch chan *response // Dispatch channel to fulfil pending requests and untrack them
|
||||||
|
|
||||||
receiptBuffer map[uint64]*receiptRequest // Previously requested receipts to buffer partial receipts
|
receiptBuffer map[uint64]*receiptRequest // Previously requested receipts to buffer partial receipts
|
||||||
|
receiptBufferLock sync.RWMutex // Lock for protecting the receiptBuffer
|
||||||
|
|
||||||
term chan struct{} // Termination channel to stop the broadcasters
|
term chan struct{} // Termination channel to stop the broadcasters
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +222,7 @@ func (p *Peer) ReplyBlockBodiesRLP(id uint64, bodies []rlp.RawValue) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplyReceiptsRLP is the response to GetReceipts.
|
// ReplyReceiptsRLP69 is the response to GetReceipts.
|
||||||
func (p *Peer) ReplyReceiptsRLP69(id uint64, receipts []rlp.RawValue) error {
|
func (p *Peer) ReplyReceiptsRLP69(id uint64, receipts []rlp.RawValue) error {
|
||||||
return p2p.Send(p.rw, ReceiptsMsg, &ReceiptsRLPPacket69{
|
return p2p.Send(p.rw, ReceiptsMsg, &ReceiptsRLPPacket69{
|
||||||
RequestId: id,
|
RequestId: id,
|
||||||
|
|
@ -226,7 +230,7 @@ func (p *Peer) ReplyReceiptsRLP69(id uint64, receipts []rlp.RawValue) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplyReceiptsRLP is the response to GetReceipts.
|
// ReplyReceiptsRLP70 is the response to GetReceipts.
|
||||||
func (p *Peer) ReplyReceiptsRLP70(id uint64, receipts []rlp.RawValue, lastBlockIncomplete bool) error {
|
func (p *Peer) ReplyReceiptsRLP70(id uint64, receipts []rlp.RawValue, lastBlockIncomplete bool) error {
|
||||||
return p2p.Send(p.rw, ReceiptsMsg, &ReceiptsRLPPacket70{
|
return p2p.Send(p.rw, ReceiptsMsg, &ReceiptsRLPPacket70{
|
||||||
RequestId: id,
|
RequestId: id,
|
||||||
|
|
@ -356,7 +360,11 @@ func (p *Peer) RequestReceipts(hashes []common.Hash, sink chan *Response) (*Requ
|
||||||
FirstBlockReceiptIndex: 0,
|
FirstBlockReceiptIndex: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
p.receiptBuffer[id] = &receiptRequest{request: hashes}
|
p.receiptBufferLock.Lock()
|
||||||
|
p.receiptBuffer[id] = &receiptRequest{
|
||||||
|
request: hashes,
|
||||||
|
}
|
||||||
|
p.receiptBufferLock.Unlock()
|
||||||
} else {
|
} else {
|
||||||
req = &Request{
|
req = &Request{
|
||||||
id: id,
|
id: id,
|
||||||
|
|
@ -372,16 +380,17 @@ func (p *Peer) RequestReceipts(hashes []common.Hash, sink chan *Response) (*Requ
|
||||||
if err := p.dispatchRequest(req); err != nil {
|
if err := p.dispatchRequest(req); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandlePartialReceipts re-request partial receipts
|
// HandlePartialReceipts re-request partial receipts
|
||||||
func (p *Peer) requestPartialReceipts(id uint64) error {
|
func (p *Peer) requestPartialReceipts(id uint64) error {
|
||||||
if _, ok := p.receiptBuffer[id]; !ok {
|
p.receiptBufferLock.RLock()
|
||||||
return fmt.Errorf("No partial receipt retreival in progress with id %d", id)
|
defer p.receiptBufferLock.RUnlock()
|
||||||
}
|
|
||||||
|
|
||||||
|
if _, ok := p.receiptBuffer[id]; !ok {
|
||||||
|
return fmt.Errorf("no partial receipt retreival in progress with id %d", id)
|
||||||
|
}
|
||||||
lastBlock := len(p.receiptBuffer[id].list) - 1
|
lastBlock := len(p.receiptBuffer[id].list) - 1
|
||||||
lastReceipt := len(p.receiptBuffer[id].list[lastBlock].items)
|
lastReceipt := len(p.receiptBuffer[id].list[lastBlock].items)
|
||||||
|
|
||||||
|
|
@ -396,26 +405,33 @@ func (p *Peer) requestPartialReceipts(id uint64) error {
|
||||||
FirstBlockReceiptIndex: uint64(lastReceipt),
|
FirstBlockReceiptIndex: uint64(lastReceipt),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.dispatchRequest(req)
|
return p.dispatchRequest(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bufferReceiptsPacket validates a receipt packet and buffer the incomplete packet.
|
// bufferReceiptsPacket validates a receipt packet and buffer the incomplete packet.
|
||||||
// If the request is completed, it appends previously collected receipts.
|
// If the request is completed, it appends previously collected receipts.
|
||||||
func (p *Peer) bufferReceiptsPacket(packet *ReceiptsPacket70, backend Backend) error {
|
func (p *Peer) bufferReceiptsPacket(packet *ReceiptsPacket70, backend Backend) error {
|
||||||
|
p.receiptBufferLock.Lock()
|
||||||
|
defer p.receiptBufferLock.Unlock()
|
||||||
|
|
||||||
requestId := packet.RequestId
|
requestId := packet.RequestId
|
||||||
buffer := p.receiptBuffer[requestId]
|
buffer := p.receiptBuffer[requestId]
|
||||||
|
|
||||||
// Do not assign buffer to the response not requested
|
// Do not assign buffer to the response not requested
|
||||||
if buffer == nil {
|
if buffer == nil {
|
||||||
return fmt.Errorf("No partial receipt retreival in progress with id %d", requestId)
|
return fmt.Errorf("no partial receipt retreival in progress with id %d", requestId)
|
||||||
}
|
}
|
||||||
|
// If the response is empty, the peer likely does not have the requested receipts.
|
||||||
|
// Forward the empty response to the internal handler regardless. However, note
|
||||||
|
// that an empty response marked as incomplete is considered invalid.
|
||||||
if len(packet.List) == 0 {
|
if len(packet.List) == 0 {
|
||||||
delete(p.receiptBuffer, requestId)
|
delete(p.receiptBuffer, requestId)
|
||||||
|
|
||||||
|
if packet.LastBlockIncomplete {
|
||||||
|
return errors.New("invalid empty receipt response with incomplete flag")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer the last block when the response is incomplete.
|
// Buffer the last block when the response is incomplete.
|
||||||
if packet.LastBlockIncomplete {
|
if packet.LastBlockIncomplete {
|
||||||
lastBlock := len(packet.List) - 1
|
lastBlock := len(packet.List) - 1
|
||||||
|
|
@ -423,15 +439,17 @@ func (p *Peer) bufferReceiptsPacket(packet *ReceiptsPacket70, backend Backend) e
|
||||||
lastBlock += len(buffer.list) - 1
|
lastBlock += len(buffer.list) - 1
|
||||||
}
|
}
|
||||||
header := backend.Chain().GetHeaderByHash(buffer.request[lastBlock])
|
header := backend.Chain().GetHeaderByHash(buffer.request[lastBlock])
|
||||||
|
if header == nil {
|
||||||
|
return fmt.Errorf("unknown block #%d for receipt retrieval", lastBlock)
|
||||||
|
}
|
||||||
logSize, err := p.validateLastBlockReceipt(packet.List, requestId, header)
|
logSize, err := p.validateLastBlockReceipt(packet.List, requestId, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the buffered data and trim the packet to exclude the incomplete block.
|
// Update the buffered data and trim the packet to exclude the incomplete block.
|
||||||
if len(buffer.list) > 0 {
|
if len(buffer.list) > 0 {
|
||||||
// If the buffer is already allocated, it means that the previous response was incomplete
|
// If the buffer is already allocated, it means that the previous response
|
||||||
// Append the first block receipts
|
// was incomplete Append the first block receipts.
|
||||||
buffer.list[len(buffer.list)-1].Append(packet.List[0])
|
buffer.list[len(buffer.list)-1].Append(packet.List[0])
|
||||||
buffer.list = append(buffer.list, packet.List[1:]...)
|
buffer.list = append(buffer.list, packet.List[1:]...)
|
||||||
buffer.lastLogSize = logSize
|
buffer.lastLogSize = logSize
|
||||||
|
|
@ -441,7 +459,6 @@ func (p *Peer) bufferReceiptsPacket(packet *ReceiptsPacket70, backend Backend) e
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the request is completed, append previously collected receipts
|
// If the request is completed, append previously collected receipts
|
||||||
// to the packet and remove the buffered receipts.
|
// to the packet and remove the buffered receipts.
|
||||||
if len(buffer.list) > 0 {
|
if len(buffer.list) > 0 {
|
||||||
|
|
@ -449,8 +466,8 @@ func (p *Peer) bufferReceiptsPacket(packet *ReceiptsPacket70, backend Backend) e
|
||||||
packet.List = packet.List[1:]
|
packet.List = packet.List[1:]
|
||||||
}
|
}
|
||||||
packet.List = append(buffer.list, packet.List...)
|
packet.List = append(buffer.list, packet.List...)
|
||||||
delete(p.receiptBuffer, requestId)
|
|
||||||
|
|
||||||
|
delete(p.receiptBuffer, requestId)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -259,13 +259,14 @@ func (p *BlockBodiesResponse) Unpack() ([][]*types.Transaction, [][]*types.Heade
|
||||||
// GetReceiptsRequest represents a block receipts query.
|
// GetReceiptsRequest represents a block receipts query.
|
||||||
type GetReceiptsRequest []common.Hash
|
type GetReceiptsRequest []common.Hash
|
||||||
|
|
||||||
// GetReceiptsPacket represents a block receipts query with request ID wrapping.
|
// GetReceiptsPacket69 represents a block receipts query with request ID wrapping.
|
||||||
type GetReceiptsPacket69 struct {
|
type GetReceiptsPacket69 struct {
|
||||||
RequestId uint64
|
RequestId uint64
|
||||||
GetReceiptsRequest
|
GetReceiptsRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReceiptsPacket represents a block receipts query with request ID wrapping.
|
// GetReceiptsPacket70 represents a block receipts query with request ID and
|
||||||
|
// FirstBlockReceiptIndex wrapping.
|
||||||
type GetReceiptsPacket70 struct {
|
type GetReceiptsPacket70 struct {
|
||||||
RequestId uint64
|
RequestId uint64
|
||||||
GetReceiptsRequest
|
GetReceiptsRequest
|
||||||
|
|
@ -299,12 +300,14 @@ type ReceiptsPacket70 struct {
|
||||||
// ReceiptsRLPResponse is used for receipts, when we already have it encoded
|
// ReceiptsRLPResponse is used for receipts, when we already have it encoded
|
||||||
type ReceiptsRLPResponse []rlp.RawValue
|
type ReceiptsRLPResponse []rlp.RawValue
|
||||||
|
|
||||||
// ReceiptsRLPPacket is ReceiptsRLPResponse with request ID wrapping.
|
// ReceiptsRLPPacket69 is ReceiptsRLPResponse with request ID wrapping.
|
||||||
type ReceiptsRLPPacket69 struct {
|
type ReceiptsRLPPacket69 struct {
|
||||||
RequestId uint64
|
RequestId uint64
|
||||||
ReceiptsRLPResponse
|
ReceiptsRLPResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReceiptsRLPPacket70 is ReceiptsRLPResponse with request ID and
|
||||||
|
// LastBlockIncomplete wrapping.
|
||||||
type ReceiptsRLPPacket70 struct {
|
type ReceiptsRLPPacket70 struct {
|
||||||
RequestId uint64
|
RequestId uint64
|
||||||
ReceiptsRLPResponse
|
ReceiptsRLPResponse
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue