aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--accounts/abi/abi.go3
-rw-r--r--accounts/abi/abi_test.go11
-rw-r--r--les/fetcher.go27
-rw-r--r--les/odr_requests.go8
-rw-r--r--les/odr_test.go2
-rw-r--r--les/peer.go6
-rw-r--r--les/request_test.go2
7 files changed, 39 insertions, 20 deletions
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go
index 254b1f7fb..535e5d78b 100644
--- a/accounts/abi/abi.go
+++ b/accounts/abi/abi.go
@@ -137,6 +137,9 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
// MethodById looks up a method by the 4-byte id
// returns nil if none found
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
+ if len(sigdata) < 4 {
+ return nil, fmt.Errorf("data too short (% bytes) for abi method lookup", len(sigdata))
+ }
for _, method := range abi.Methods {
if bytes.Equal(method.Id(), sigdata[:4]) {
return &method, nil
diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go
index 8018df775..59ba79cb6 100644
--- a/accounts/abi/abi_test.go
+++ b/accounts/abi/abi_test.go
@@ -711,5 +711,14 @@ func TestABI_MethodById(t *testing.T) {
t.Errorf("Method %v (id %v) not 'findable' by id in ABI", name, common.ToHex(m.Id()))
}
}
-
+ // Also test empty
+ if _, err := abi.MethodById([]byte{0x00}); err == nil {
+ t.Errorf("Expected error, too short to decode data")
+ }
+ if _, err := abi.MethodById([]byte{}); err == nil {
+ t.Errorf("Expected error, too short to decode data")
+ }
+ if _, err := abi.MethodById(nil); err == nil {
+ t.Errorf("Expected error, nil is short to decode data")
+ }
}
diff --git a/les/fetcher.go b/les/fetcher.go
index cc539c42b..f0d3b188d 100644
--- a/les/fetcher.go
+++ b/les/fetcher.go
@@ -32,8 +32,9 @@ import (
)
const (
- blockDelayTimeout = time.Second * 10 // timeout for a peer to announce a head that has already been confirmed by others
- maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer
+ blockDelayTimeout = time.Second * 10 // timeout for a peer to announce a head that has already been confirmed by others
+ maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer
+ serverStateAvailable = 100 // number of recent blocks where state availability is assumed
)
// lightFetcher implements retrieval of newly announced headers. It also provides a peerHasBlock function for the
@@ -215,8 +216,8 @@ func (f *lightFetcher) syncLoop() {
// registerPeer adds a new peer to the fetcher's peer set
func (f *lightFetcher) registerPeer(p *peer) {
p.lock.Lock()
- p.hasBlock = func(hash common.Hash, number uint64) bool {
- return f.peerHasBlock(p, hash, number)
+ p.hasBlock = func(hash common.Hash, number uint64, hasState bool) bool {
+ return f.peerHasBlock(p, hash, number, hasState)
}
p.lock.Unlock()
@@ -344,21 +345,27 @@ func (f *lightFetcher) announce(p *peer, head *announceData) {
// peerHasBlock returns true if we can assume the peer knows the given block
// based on its announcements
-func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64) bool {
+func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64, hasState bool) bool {
f.lock.Lock()
defer f.lock.Unlock()
+ fp := f.peers[p]
+ if fp == nil || fp.root == nil {
+ return false
+ }
+
+ if hasState {
+ if fp.lastAnnounced == nil || fp.lastAnnounced.number > number+serverStateAvailable {
+ return false
+ }
+ }
+
if f.syncing {
// always return true when syncing
// false positives are acceptable, a more sophisticated condition can be implemented later
return true
}
- fp := f.peers[p]
- if fp == nil || fp.root == nil {
- return false
- }
-
if number >= fp.root.number {
// it is recent enough that if it is known, is should be in the peer's block tree
return fp.nodeByHash[hash] != nil
diff --git a/les/odr_requests.go b/les/odr_requests.go
index 77b1b6d0c..0f2e5dd9e 100644
--- a/les/odr_requests.go
+++ b/les/odr_requests.go
@@ -84,7 +84,7 @@ func (r *BlockRequest) GetCost(peer *peer) uint64 {
// CanSend tells if a certain peer is suitable for serving the given request
func (r *BlockRequest) CanSend(peer *peer) bool {
- return peer.HasBlock(r.Hash, r.Number)
+ return peer.HasBlock(r.Hash, r.Number, false)
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
@@ -140,7 +140,7 @@ func (r *ReceiptsRequest) GetCost(peer *peer) uint64 {
// CanSend tells if a certain peer is suitable for serving the given request
func (r *ReceiptsRequest) CanSend(peer *peer) bool {
- return peer.HasBlock(r.Hash, r.Number)
+ return peer.HasBlock(r.Hash, r.Number, false)
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
@@ -202,7 +202,7 @@ func (r *TrieRequest) GetCost(peer *peer) uint64 {
// CanSend tells if a certain peer is suitable for serving the given request
func (r *TrieRequest) CanSend(peer *peer) bool {
- return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber)
+ return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true)
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
@@ -272,7 +272,7 @@ func (r *CodeRequest) GetCost(peer *peer) uint64 {
// CanSend tells if a certain peer is suitable for serving the given request
func (r *CodeRequest) CanSend(peer *peer) bool {
- return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber)
+ return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true)
}
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
diff --git a/les/odr_test.go b/les/odr_test.go
index e6458adf5..ac81fbcf0 100644
--- a/les/odr_test.go
+++ b/les/odr_test.go
@@ -194,7 +194,7 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
client.peers.Register(client.rPeer)
time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed
client.peers.lock.Lock()
- client.rPeer.hasBlock = func(common.Hash, uint64) bool { return true }
+ client.rPeer.hasBlock = func(common.Hash, uint64, bool) bool { return true }
client.peers.lock.Unlock()
test(5)
// still expect all retrievals to pass, now data should be cached locally
diff --git a/les/peer.go b/les/peer.go
index 1f343847e..678384f0e 100644
--- a/les/peer.go
+++ b/les/peer.go
@@ -67,7 +67,7 @@ type peer struct {
sendQueue *execQueue
poolEntry *poolEntry
- hasBlock func(common.Hash, uint64) bool
+ hasBlock func(common.Hash, uint64, bool) bool
responseErrors int
fcClient *flowcontrol.ClientNode // nil if the peer is server only
@@ -171,11 +171,11 @@ func (p *peer) GetRequestCost(msgcode uint64, amount int) uint64 {
}
// HasBlock checks if the peer has a given block
-func (p *peer) HasBlock(hash common.Hash, number uint64) bool {
+func (p *peer) HasBlock(hash common.Hash, number uint64, hasState bool) bool {
p.lock.RLock()
hasBlock := p.hasBlock
p.lock.RUnlock()
- return hasBlock != nil && hasBlock(hash, number)
+ return hasBlock != nil && hasBlock(hash, number, hasState)
}
// SendAnnounce announces the availability of a number of blocks through
diff --git a/les/request_test.go b/les/request_test.go
index f02c2a3d7..c9c185198 100644
--- a/les/request_test.go
+++ b/les/request_test.go
@@ -115,7 +115,7 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) {
client.peers.Register(client.rPeer)
time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed
client.rPeer.lock.Lock()
- client.rPeer.hasBlock = func(common.Hash, uint64) bool { return true }
+ client.rPeer.hasBlock = func(common.Hash, uint64, bool) bool { return true }
client.rPeer.lock.Unlock()
// expect all retrievals to pass
test(5)