Skip to content

Commit b9c90c5

Browse files
rjl493456442karalabe
authored andcommitted
core/rawdb: check hash before return data from ancient db (#20195)
* core/rawdb: check hash before return data from ancient db * core/rawdb: fix lint * core/rawdb: calculate the hash in the fly
1 parent 5fefe39 commit b9c90c5

File tree

2 files changed

+158
-37
lines changed

2 files changed

+158
-37
lines changed

core/rawdb/accessors_chain.go

Lines changed: 92 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/ethereum/go-ethereum/common"
2525
"github.com/ethereum/go-ethereum/core/types"
26+
"github.com/ethereum/go-ethereum/crypto"
2627
"github.com/ethereum/go-ethereum/ethdb"
2728
"github.com/ethereum/go-ethereum/log"
2829
"github.com/ethereum/go-ethereum/params"
@@ -173,18 +174,27 @@ func WriteFastTrieProgress(db ethdb.KeyValueWriter, count uint64) {
173174

174175
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
175176
func ReadHeaderRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
177+
// First try to look up the data in ancient database. Extra hash
178+
// comparison is necessary since ancient database only maintains
179+
// the canonical data.
176180
data, _ := db.Ancient(freezerHeaderTable, number)
177-
if len(data) == 0 {
178-
data, _ = db.Get(headerKey(number, hash))
179-
// In the background freezer is moving data from leveldb to flatten files.
180-
// So during the first check for ancient db, the data is not yet in there,
181-
// but when we reach into leveldb, the data was already moved. That would
182-
// result in a not found error.
183-
if len(data) == 0 {
184-
data, _ = db.Ancient(freezerHeaderTable, number)
185-
}
181+
if len(data) > 0 && crypto.Keccak256Hash(data) == hash {
182+
return data
183+
}
184+
// Then try to look up the data in leveldb.
185+
data, _ = db.Get(headerKey(number, hash))
186+
if len(data) > 0 {
187+
return data
188+
}
189+
// In the background freezer is moving data from leveldb to flatten files.
190+
// So during the first check for ancient db, the data is not yet in there,
191+
// but when we reach into leveldb, the data was already moved. That would
192+
// result in a not found error.
193+
data, _ = db.Ancient(freezerHeaderTable, number)
194+
if len(data) > 0 && crypto.Keccak256Hash(data) == hash {
195+
return data
186196
}
187-
return data
197+
return nil // Can't find the data anywhere.
188198
}
189199

190200
// HasHeader verifies the existence of a block header corresponding to the hash.
@@ -251,18 +261,33 @@ func deleteHeaderWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number
251261

252262
// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
253263
func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
264+
// First try to look up the data in ancient database. Extra hash
265+
// comparison is necessary since ancient database only maintains
266+
// the canonical data.
254267
data, _ := db.Ancient(freezerBodiesTable, number)
255-
if len(data) == 0 {
256-
data, _ = db.Get(blockBodyKey(number, hash))
257-
// In the background freezer is moving data from leveldb to flatten files.
258-
// So during the first check for ancient db, the data is not yet in there,
259-
// but when we reach into leveldb, the data was already moved. That would
260-
// result in a not found error.
261-
if len(data) == 0 {
262-
data, _ = db.Ancient(freezerBodiesTable, number)
268+
if len(data) > 0 {
269+
h, _ := db.Ancient(freezerHashTable, number)
270+
if common.BytesToHash(h) == hash {
271+
return data
272+
}
273+
}
274+
// Then try to look up the data in leveldb.
275+
data, _ = db.Get(blockBodyKey(number, hash))
276+
if len(data) > 0 {
277+
return data
278+
}
279+
// In the background freezer is moving data from leveldb to flatten files.
280+
// So during the first check for ancient db, the data is not yet in there,
281+
// but when we reach into leveldb, the data was already moved. That would
282+
// result in a not found error.
283+
data, _ = db.Ancient(freezerBodiesTable, number)
284+
if len(data) > 0 {
285+
h, _ := db.Ancient(freezerHashTable, number)
286+
if common.BytesToHash(h) == hash {
287+
return data
263288
}
264289
}
265-
return data
290+
return nil // Can't find the data anywhere.
266291
}
267292

268293
// WriteBodyRLP stores an RLP encoded block body into the database.
@@ -315,18 +340,33 @@ func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
315340

316341
// ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding.
317342
func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
343+
// First try to look up the data in ancient database. Extra hash
344+
// comparison is necessary since ancient database only maintains
345+
// the canonical data.
318346
data, _ := db.Ancient(freezerDifficultyTable, number)
319-
if len(data) == 0 {
320-
data, _ = db.Get(headerTDKey(number, hash))
321-
// In the background freezer is moving data from leveldb to flatten files.
322-
// So during the first check for ancient db, the data is not yet in there,
323-
// but when we reach into leveldb, the data was already moved. That would
324-
// result in a not found error.
325-
if len(data) == 0 {
326-
data, _ = db.Ancient(freezerDifficultyTable, number)
347+
if len(data) > 0 {
348+
h, _ := db.Ancient(freezerHashTable, number)
349+
if common.BytesToHash(h) == hash {
350+
return data
351+
}
352+
}
353+
// Then try to look up the data in leveldb.
354+
data, _ = db.Get(headerTDKey(number, hash))
355+
if len(data) > 0 {
356+
return data
357+
}
358+
// In the background freezer is moving data from leveldb to flatten files.
359+
// So during the first check for ancient db, the data is not yet in there,
360+
// but when we reach into leveldb, the data was already moved. That would
361+
// result in a not found error.
362+
data, _ = db.Ancient(freezerDifficultyTable, number)
363+
if len(data) > 0 {
364+
h, _ := db.Ancient(freezerHashTable, number)
365+
if common.BytesToHash(h) == hash {
366+
return data
327367
}
328368
}
329-
return data
369+
return nil // Can't find the data anywhere.
330370
}
331371

332372
// ReadTd retrieves a block's total difficulty corresponding to the hash.
@@ -375,18 +415,33 @@ func HasReceipts(db ethdb.Reader, hash common.Hash, number uint64) bool {
375415

376416
// ReadReceiptsRLP retrieves all the transaction receipts belonging to a block in RLP encoding.
377417
func ReadReceiptsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
418+
// First try to look up the data in ancient database. Extra hash
419+
// comparison is necessary since ancient database only maintains
420+
// the canonical data.
378421
data, _ := db.Ancient(freezerReceiptTable, number)
379-
if len(data) == 0 {
380-
data, _ = db.Get(blockReceiptsKey(number, hash))
381-
// In the background freezer is moving data from leveldb to flatten files.
382-
// So during the first check for ancient db, the data is not yet in there,
383-
// but when we reach into leveldb, the data was already moved. That would
384-
// result in a not found error.
385-
if len(data) == 0 {
386-
data, _ = db.Ancient(freezerReceiptTable, number)
422+
if len(data) > 0 {
423+
h, _ := db.Ancient(freezerHashTable, number)
424+
if common.BytesToHash(h) == hash {
425+
return data
426+
}
427+
}
428+
// Then try to look up the data in leveldb.
429+
data, _ = db.Get(blockReceiptsKey(number, hash))
430+
if len(data) > 0 {
431+
return data
432+
}
433+
// In the background freezer is moving data from leveldb to flatten files.
434+
// So during the first check for ancient db, the data is not yet in there,
435+
// but when we reach into leveldb, the data was already moved. That would
436+
// result in a not found error.
437+
data, _ = db.Ancient(freezerReceiptTable, number)
438+
if len(data) > 0 {
439+
h, _ := db.Ancient(freezerHashTable, number)
440+
if common.BytesToHash(h) == hash {
441+
return data
387442
}
388443
}
389-
return data
444+
return nil // Can't find the data anywhere.
390445
}
391446

392447
// ReadRawReceipts retrieves all the transaction receipts belonging to a block.

core/rawdb/accessors_chain_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import (
2020
"bytes"
2121
"encoding/hex"
2222
"fmt"
23+
"io/ioutil"
2324
"math/big"
25+
"os"
2426
"testing"
2527

2628
"github.com/ethereum/go-ethereum/common"
@@ -358,3 +360,67 @@ func checkReceiptsRLP(have, want types.Receipts) error {
358360
}
359361
return nil
360362
}
363+
364+
func TestAncientStorage(t *testing.T) {
365+
// Freezer style fast import the chain.
366+
frdir, err := ioutil.TempDir("", "")
367+
if err != nil {
368+
t.Fatalf("failed to create temp freezer dir: %v", err)
369+
}
370+
defer os.Remove(frdir)
371+
372+
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "")
373+
if err != nil {
374+
t.Fatalf("failed to create database with ancient backend")
375+
}
376+
// Create a test block
377+
block := types.NewBlockWithHeader(&types.Header{
378+
Number: big.NewInt(0),
379+
Extra: []byte("test block"),
380+
UncleHash: types.EmptyUncleHash,
381+
TxHash: types.EmptyRootHash,
382+
ReceiptHash: types.EmptyRootHash,
383+
})
384+
// Ensure nothing non-existent will be read
385+
hash, number := block.Hash(), block.NumberU64()
386+
if blob := ReadHeaderRLP(db, hash, number); len(blob) > 0 {
387+
t.Fatalf("non existent header returned")
388+
}
389+
if blob := ReadBodyRLP(db, hash, number); len(blob) > 0 {
390+
t.Fatalf("non existent body returned")
391+
}
392+
if blob := ReadReceiptsRLP(db, hash, number); len(blob) > 0 {
393+
t.Fatalf("non existent receipts returned")
394+
}
395+
if blob := ReadTdRLP(db, hash, number); len(blob) > 0 {
396+
t.Fatalf("non existent td returned")
397+
}
398+
// Write and verify the header in the database
399+
WriteAncientBlock(db, block, nil, big.NewInt(100))
400+
if blob := ReadHeaderRLP(db, hash, number); len(blob) == 0 {
401+
t.Fatalf("no header returned")
402+
}
403+
if blob := ReadBodyRLP(db, hash, number); len(blob) == 0 {
404+
t.Fatalf("no body returned")
405+
}
406+
if blob := ReadReceiptsRLP(db, hash, number); len(blob) == 0 {
407+
t.Fatalf("no receipts returned")
408+
}
409+
if blob := ReadTdRLP(db, hash, number); len(blob) == 0 {
410+
t.Fatalf("no td returned")
411+
}
412+
// Use a fake hash for data retrieval, nothing should be returned.
413+
fakeHash := common.BytesToHash([]byte{0x01, 0x02, 0x03})
414+
if blob := ReadHeaderRLP(db, fakeHash, number); len(blob) != 0 {
415+
t.Fatalf("invalid header returned")
416+
}
417+
if blob := ReadBodyRLP(db, fakeHash, number); len(blob) != 0 {
418+
t.Fatalf("invalid body returned")
419+
}
420+
if blob := ReadReceiptsRLP(db, fakeHash, number); len(blob) != 0 {
421+
t.Fatalf("invalid receipts returned")
422+
}
423+
if blob := ReadTdRLP(db, fakeHash, number); len(blob) != 0 {
424+
t.Fatalf("invalid td returned")
425+
}
426+
}

0 commit comments

Comments
 (0)