core: ensure the canonical block is written before the canonical hash is set
This commit is contained in:
parent
4c2cc32f2e
commit
bb8059f6aa
@ -778,6 +778,14 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err
|
|||||||
localTd := self.GetTd(self.currentBlock.Hash(), self.currentBlock.NumberU64())
|
localTd := self.GetTd(self.currentBlock.Hash(), self.currentBlock.NumberU64())
|
||||||
externTd := new(big.Int).Add(block.Difficulty(), ptd)
|
externTd := new(big.Int).Add(block.Difficulty(), ptd)
|
||||||
|
|
||||||
|
// Irrelevant of the canonical status, write the block itself to the database
|
||||||
|
if err := self.hc.WriteTd(block.Hash(), block.NumberU64(), externTd); err != nil {
|
||||||
|
glog.Fatalf("failed to write block total difficulty: %v", err)
|
||||||
|
}
|
||||||
|
if err := WriteBlock(self.chainDb, block); err != nil {
|
||||||
|
glog.Fatalf("failed to write block contents: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// If the total difficulty is higher than our known, add it to the canonical chain
|
// If the total difficulty is higher than our known, add it to the canonical chain
|
||||||
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
||||||
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
||||||
@ -788,19 +796,11 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err
|
|||||||
return NonStatTy, err
|
return NonStatTy, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert the block as the new head of the chain
|
self.insert(block) // Insert the block as the new head of the chain
|
||||||
self.insert(block)
|
|
||||||
status = CanonStatTy
|
status = CanonStatTy
|
||||||
} else {
|
} else {
|
||||||
status = SideStatTy
|
status = SideStatTy
|
||||||
}
|
}
|
||||||
// Irrelevant of the canonical status, write the block itself to the database
|
|
||||||
if err := self.hc.WriteTd(block.Hash(), block.NumberU64(), externTd); err != nil {
|
|
||||||
glog.Fatalf("failed to write block total difficulty: %v", err)
|
|
||||||
}
|
|
||||||
if err := WriteBlock(self.chainDb, block); err != nil {
|
|
||||||
glog.Fatalf("failed to write block contents: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.futureBlocks.Remove(block.Hash())
|
self.futureBlocks.Remove(block.Hash())
|
||||||
|
|
||||||
|
@ -1090,3 +1090,41 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests if the canonical block can be fetched from the database during chain insertion.
|
||||||
|
func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||||
|
var (
|
||||||
|
db, _ = ethdb.NewMemDatabase()
|
||||||
|
genesis = WriteGenesisBlockForTesting(db)
|
||||||
|
)
|
||||||
|
|
||||||
|
evmux := &event.TypeMux{}
|
||||||
|
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
|
||||||
|
|
||||||
|
chain, _ := GenerateChain(nil, genesis, db, 10, func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
|
for i, _ := range chain {
|
||||||
|
go func(block *types.Block) {
|
||||||
|
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
|
||||||
|
for {
|
||||||
|
ch := GetCanonicalHash(db, block.NumberU64())
|
||||||
|
if ch == (common.Hash{}) {
|
||||||
|
continue // busy wait for canonical hash to be written
|
||||||
|
}
|
||||||
|
if ch != block.Hash() {
|
||||||
|
t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
|
||||||
|
}
|
||||||
|
fb := GetBlock(db, ch, block.NumberU64())
|
||||||
|
if fb == nil {
|
||||||
|
t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
|
||||||
|
}
|
||||||
|
if fb.Hash() != block.Hash() {
|
||||||
|
t.Fatalf("invalid block hash for block %d, want %s, got %s", block.NumberU64(), block.Hash().Hex(), fb.Hash().Hex())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}(chain[i])
|
||||||
|
|
||||||
|
blockchain.InsertChain(types.Blocks{chain[i]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -204,7 +204,11 @@ func GetTd(db ethdb.Database, hash common.Hash, number uint64) *big.Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetBlock retrieves an entire block corresponding to the hash, assembling it
|
// GetBlock retrieves an entire block corresponding to the hash, assembling it
|
||||||
// back from the stored header and body.
|
// back from the stored header and body. If either the header or body could not
|
||||||
|
// be retrieved nil is returned.
|
||||||
|
//
|
||||||
|
// Note, due to concurrent download of header and block body the header and thus
|
||||||
|
// canonical hash can be stored in the database but the body data not (yet).
|
||||||
func GetBlock(db ethdb.Database, hash common.Hash, number uint64) *types.Block {
|
func GetBlock(db ethdb.Database, hash common.Hash, number uint64) *types.Block {
|
||||||
// Retrieve the block header and body contents
|
// Retrieve the block header and body contents
|
||||||
header := GetHeader(db, hash, number)
|
header := GetHeader(db, hash, number)
|
||||||
|
@ -151,6 +151,14 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
|
|||||||
localTd := hc.GetTd(hc.currentHeaderHash, hc.currentHeader.Number.Uint64())
|
localTd := hc.GetTd(hc.currentHeaderHash, hc.currentHeader.Number.Uint64())
|
||||||
externTd := new(big.Int).Add(header.Difficulty, ptd)
|
externTd := new(big.Int).Add(header.Difficulty, ptd)
|
||||||
|
|
||||||
|
// Irrelevant of the canonical status, write the td and header to the database
|
||||||
|
if err := hc.WriteTd(hash, number, externTd); err != nil {
|
||||||
|
glog.Fatalf("failed to write header total difficulty: %v", err)
|
||||||
|
}
|
||||||
|
if err := WriteHeader(hc.chainDb, header); err != nil {
|
||||||
|
glog.Fatalf("failed to write header contents: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// If the total difficulty is higher than our known, add it to the canonical chain
|
// If the total difficulty is higher than our known, add it to the canonical chain
|
||||||
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
||||||
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
||||||
@ -176,6 +184,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
|
|||||||
headNumber = headHeader.Number.Uint64() - 1
|
headNumber = headHeader.Number.Uint64() - 1
|
||||||
headHeader = hc.GetHeader(headHash, headNumber)
|
headHeader = hc.GetHeader(headHash, headNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend the canonical chain with the new header
|
// Extend the canonical chain with the new header
|
||||||
if err := WriteCanonicalHash(hc.chainDb, hash, number); err != nil {
|
if err := WriteCanonicalHash(hc.chainDb, hash, number); err != nil {
|
||||||
glog.Fatalf("failed to insert header number: %v", err)
|
glog.Fatalf("failed to insert header number: %v", err)
|
||||||
@ -183,19 +192,14 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
|
|||||||
if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
|
if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
|
||||||
glog.Fatalf("failed to insert head header hash: %v", err)
|
glog.Fatalf("failed to insert head header hash: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header)
|
hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header)
|
||||||
|
|
||||||
status = CanonStatTy
|
status = CanonStatTy
|
||||||
} else {
|
} else {
|
||||||
status = SideStatTy
|
status = SideStatTy
|
||||||
}
|
}
|
||||||
// Irrelevant of the canonical status, write the header itself to the database
|
|
||||||
if err := hc.WriteTd(hash, number, externTd); err != nil {
|
|
||||||
glog.Fatalf("failed to write header total difficulty: %v", err)
|
|
||||||
}
|
|
||||||
if err := WriteHeader(hc.chainDb, header); err != nil {
|
|
||||||
glog.Fatalf("failed to write header contents: %v", err)
|
|
||||||
}
|
|
||||||
hc.headerCache.Add(hash, header)
|
hc.headerCache.Add(hash, header)
|
||||||
hc.numberCache.Add(hash, number)
|
hc.numberCache.Add(hash, number)
|
||||||
|
|
||||||
|
@ -74,6 +74,9 @@ func (self *Filter) SetTopics(topics [][]common.Hash) {
|
|||||||
func (self *Filter) Find() vm.Logs {
|
func (self *Filter) Find() vm.Logs {
|
||||||
latestHash := core.GetHeadBlockHash(self.db)
|
latestHash := core.GetHeadBlockHash(self.db)
|
||||||
latestBlock := core.GetBlock(self.db, latestHash, core.GetBlockNumber(self.db, latestHash))
|
latestBlock := core.GetBlock(self.db, latestHash, core.GetBlockNumber(self.db, latestHash))
|
||||||
|
if latestBlock == nil {
|
||||||
|
return vm.Logs{}
|
||||||
|
}
|
||||||
var beginBlockNo uint64 = uint64(self.begin)
|
var beginBlockNo uint64 = uint64(self.begin)
|
||||||
if self.begin == -1 {
|
if self.begin == -1 {
|
||||||
beginBlockNo = latestBlock.NumberU64()
|
beginBlockNo = latestBlock.NumberU64()
|
||||||
@ -123,13 +126,13 @@ func (self *Filter) mipFind(start, end uint64, depth int) (logs vm.Logs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Filter) getLogs(start, end uint64) (logs vm.Logs) {
|
func (self *Filter) getLogs(start, end uint64) (logs vm.Logs) {
|
||||||
var block *types.Block
|
|
||||||
|
|
||||||
for i := start; i <= end; i++ {
|
for i := start; i <= end; i++ {
|
||||||
|
var block *types.Block
|
||||||
hash := core.GetCanonicalHash(self.db, i)
|
hash := core.GetCanonicalHash(self.db, i)
|
||||||
if hash != (common.Hash{}) {
|
if hash != (common.Hash{}) {
|
||||||
block = core.GetBlock(self.db, hash, i)
|
block = core.GetBlock(self.db, hash, i)
|
||||||
} else { // block not found
|
}
|
||||||
|
if block == nil { // block not found/written
|
||||||
return logs
|
return logs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user