forked from cerc-io/plugeth
eth, les: reject stale request (#19689)
* eth, les: reject stale request * les: reuse local head number
This commit is contained in:
parent
3d3e83ecff
commit
c0a034ec89
@ -481,6 +481,7 @@ func (s *Ethereum) EthVersion() int { return int(s.protocolMa
|
|||||||
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
|
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
|
||||||
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
|
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) 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
|
// Protocols implements node.Service, returning all the currently configured
|
||||||
// network protocols to start.
|
// 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)
|
p.Log().Warn("Failed to retrieve header for code", "block", *number, "hash", request.BHash)
|
||||||
continue
|
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()
|
triedb := pm.blockchain.StateCache().TrieDB()
|
||||||
|
|
||||||
account, err := pm.getAccount(triedb, header.Root, common.BytesToHash(request.AccKey))
|
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)
|
p.Log().Warn("Failed to retrieve header for proof", "block", *number, "hash", request.BHash)
|
||||||
continue
|
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
|
root = header.Root
|
||||||
}
|
}
|
||||||
// Open the account or storage trie for the request
|
// 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.
|
// Tests that the transaction receipts can be retrieved based on hashes.
|
||||||
func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) }
|
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.
|
// Tests that CHT proofs can be correctly retrieved.
|
||||||
func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) }
|
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("serveHeaders", nil)
|
||||||
send = send.add("serveChainSince", uint64(0))
|
send = send.add("serveChainSince", uint64(0))
|
||||||
send = send.add("serveStateSince", 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("txRelay", nil)
|
||||||
}
|
}
|
||||||
send = send.add("flowControl/BL", server.defParams.BufLimit)
|
send = send.add("flowControl/BL", server.defParams.BufLimit)
|
||||||
|
@ -51,6 +51,8 @@ const (
|
|||||||
type LesServer struct {
|
type LesServer struct {
|
||||||
lesCommons
|
lesCommons
|
||||||
|
|
||||||
|
archiveMode bool // Flag whether the ethereum node runs in archive mode.
|
||||||
|
|
||||||
fcManager *flowcontrol.ClientManager // nil if our node is client only
|
fcManager *flowcontrol.ClientManager // nil if our node is client only
|
||||||
costTracker *costTracker
|
costTracker *costTracker
|
||||||
testCost uint64
|
testCost uint64
|
||||||
@ -93,7 +95,8 @@ func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
|
|||||||
nil,
|
nil,
|
||||||
quitSync,
|
quitSync,
|
||||||
new(sync.WaitGroup),
|
new(sync.WaitGroup),
|
||||||
config.ULC, eth.Synced)
|
config.ULC,
|
||||||
|
eth.Synced)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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),
|
bloomTrieIndexer: light.NewBloomTrieIndexer(eth.ChainDb(), nil, params.BloomBitsBlocks, params.BloomTrieFrequency),
|
||||||
protocolManager: pm,
|
protocolManager: pm,
|
||||||
},
|
},
|
||||||
|
archiveMode: eth.ArchiveMode(),
|
||||||
quitSync: quitSync,
|
quitSync: quitSync,
|
||||||
lesTopics: lesTopics,
|
lesTopics: lesTopics,
|
||||||
onlyAnnounce: config.OnlyAnnounce,
|
onlyAnnounce: config.OnlyAnnounce,
|
||||||
|
Loading…
Reference in New Issue
Block a user