aboutsummaryrefslogtreecommitdiffstats
path: root/les
diff options
context:
space:
mode:
Diffstat (limited to 'les')
-rw-r--r--les/handler.go14
-rw-r--r--les/handler_test.go62
-rw-r--r--les/peer.go9
-rw-r--r--les/server.go6
4 files changed, 89 insertions, 2 deletions
diff --git a/les/handler.go b/les/handler.go
index 59bfd81cd..32f1903d1 100644
--- a/les/handler.go
+++ b/les/handler.go
@@ -698,6 +698,13 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
p.Log().Warn("Failed to retrieve header for code", "block", *number, "hash", request.BHash)
continue
}
+ // Refuse to search stale state data in the database since looking for
+ // a non-exist key is kind of expensive.
+ local := pm.blockchain.CurrentHeader().Number.Uint64()
+ if !pm.server.archiveMode && header.Number.Uint64()+core.TriesInMemory <= local {
+ p.Log().Debug("Reject stale code request", "number", header.Number.Uint64(), "head", local)
+ continue
+ }
triedb := pm.blockchain.StateCache().TrieDB()
account, err := pm.getAccount(triedb, header.Root, common.BytesToHash(request.AccKey))
@@ -852,6 +859,13 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", request.BHash)
continue
}
+ // Refuse to search stale state data in the database since looking for
+ // a non-exist key is kind of expensive.
+ local := pm.blockchain.CurrentHeader().Number.Uint64()
+ if !pm.server.archiveMode && header.Number.Uint64()+core.TriesInMemory <= local {
+ p.Log().Debug("Reject stale trie request", "number", header.Number.Uint64(), "head", local)
+ continue
+ }
root = header.Root
}
// Open the account or storage trie for the request
diff --git a/les/handler_test.go b/les/handler_test.go
index 6e24165cf..51f0a1a0e 100644
--- a/les/handler_test.go
+++ b/les/handler_test.go
@@ -278,6 +278,31 @@ func testGetCode(t *testing.T, protocol int) {
}
}
+// Tests that the stale contract codes can't be retrieved based on account addresses.
+func TestGetStaleCodeLes2(t *testing.T) { testGetStaleCode(t, 2) }
+func TestGetStaleCodeLes3(t *testing.T) { testGetStaleCode(t, 3) }
+
+func testGetStaleCode(t *testing.T, protocol int) {
+ server, tearDown := newServerEnv(t, core.TriesInMemory+4, protocol, nil)
+ defer tearDown()
+ bc := server.pm.blockchain.(*core.BlockChain)
+
+ check := func(number uint64, expected [][]byte) {
+ req := &CodeReq{
+ BHash: bc.GetHeaderByNumber(number).Hash(),
+ AccKey: crypto.Keccak256(testContractAddr[:]),
+ }
+ cost := server.tPeer.GetRequestCost(GetCodeMsg, 1)
+ sendRequest(server.tPeer.app, GetCodeMsg, 42, cost, []*CodeReq{req})
+ if err := expectResponse(server.tPeer.app, CodeMsg, 42, testBufLimit, expected); err != nil {
+ t.Errorf("codes mismatch: %v", err)
+ }
+ }
+ check(0, [][]byte{}) // Non-exist contract
+ check(testContractDeployed, [][]byte{}) // Stale contract
+ check(bc.CurrentHeader().Number.Uint64(), [][]byte{testContractCodeDeployed}) // Fresh contract
+}
+
// Tests that the transaction receipts can be retrieved based on hashes.
func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) }
@@ -338,6 +363,43 @@ func testGetProofs(t *testing.T, protocol int) {
}
}
+// Tests that the stale contract codes can't be retrieved based on account addresses.
+func TestGetStaleProofLes2(t *testing.T) { testGetStaleProof(t, 2) }
+func TestGetStaleProofLes3(t *testing.T) { testGetStaleProof(t, 3) }
+
+func testGetStaleProof(t *testing.T, protocol int) {
+ server, tearDown := newServerEnv(t, core.TriesInMemory+4, protocol, nil)
+ defer tearDown()
+ bc := server.pm.blockchain.(*core.BlockChain)
+
+ check := func(number uint64, wantOK bool) {
+ var (
+ header = bc.GetHeaderByNumber(number)
+ account = crypto.Keccak256(testBankAddress.Bytes())
+ )
+ req := &ProofReq{
+ BHash: header.Hash(),
+ Key: account,
+ }
+ cost := server.tPeer.GetRequestCost(GetProofsV2Msg, 1)
+ sendRequest(server.tPeer.app, GetProofsV2Msg, 42, cost, []*ProofReq{req})
+
+ var expected []rlp.RawValue
+ if wantOK {
+ proofsV2 := light.NewNodeSet()
+ t, _ := trie.New(header.Root, trie.NewDatabase(server.db))
+ t.Prove(crypto.Keccak256(account), 0, proofsV2)
+ expected = proofsV2.NodeList()
+ }
+ if err := expectResponse(server.tPeer.app, ProofsV2Msg, 42, testBufLimit, expected); err != nil {
+ t.Errorf("codes mismatch: %v", err)
+ }
+ }
+ check(0, false) // Non-exist proof
+ check(2, false) // Stale proof
+ check(bc.CurrentHeader().Number.Uint64(), true) // Fresh proof
+}
+
// Tests that CHT proofs can be correctly retrieved.
func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) }
diff --git a/les/peer.go b/les/peer.go
index 6792d0611..56d316f50 100644
--- a/les/peer.go
+++ b/les/peer.go
@@ -551,7 +551,14 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
send = send.add("serveHeaders", nil)
send = send.add("serveChainSince", uint64(0))
send = send.add("serveStateSince", uint64(0))
- send = send.add("serveRecentState", uint64(core.TriesInMemory-4))
+
+ // If local ethereum node is running in archive mode, advertise ourselves we have
+ // all version state data. Otherwise only recent state is available.
+ stateRecent := uint64(core.TriesInMemory - 4)
+ if server.archiveMode {
+ stateRecent = 0
+ }
+ send = send.add("serveRecentState", stateRecent)
send = send.add("txRelay", nil)
}
send = send.add("flowControl/BL", server.defParams.BufLimit)
diff --git a/les/server.go b/les/server.go
index 836fa0d55..fbdf6cf1e 100644
--- a/les/server.go
+++ b/les/server.go
@@ -51,6 +51,8 @@ const (
type LesServer struct {
lesCommons
+ archiveMode bool // Flag whether the ethereum node runs in archive mode.
+
fcManager *flowcontrol.ClientManager // nil if our node is client only
costTracker *costTracker
testCost uint64
@@ -93,7 +95,8 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
nil,
quitSync,
new(sync.WaitGroup),
- config.ULC, eth.Synced)
+ config.ULC,
+ eth.Synced)
if err != nil {
return nil, err
}
@@ -120,6 +123,7 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency),
protocolManager: pm,
},
+ archiveMode: eth.ArchiveMode(),
quitSync: quitSync,
lesTopics: lesTopics,
onlyAnnounce: config.OnlyAnnounce,