eth, les: reject stale request (#19689)

* eth, les: reject stale request

* les: reuse local head number
This commit is contained in:
gary rong 2019-06-11 15:40:32 +08:00 committed by Péter Szilágyi
parent 3d3e83ecff
commit c0a034ec89
5 changed files with 90 additions and 2 deletions

@ -481,6 +481,7 @@ func (s *Ethereum) EthVersion() int { return int(s.protocolMa
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 }
func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning }
// Protocols implements node.Service, returning all the currently configured
// network protocols to start.

@ -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

@ -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) }

@ -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)

@ -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,