Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
f9917c8c
Commit
f9917c8c
authored
Apr 05, 2016
by
zsfelfoldi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: improved chainDb using sequential keys
parent
5a458da4
Changes
24
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
726 additions
and
365 deletions
+726
-365
chaincmd.go
cmd/geth/chaincmd.go
+1
-1
flags.go
cmd/utils/flags.go
+1
-1
bench_test.go
core/bench_test.go
+5
-5
block_validator.go
core/block_validator.go
+1
-1
blockchain.go
core/blockchain.go
+72
-52
blockchain_test.go
core/blockchain_test.go
+15
-15
database_util.go
core/database_util.go
+114
-65
database_util_test.go
core/database_util_test.go
+40
-40
genesis.go
core/genesis.go
+3
-3
headerchain.go
core/headerchain.go
+69
-28
vm_env.go
core/vm_env.go
+1
-1
api.go
eth/api.go
+13
-13
backend.go
eth/backend.go
+10
-108
backend_test.go
eth/backend_test.go
+1
-1
db_upgrade.go
eth/db_upgrade.go
+343
-0
api.go
eth/filters/api.go
+1
-1
filter.go
eth/filters/filter.go
+4
-3
filter_test.go
eth/filters/filter_test.go
+2
-2
gasprice.go
eth/gasprice.go
+1
-1
handler.go
eth/handler.go
+18
-14
handler_test.go
eth/handler_test.go
+5
-5
sync.go
eth/sync.go
+2
-1
worker.go
miner/worker.go
+2
-2
block_test_util.go
tests/block_test_util.go
+2
-2
No files found.
cmd/geth/chaincmd.go
View file @
f9917c8c
...
...
@@ -170,7 +170,7 @@ func dump(ctx *cli.Context) {
for
_
,
arg
:=
range
ctx
.
Args
()
{
var
block
*
types
.
Block
if
hashish
(
arg
)
{
block
=
chain
.
GetBlock
(
common
.
HexToHash
(
arg
))
block
=
chain
.
GetBlock
ByHash
(
common
.
HexToHash
(
arg
))
}
else
{
num
,
_
:=
strconv
.
Atoi
(
arg
)
block
=
chain
.
GetBlockByNumber
(
uint64
(
num
))
...
...
cmd/utils/flags.go
View file @
f9917c8c
...
...
@@ -806,7 +806,7 @@ func MustMakeChainConfig(ctx *cli.Context) *core.ChainConfig {
// MustMakeChainConfigFromDb reads the chain configuration from the given database.
func
MustMakeChainConfigFromDb
(
ctx
*
cli
.
Context
,
db
ethdb
.
Database
)
*
core
.
ChainConfig
{
genesis
:=
core
.
GetBlock
(
db
,
core
.
GetCanonicalHash
(
db
,
0
))
genesis
:=
core
.
GetBlock
(
db
,
core
.
GetCanonicalHash
(
db
,
0
)
,
0
)
if
genesis
!=
nil
{
// Existing genesis block, use stored config if available.
...
...
core/bench_test.go
View file @
f9917c8c
...
...
@@ -231,11 +231,11 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
hash
=
header
.
Hash
()
WriteHeader
(
db
,
header
)
WriteCanonicalHash
(
db
,
hash
,
n
)
WriteTd
(
db
,
hash
,
big
.
NewInt
(
int64
(
n
+
1
)))
WriteTd
(
db
,
hash
,
n
,
big
.
NewInt
(
int64
(
n
+
1
)))
if
full
||
n
==
0
{
block
:=
types
.
NewBlockWithHeader
(
header
)
WriteBody
(
db
,
hash
,
block
.
Body
())
WriteBlockReceipts
(
db
,
hash
,
nil
)
WriteBody
(
db
,
hash
,
n
,
block
.
Body
())
WriteBlockReceipts
(
db
,
hash
,
n
,
n
il
)
}
}
}
...
...
@@ -287,8 +287,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
header
:=
chain
.
GetHeaderByNumber
(
n
)
if
full
{
hash
:=
header
.
Hash
()
GetBody
(
db
,
hash
)
GetBlockReceipts
(
db
,
hash
)
GetBody
(
db
,
hash
,
n
)
GetBlockReceipts
(
db
,
hash
,
n
)
}
}
...
...
core/block_validator.go
View file @
f9917c8c
...
...
@@ -72,7 +72,7 @@ func (v *BlockValidator) ValidateBlock(block *types.Block) error {
return
&
KnownBlockError
{
block
.
Number
(),
block
.
Hash
()}
}
}
parent
:=
v
.
bc
.
GetBlock
(
block
.
ParentHash
())
parent
:=
v
.
bc
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
)
if
parent
==
nil
{
return
ParentError
(
block
.
ParentHash
())
}
...
...
core/blockchain.go
View file @
f9917c8c
...
...
@@ -54,9 +54,7 @@ var (
)
const
(
headerCacheLimit
=
512
bodyCacheLimit
=
256
tdCacheLimit
=
1024
blockCacheLimit
=
256
maxFutureBlocks
=
256
maxTimeFutureBlocks
=
30
...
...
@@ -151,7 +149,7 @@ func NewBlockChain(chainDb ethdb.Database, config *ChainConfig, pow pow.PoW, mux
}
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
for
hash
,
_
:=
range
BadHashes
{
if
header
:=
bc
.
GetHeader
(
hash
);
header
!=
nil
{
if
header
:=
bc
.
GetHeader
ByHash
(
hash
);
header
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Found bad hash, rewinding chain to block #%d [%x…]"
,
header
.
Number
,
header
.
ParentHash
[
:
4
])
bc
.
SetHead
(
header
.
Number
.
Uint64
()
-
1
)
glog
.
V
(
logger
.
Error
)
.
Infoln
(
"Chain rewind was successful, resuming normal operation"
)
...
...
@@ -175,7 +173,7 @@ func (self *BlockChain) loadLastState() error {
// Corrupt or empty database, init from scratch
self
.
Reset
()
}
else
{
if
block
:=
self
.
GetBlock
(
head
);
block
!=
nil
{
if
block
:=
self
.
GetBlock
ByHash
(
head
);
block
!=
nil
{
// Block found, set as the current head
self
.
currentBlock
=
block
}
else
{
...
...
@@ -186,7 +184,7 @@ func (self *BlockChain) loadLastState() error {
// Restore the last known head header
currentHeader
:=
self
.
currentBlock
.
Header
()
if
head
:=
GetHeadHeaderHash
(
self
.
chainDb
);
head
!=
(
common
.
Hash
{})
{
if
header
:=
self
.
GetHeader
(
head
);
header
!=
nil
{
if
header
:=
self
.
GetHeader
ByHash
(
head
);
header
!=
nil
{
currentHeader
=
header
}
}
...
...
@@ -194,16 +192,16 @@ func (self *BlockChain) loadLastState() error {
// Restore the last known head fast block
self
.
currentFastBlock
=
self
.
currentBlock
if
head
:=
GetHeadFastBlockHash
(
self
.
chainDb
);
head
!=
(
common
.
Hash
{})
{
if
block
:=
self
.
GetBlock
(
head
);
block
!=
nil
{
if
block
:=
self
.
GetBlock
ByHash
(
head
);
block
!=
nil
{
self
.
currentFastBlock
=
block
}
}
// Issue a status log and return
headerTd
:=
self
.
GetTd
(
self
.
hc
.
CurrentHeader
()
.
Hash
())
blockTd
:=
self
.
GetTd
(
self
.
currentBlock
.
Hash
())
fastTd
:=
self
.
GetTd
(
self
.
currentFastBlock
.
Hash
())
headerTd
:=
self
.
GetTd
(
currentHeader
.
Hash
(),
currentHeader
.
Number
.
Uint64
())
blockTd
:=
self
.
GetTd
(
self
.
currentBlock
.
Hash
()
,
self
.
currentBlock
.
NumberU64
()
)
fastTd
:=
self
.
GetTd
(
self
.
currentFastBlock
.
Hash
()
,
self
.
currentFastBlock
.
NumberU64
()
)
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Last header: #%d [%x…] TD=%v"
,
self
.
hc
.
CurrentHeader
()
.
Number
,
self
.
hc
.
CurrentHeader
()
.
Hash
()
.
Bytes
()[
:
4
],
headerTd
)
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Last header: #%d [%x…] TD=%v"
,
currentHeader
.
Number
,
currentHeader
.
Hash
()
.
Bytes
()[
:
4
],
headerTd
)
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Last block: #%d [%x…] TD=%v"
,
self
.
currentBlock
.
Number
(),
self
.
currentBlock
.
Hash
()
.
Bytes
()[
:
4
],
blockTd
)
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Fast block: #%d [%x…] TD=%v"
,
self
.
currentFastBlock
.
Number
(),
self
.
currentFastBlock
.
Hash
()
.
Bytes
()[
:
4
],
fastTd
)
...
...
@@ -218,8 +216,8 @@ func (bc *BlockChain) SetHead(head uint64) {
bc
.
mu
.
Lock
()
defer
bc
.
mu
.
Unlock
()
delFn
:=
func
(
hash
common
.
Hash
)
{
DeleteBody
(
bc
.
chainDb
,
hash
)
delFn
:=
func
(
hash
common
.
Hash
,
num
uint64
)
{
DeleteBody
(
bc
.
chainDb
,
hash
,
num
)
}
bc
.
hc
.
SetHead
(
head
,
delFn
)
...
...
@@ -230,11 +228,12 @@ func (bc *BlockChain) SetHead(head uint64) {
bc
.
futureBlocks
.
Purge
()
// Update all computed fields to the new head
if
bc
.
currentBlock
!=
nil
&&
bc
.
hc
.
CurrentHeader
()
.
Number
.
Uint64
()
<
bc
.
currentBlock
.
NumberU64
()
{
bc
.
currentBlock
=
bc
.
GetBlock
(
bc
.
hc
.
CurrentHeader
()
.
Hash
())
currentHeader
:=
bc
.
hc
.
CurrentHeader
()
if
bc
.
currentBlock
!=
nil
&&
currentHeader
.
Number
.
Uint64
()
<
bc
.
currentBlock
.
NumberU64
()
{
bc
.
currentBlock
=
bc
.
GetBlock
(
currentHeader
.
Hash
(),
currentHeader
.
Number
.
Uint64
())
}
if
bc
.
currentFastBlock
!=
nil
&&
bc
.
hc
.
CurrentHeader
()
.
Number
.
Uint64
()
<
bc
.
currentFastBlock
.
NumberU64
()
{
bc
.
currentFastBlock
=
bc
.
GetBlock
(
bc
.
hc
.
CurrentHeader
()
.
Hash
())
if
bc
.
currentFastBlock
!=
nil
&&
currentHeader
.
Number
.
Uint64
()
<
bc
.
currentFastBlock
.
NumberU64
()
{
bc
.
currentFastBlock
=
bc
.
GetBlock
(
currentHeader
.
Hash
(),
currentHeader
.
Number
.
Uint64
())
}
if
bc
.
currentBlock
==
nil
{
...
...
@@ -257,7 +256,7 @@ func (bc *BlockChain) SetHead(head uint64) {
// irrelevant what the chain contents were prior.
func
(
self
*
BlockChain
)
FastSyncCommitHead
(
hash
common
.
Hash
)
error
{
// Make sure that both the block as well at its state trie exists
block
:=
self
.
GetBlock
(
hash
)
block
:=
self
.
GetBlock
ByHash
(
hash
)
if
block
==
nil
{
return
fmt
.
Errorf
(
"non existent block [%x…]"
,
hash
[
:
4
])
}
...
...
@@ -313,7 +312,7 @@ func (self *BlockChain) Status() (td *big.Int, currentBlock common.Hash, genesis
self
.
mu
.
RLock
()
defer
self
.
mu
.
RUnlock
()
return
self
.
GetTd
(
self
.
currentBlock
.
Hash
()),
self
.
currentBlock
.
Hash
(),
self
.
genesisBlock
.
Hash
()
return
self
.
GetTd
(
self
.
currentBlock
.
Hash
()
,
self
.
currentBlock
.
NumberU64
()
),
self
.
currentBlock
.
Hash
(),
self
.
genesisBlock
.
Hash
()
}
// SetProcessor sets the processor required for making state modifications.
...
...
@@ -367,7 +366,7 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) {
defer
bc
.
mu
.
Unlock
()
// Prepare the genesis block and reinitialise the chain
if
err
:=
bc
.
hc
.
WriteTd
(
genesis
.
Hash
(),
genesis
.
Difficulty
());
err
!=
nil
{
if
err
:=
bc
.
hc
.
WriteTd
(
genesis
.
Hash
(),
genesis
.
NumberU64
(),
genesis
.
Difficulty
());
err
!=
nil
{
glog
.
Fatalf
(
"failed to write genesis block TD: %v"
,
err
)
}
if
err
:=
WriteBlock
(
bc
.
chainDb
,
genesis
);
err
!=
nil
{
...
...
@@ -457,7 +456,7 @@ func (self *BlockChain) GetBody(hash common.Hash) *types.Body {
body
:=
cached
.
(
*
types
.
Body
)
return
body
}
body
:=
GetBody
(
self
.
chainDb
,
hash
)
body
:=
GetBody
(
self
.
chainDb
,
hash
,
self
.
hc
.
GetBlockNumber
(
hash
)
)
if
body
==
nil
{
return
nil
}
...
...
@@ -473,7 +472,7 @@ func (self *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue {
if
cached
,
ok
:=
self
.
bodyRLPCache
.
Get
(
hash
);
ok
{
return
cached
.
(
rlp
.
RawValue
)
}
body
:=
GetBodyRLP
(
self
.
chainDb
,
hash
)
body
:=
GetBodyRLP
(
self
.
chainDb
,
hash
,
self
.
hc
.
GetBlockNumber
(
hash
)
)
if
len
(
body
)
==
0
{
return
nil
}
...
...
@@ -485,14 +484,14 @@ func (self *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue {
// HasBlock checks if a block is fully present in the database or not, caching
// it if present.
func
(
bc
*
BlockChain
)
HasBlock
(
hash
common
.
Hash
)
bool
{
return
bc
.
GetBlock
(
hash
)
!=
nil
return
bc
.
GetBlock
ByHash
(
hash
)
!=
nil
}
// HasBlockAndState checks if a block and associated state trie is fully present
// in the database or not, caching it if present.
func
(
bc
*
BlockChain
)
HasBlockAndState
(
hash
common
.
Hash
)
bool
{
// Check first that the block itself is known
block
:=
bc
.
GetBlock
(
hash
)
block
:=
bc
.
GetBlock
ByHash
(
hash
)
if
block
==
nil
{
return
false
}
...
...
@@ -501,13 +500,14 @@ func (bc *BlockChain) HasBlockAndState(hash common.Hash) bool {
return
err
==
nil
}
// GetBlock retrieves a block from the database by hash, caching it if found.
func
(
self
*
BlockChain
)
GetBlock
(
hash
common
.
Hash
)
*
types
.
Block
{
// GetBlock retrieves a block from the database by hash and number,
// caching it if found.
func
(
self
*
BlockChain
)
GetBlock
(
hash
common
.
Hash
,
number
uint64
)
*
types
.
Block
{
// Short circuit if the block's already in the cache, retrieve otherwise
if
block
,
ok
:=
self
.
blockCache
.
Get
(
hash
);
ok
{
return
block
.
(
*
types
.
Block
)
}
block
:=
GetBlock
(
self
.
chainDb
,
hash
)
block
:=
GetBlock
(
self
.
chainDb
,
hash
,
number
)
if
block
==
nil
{
return
nil
}
...
...
@@ -516,6 +516,11 @@ func (self *BlockChain) GetBlock(hash common.Hash) *types.Block {
return
block
}
// GetBlockByHash retrieves a block from the database by hash, caching it if found.
func
(
self
*
BlockChain
)
GetBlockByHash
(
hash
common
.
Hash
)
*
types
.
Block
{
return
self
.
GetBlock
(
hash
,
self
.
hc
.
GetBlockNumber
(
hash
))
}
// GetBlockByNumber retrieves a block from the database by number, caching it
// (associated with its hash) if found.
func
(
self
*
BlockChain
)
GetBlockByNumber
(
number
uint64
)
*
types
.
Block
{
...
...
@@ -523,19 +528,21 @@ func (self *BlockChain) GetBlockByNumber(number uint64) *types.Block {
if
hash
==
(
common
.
Hash
{})
{
return
nil
}
return
self
.
GetBlock
(
hash
)
return
self
.
GetBlock
(
hash
,
number
)
}
// [deprecated by eth/62]
// GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors.
func
(
self
*
BlockChain
)
GetBlocksFromHash
(
hash
common
.
Hash
,
n
int
)
(
blocks
[]
*
types
.
Block
)
{
number
:=
self
.
hc
.
GetBlockNumber
(
hash
)
for
i
:=
0
;
i
<
n
;
i
++
{
block
:=
self
.
GetBlock
(
hash
)
block
:=
self
.
GetBlock
(
hash
,
number
)
if
block
==
nil
{
break
}
blocks
=
append
(
blocks
,
block
)
hash
=
block
.
ParentHash
()
number
--
}
return
}
...
...
@@ -546,7 +553,7 @@ func (self *BlockChain) GetUnclesInChain(block *types.Block, length int) []*type
uncles
:=
[]
*
types
.
Header
{}
for
i
:=
0
;
block
!=
nil
&&
i
<
length
;
i
++
{
uncles
=
append
(
uncles
,
block
.
Uncles
()
...
)
block
=
self
.
GetBlock
(
block
.
ParentHash
())
block
=
self
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
)
}
return
uncles
}
...
...
@@ -596,15 +603,16 @@ func (self *BlockChain) Rollback(chain []common.Hash) {
for
i
:=
len
(
chain
)
-
1
;
i
>=
0
;
i
--
{
hash
:=
chain
[
i
]
if
self
.
hc
.
CurrentHeader
()
.
Hash
()
==
hash
{
self
.
hc
.
SetCurrentHeader
(
self
.
GetHeader
(
self
.
hc
.
CurrentHeader
()
.
ParentHash
))
currentHeader
:=
self
.
hc
.
CurrentHeader
()
if
currentHeader
.
Hash
()
==
hash
{
self
.
hc
.
SetCurrentHeader
(
self
.
GetHeader
(
currentHeader
.
ParentHash
,
currentHeader
.
Number
.
Uint64
()
-
1
))
}
if
self
.
currentFastBlock
.
Hash
()
==
hash
{
self
.
currentFastBlock
=
self
.
GetBlock
(
self
.
currentFastBlock
.
ParentHash
())
self
.
currentFastBlock
=
self
.
GetBlock
(
self
.
currentFastBlock
.
ParentHash
()
,
self
.
currentFastBlock
.
NumberU64
()
-
1
)
WriteHeadFastBlockHash
(
self
.
chainDb
,
self
.
currentFastBlock
.
Hash
())
}
if
self
.
currentBlock
.
Hash
()
==
hash
{
self
.
currentBlock
=
self
.
GetBlock
(
self
.
currentBlock
.
ParentHash
())
self
.
currentBlock
=
self
.
GetBlock
(
self
.
currentBlock
.
ParentHash
()
,
self
.
currentBlock
.
NumberU64
()
-
1
)
WriteHeadBlockHash
(
self
.
chainDb
,
self
.
currentBlock
.
Hash
())
}
}
...
...
@@ -678,13 +686,13 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
}
}
// Write all the data out into the database
if
err
:=
WriteBody
(
self
.
chainDb
,
block
.
Hash
(),
block
.
Body
());
err
!=
nil
{
if
err
:=
WriteBody
(
self
.
chainDb
,
block
.
Hash
(),
block
.
NumberU64
(),
block
.
Body
());
err
!=
nil
{
errs
[
index
]
=
fmt
.
Errorf
(
"failed to write block body: %v"
,
err
)
atomic
.
AddInt32
(
&
failed
,
1
)
glog
.
Fatal
(
errs
[
index
])
return
}
if
err
:=
WriteBlockReceipts
(
self
.
chainDb
,
block
.
Hash
(),
receipts
);
err
!=
nil
{
if
err
:=
WriteBlockReceipts
(
self
.
chainDb
,
block
.
Hash
(),
block
.
NumberU64
(),
receipts
);
err
!=
nil
{
errs
[
index
]
=
fmt
.
Errorf
(
"failed to write block receipts: %v"
,
err
)
atomic
.
AddInt32
(
&
failed
,
1
)
glog
.
Fatal
(
errs
[
index
])
...
...
@@ -737,7 +745,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
// Update the head fast sync block if better
self
.
mu
.
Lock
()
head
:=
blockChain
[
len
(
errs
)
-
1
]
if
self
.
GetTd
(
self
.
currentFastBlock
.
Hash
()
)
.
Cmp
(
self
.
GetTd
(
head
.
Hash
()))
<
0
{
if
self
.
GetTd
(
self
.
currentFastBlock
.
Hash
()
,
self
.
currentFastBlock
.
NumberU64
())
.
Cmp
(
self
.
GetTd
(
head
.
Hash
(),
head
.
NumberU64
()))
<
0
{
if
err
:=
WriteHeadFastBlockHash
(
self
.
chainDb
,
head
.
Hash
());
err
!=
nil
{
glog
.
Fatalf
(
"failed to update head fast block hash: %v"
,
err
)
}
...
...
@@ -759,12 +767,12 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err
defer
self
.
wg
.
Done
()
// Calculate the total difficulty of the block
ptd
:=
self
.
GetTd
(
block
.
ParentHash
())
ptd
:=
self
.
GetTd
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
)
if
ptd
==
nil
{
return
NonStatTy
,
ParentError
(
block
.
ParentHash
())
}
localTd
:=
self
.
GetTd
(
self
.
currentBlock
.
Hash
())
localTd
:=
self
.
GetTd
(
self
.
currentBlock
.
Hash
()
,
self
.
currentBlock
.
NumberU64
()
)
externTd
:=
new
(
big
.
Int
)
.
Add
(
block
.
Difficulty
(),
ptd
)
// Make sure no inconsistent state is leaked during insertion
...
...
@@ -788,7 +796,7 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err
status
=
SideStatTy
}
// Irrelevant of the canonical status, write the block itself to the database
if
err
:=
self
.
hc
.
WriteTd
(
block
.
Hash
(),
externTd
);
err
!=
nil
{
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
{
...
...
@@ -887,7 +895,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// Create a new statedb using the parent block and report an
// error if it fails.
if
statedb
==
nil
{
statedb
,
err
=
state
.
New
(
self
.
GetBlock
(
block
.
ParentHash
())
.
Root
(),
self
.
chainDb
)
statedb
,
err
=
state
.
New
(
self
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
)
.
Root
(),
self
.
chainDb
)
}
else
{
err
=
statedb
.
Reset
(
chain
[
i
-
1
]
.
Root
())
}
...
...
@@ -902,7 +910,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
return
i
,
err
}
// Validate the state using the default validator
err
=
self
.
Validator
()
.
ValidateState
(
block
,
self
.
GetBlock
(
block
.
ParentHash
()),
statedb
,
receipts
,
usedGas
)
err
=
self
.
Validator
()
.
ValidateState
(
block
,
self
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
),
statedb
,
receipts
,
usedGas
)
if
err
!=
nil
{
reportBlock
(
block
,
err
)
return
i
,
err
...
...
@@ -916,7 +924,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// coalesce logs for later processing
coalescedLogs
=
append
(
coalescedLogs
,
logs
...
)
if
err
:=
WriteBlockReceipts
(
self
.
chainDb
,
block
.
Hash
(),
receipts
);
err
!=
nil
{
if
err
:=
WriteBlockReceipts
(
self
.
chainDb
,
block
.
Hash
(),
block
.
NumberU64
(),
receipts
);
err
!=
nil
{
return
i
,
err
}
...
...
@@ -986,7 +994,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
// These logs are later announced as deleted.
collectLogs
=
func
(
h
common
.
Hash
)
{
// Coalesce logs
receipts
:=
GetBlockReceipts
(
self
.
chainDb
,
h
)
receipts
:=
GetBlockReceipts
(
self
.
chainDb
,
h
,
self
.
hc
.
GetBlockNumber
(
h
)
)
for
_
,
receipt
:=
range
receipts
{
deletedLogs
=
append
(
deletedLogs
,
receipt
.
Logs
...
)
...
...
@@ -998,7 +1006,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
// first reduce whoever is higher bound
if
oldBlock
.
NumberU64
()
>
newBlock
.
NumberU64
()
{
// reduce old chain
for
;
oldBlock
!=
nil
&&
oldBlock
.
NumberU64
()
!=
newBlock
.
NumberU64
();
oldBlock
=
self
.
GetBlock
(
oldBlock
.
ParentHash
())
{
for
;
oldBlock
!=
nil
&&
oldBlock
.
NumberU64
()
!=
newBlock
.
NumberU64
();
oldBlock
=
self
.
GetBlock
(
oldBlock
.
ParentHash
()
,
oldBlock
.
NumberU64
()
-
1
)
{
oldChain
=
append
(
oldChain
,
oldBlock
)
deletedTxs
=
append
(
deletedTxs
,
oldBlock
.
Transactions
()
...
)
...
...
@@ -1006,7 +1014,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
}
}
else
{
// reduce new chain and append new chain blocks for inserting later on
for
;
newBlock
!=
nil
&&
newBlock
.
NumberU64
()
!=
oldBlock
.
NumberU64
();
newBlock
=
self
.
GetBlock
(
newBlock
.
ParentHash
())
{
for
;
newBlock
!=
nil
&&
newBlock
.
NumberU64
()
!=
oldBlock
.
NumberU64
();
newBlock
=
self
.
GetBlock
(
newBlock
.
ParentHash
()
,
newBlock
.
NumberU64
()
-
1
)
{
newChain
=
append
(
newChain
,
newBlock
)
}
}
...
...
@@ -1029,7 +1037,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
deletedTxs
=
append
(
deletedTxs
,
oldBlock
.
Transactions
()
...
)
collectLogs
(
oldBlock
.
Hash
())
oldBlock
,
newBlock
=
self
.
GetBlock
(
oldBlock
.
ParentHash
()
),
self
.
GetBlock
(
newBlock
.
ParentHash
()
)
oldBlock
,
newBlock
=
self
.
GetBlock
(
oldBlock
.
ParentHash
()
,
oldBlock
.
NumberU64
()
-
1
),
self
.
GetBlock
(
newBlock
.
ParentHash
(),
newBlock
.
NumberU64
()
-
1
)
if
oldBlock
==
nil
{
return
fmt
.
Errorf
(
"Invalid old chain"
)
}
...
...
@@ -1052,7 +1060,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
if
err
:=
WriteTransactions
(
self
.
chainDb
,
block
);
err
!=
nil
{
return
err
}
receipts
:=
GetBlockReceipts
(
self
.
chainDb
,
block
.
Hash
())
receipts
:=
GetBlockReceipts
(
self
.
chainDb
,
block
.
Hash
()
,
block
.
NumberU64
()
)
// write receipts
if
err
:=
WriteReceipts
(
self
.
chainDb
,
receipts
);
err
!=
nil
{
return
err
...
...
@@ -1187,15 +1195,27 @@ func (self *BlockChain) CurrentHeader() *types.Header {
}
// GetTd retrieves a block's total difficulty in the canonical chain from the
// database by hash and number, caching it if found.
func
(
self
*
BlockChain
)
GetTd
(
hash
common
.
Hash
,
number
uint64
)
*
big
.
Int
{
return
self
.
hc
.
GetTd
(
hash
,
number
)
}
// GetTdByHash retrieves a block's total difficulty in the canonical chain from the
// database by hash, caching it if found.
func
(
self
*
BlockChain
)
GetTd
(
hash
common
.
Hash
)
*
big
.
Int
{
return
self
.
hc
.
GetTd
(
hash
)
func
(
self
*
BlockChain
)
GetTdByHash
(
hash
common
.
Hash
)
*
big
.
Int
{
return
self
.
hc
.
GetTdByHash
(
hash
)
}
// GetHeader retrieves a block header from the database by hash and number,
// caching it if found.
func
(
self
*
BlockChain
)
GetHeader
(
hash
common
.
Hash
,
number
uint64
)
*
types
.
Header
{
return
self
.
hc
.
GetHeader
(
hash
,
number
)
}
// GetHeader retrieves a block header from the database by hash, caching it if
// GetHeader
ByHash
retrieves a block header from the database by hash, caching it if
// found.
func
(
self
*
BlockChain
)
GetHeader
(
hash
common
.
Hash
)
*
types
.
Header
{
return
self
.
hc
.
GetHeader
(
hash
)
func
(
self
*
BlockChain
)
GetHeader
ByHash
(
hash
common
.
Hash
)
*
types
.
Header
{
return
self
.
hc
.
GetHeader
ByHash
(
hash
)
}
// HasHeader checks if a block header is present in the database or not, caching
...
...
core/blockchain_test.go
View file @
f9917c8c
...
...
@@ -102,17 +102,17 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara
var
tdPre
,
tdPost
*
big
.
Int
if
full
{
tdPre
=
blockchain
.
GetTd
(
blockchain
.
CurrentBlock
()
.
Hash
())
tdPre
=
blockchain
.
GetTd
ByHash
(
blockchain
.
CurrentBlock
()
.
Hash
())
if
err
:=
testBlockChainImport
(
blockChainB
,
blockchain
);
err
!=
nil
{
t
.
Fatalf
(
"failed to import forked block chain: %v"
,
err
)
}
tdPost
=
blockchain
.
GetTd
(
blockChainB
[
len
(
blockChainB
)
-
1
]
.
Hash
())
tdPost
=
blockchain
.
GetTd
ByHash
(
blockChainB
[
len
(
blockChainB
)
-
1
]
.
Hash
())
}
else
{
tdPre
=
blockchain
.
GetTd
(
blockchain
.
CurrentHeader
()
.
Hash
())
tdPre
=
blockchain
.
GetTd
ByHash
(
blockchain
.
CurrentHeader
()
.
Hash
())
if
err
:=
testHeaderChainImport
(
headerChainB
,
blockchain
);
err
!=
nil
{
t
.
Fatalf
(
"failed to import forked header chain: %v"
,
err
)
}
tdPost
=
blockchain
.
GetTd
(
headerChainB
[
len
(
headerChainB
)
-
1
]
.
Hash
())
tdPost
=
blockchain
.
GetTd
ByHash
(
headerChainB
[
len
(
headerChainB
)
-
1
]
.
Hash
())
}
// Compare the total difficulties of the chains
comparator
(
tdPre
,
tdPost
)
...
...
@@ -137,7 +137,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
}
return
err
}
statedb
,
err
:=
state
.
New
(
blockchain
.
GetBlock
(
block
.
ParentHash
())
.
Root
(),
blockchain
.
chainDb
)
statedb
,
err
:=
state
.
New
(
blockchain
.
GetBlock
ByHash
(
block
.
ParentHash
())
.
Root
(),
blockchain
.
chainDb
)
if
err
!=
nil
{
return
err
}
...
...
@@ -146,13 +146,13 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
reportBlock
(
block
,
err
)
return
err
}
err
=
blockchain
.
Validator
()
.
ValidateState
(
block
,
blockchain
.
GetBlock
(
block
.
ParentHash
()),
statedb
,
receipts
,
usedGas
)
err
=
blockchain
.
Validator
()
.
ValidateState
(
block
,
blockchain
.
GetBlock
ByHash
(
block
.
ParentHash
()),
statedb
,
receipts
,
usedGas
)
if
err
!=
nil
{
reportBlock
(
block
,
err
)
return
err
}
blockchain
.
mu
.
Lock
()
WriteTd
(
blockchain
.
chainDb
,
block
.
Hash
(),
new
(
big
.
Int
)
.
Add
(
block
.
Difficulty
(),
blockchain
.
GetTd
(
block
.
ParentHash
())))
WriteTd
(
blockchain
.
chainDb
,
block
.
Hash
(),
block
.
NumberU64
(),
new
(
big
.
Int
)
.
Add
(
block
.
Difficulty
(),
blockchain
.
GetTdByHash
(
block
.
ParentHash
())))
WriteBlock
(
blockchain
.
chainDb
,
block
)
statedb
.
Commit
()
blockchain
.
mu
.
Unlock
()
...
...
@@ -165,12 +165,12 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
func
testHeaderChainImport
(
chain
[]
*
types
.
Header
,
blockchain
*
BlockChain
)
error
{
for
_
,
header
:=
range
chain
{
// Try and validate the header
if
err
:=
blockchain
.
Validator
()
.
ValidateHeader
(
header
,
blockchain
.
GetHeader
(
header
.
ParentHash
),
false
);
err
!=
nil
{
if
err
:=
blockchain
.
Validator
()
.
ValidateHeader
(
header
,
blockchain
.
GetHeader
ByHash
(
header
.
ParentHash
),
false
);
err
!=
nil
{
return
err
}
// Manually insert the header into the database, but don't reorganise (allows subsequent testing)
blockchain
.
mu
.
Lock
()
WriteTd
(
blockchain
.
chainDb
,
header
.
Hash
(),
new
(
big
.
Int
)
.
Add
(
header
.
Difficulty
,
blockchain
.
GetTd
(
header
.
ParentHash
)))
WriteTd
(
blockchain
.
chainDb
,
header
.
Hash
(),
header
.
Number
.
Uint64
(),
new
(
big
.
Int
)
.
Add
(
header
.
Difficulty
,
blockchain
.
GetTdByHash
(
header
.
ParentHash
)))
WriteHeader
(
blockchain
.
chainDb
,
header
)
blockchain
.
mu
.
Unlock
()
}
...
...
@@ -543,11 +543,11 @@ func testReorg(t *testing.T, first, second []int, td int64, full bool) {
// Make sure the chain total difficulty is the correct one
want
:=
new
(
big
.
Int
)
.
Add
(
genesis
.
Difficulty
(),
big
.
NewInt
(
td
))
if
full
{
if
have
:=
bc
.
GetTd
(
bc
.
CurrentBlock
()
.
Hash
());
have
.
Cmp
(
want
)
!=
0
{
if
have
:=
bc
.
GetTd
ByHash
(
bc
.
CurrentBlock
()
.
Hash
());
have
.
Cmp
(
want
)
!=
0
{
t
.
Errorf
(
"total difficulty mismatch: have %v, want %v"
,
have
,
want
)
}
}
else
{
if
have
:=
bc
.
GetTd
(
bc
.
CurrentHeader
()
.
Hash
());
have
.
Cmp
(
want
)
!=
0
{
if
have
:=
bc
.
GetTd
ByHash
(
bc
.
CurrentHeader
()
.
Hash
());
have
.
Cmp
(
want
)
!=
0
{
t
.
Errorf
(
"total difficulty mismatch: have %v, want %v"
,
have
,
want
)
}
}
...
...
@@ -758,20 +758,20 @@ func TestFastVsFullChains(t *testing.T) {
for
i
:=
0
;
i
<
len
(
blocks
);
i
++
{
num
,
hash
:=
blocks
[
i
]
.
NumberU64
(),
blocks
[
i
]
.
Hash
()
if
ftd
,
atd
:=
fast
.
GetTd
(
hash
),
archive
.
GetTd
(
hash
);
ftd
.
Cmp
(
atd
)
!=
0
{
if
ftd
,
atd
:=
fast
.
GetTd
ByHash
(
hash
),
archive
.
GetTdByHash
(
hash
);
ftd
.
Cmp
(
atd
)
!=
0
{
t
.
Errorf
(
"block #%d [%x]: td mismatch: have %v, want %v"
,
num
,
hash
,
ftd
,
atd
)
}
if
fheader
,
aheader
:=
fast
.
GetHeader
(
hash
),
archive
.
GetHeader
(
hash
);
fheader
.
Hash
()
!=
aheader
.
Hash
()
{
if
fheader
,
aheader
:=
fast
.
GetHeader
ByHash
(
hash
),
archive
.
GetHeaderByHash
(
hash
);
fheader
.
Hash
()
!=
aheader
.
Hash
()
{
t
.
Errorf
(
"block #%d [%x]: header mismatch: have %v, want %v"
,
num
,
hash
,
fheader
,
aheader
)
}
if
fblock
,
ablock
:=
fast
.
GetBlock
(
hash
),
archive
.
GetBlock
(
hash
);
fblock
.
Hash
()
!=
ablock
.
Hash
()
{
if
fblock
,
ablock
:=
fast
.
GetBlock
ByHash
(
hash
),
archive
.
GetBlockByHash
(
hash
);
fblock
.
Hash
()
!=
ablock
.
Hash
()
{
t
.
Errorf
(
"block #%d [%x]: block mismatch: have %v, want %v"
,
num
,
hash
,
fblock
,
ablock
)
}
else
if
types
.
DeriveSha
(
fblock
.
Transactions
())
!=
types
.
DeriveSha
(
ablock
.
Transactions
())
{
t
.
Errorf
(
"block #%d [%x]: transactions mismatch: have %v, want %v"
,
num
,
hash
,
fblock
.
Transactions
(),
ablock
.
Transactions
())
}
else
if
types
.
CalcUncleHash
(
fblock
.
Uncles
())
!=
types
.
CalcUncleHash
(
ablock
.
Uncles
())
{
t
.
Errorf
(
"block #%d [%x]: uncles mismatch: have %v, want %v"
,
num
,
hash
,
fblock
.
Uncles
(),
ablock
.
Uncles
())
}
if
freceipts
,
areceipts
:=
GetBlockReceipts
(
fastDb
,
hash
),
GetBlockReceipts
(
archiveDb
,
hash
);
types
.
DeriveSha
(
freceipts
)
!=
types
.
DeriveSha
(
areceipts
)
{
if
freceipts
,
areceipts
:=
GetBlockReceipts
(
fastDb
,
hash
,
GetBlockNumber
(
fastDb
,
hash
)),
GetBlockReceipts
(
archiveDb
,
hash
,
GetBlockNumber
(
archiveDb
,
hash
)
);
types
.
DeriveSha
(
freceipts
)
!=
types
.
DeriveSha
(
areceipts
)
{
t
.
Errorf
(
"block #%d [%x]: receipts mismatch: have %v, want %v"
,
num
,
hash
,
freceipts
,
areceipts
)
}
}
...
...
core/database_util.go
View file @
f9917c8c
...
...
@@ -36,34 +36,72 @@ var (
headBlockKey
=
[]
byte
(
"LastBlock"
)
headFastKey
=
[]
byte
(
"LastFast"
)
blockPrefix
=
[]
byte
(
"block-"
)
blockNumPrefix
=
[]
byte
(
"block-num-"
)
headerSuffix
=
[]
byte
(
"-header"
)
body
Suffix
=
[]
byte
(
"-body"
)
tdSuffix
=
[]
byte
(
"-td"
)
headerPrefix
=
[]
byte
(
"h"
)
// headerPrefix + num (uint64 big endian) + hash -> header
tdSuffix
=
[]
byte
(
"t"
)
// headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td
numSuffix
=
[]
byte
(
"n"
)
// headerPrefix + num (uint64 big endian) + numSuffix -> hash
blockHashPrefix
=
[]
byte
(
"H"
)
// blockHashPrefix + hash -> num (uint64 big endian
)
body
Prefix
=
[]
byte
(
"b"
)
// bodyPrefix + num (uint64 big endian) + hash -> block body
blockReceiptsPrefix
=
[]
byte
(
"r"
)
// blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
txMetaSuffix
=
[]
byte
{
0x01
}
receiptsPrefix
=
[]
byte
(
"receipts-"
)
blockReceiptsPrefix
=
[]
byte
(
"receipts-block-"
)
mipmapPre
=
[]
byte
(
"mipmap-log-bloom-"
)
MIPMapLevels
=
[]
uint64
{
1000000
,
500000
,
100000
,
50000
,
1000
}
blockHashPrefix
=
[]
byte
(
"block-hash-"
)
// [deprecated by the header/block split, remove eventually]
configPrefix
=
[]
byte
(
"ethereum-config-"
)
// config prefix for the db
// used by old (non-sequential keys) db, now only used for conversion
oldBlockPrefix
=
[]
byte
(
"block-"
)
oldHeaderSuffix
=
[]
byte
(
"-header"
)
oldTdSuffix
=
[]
byte
(
"-td"
)
// headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td
oldBodySuffix
=
[]
byte
(
"-body"
)
oldBlockNumPrefix
=
[]
byte
(
"block-num-"
)
oldBlockReceiptsPrefix
=
[]
byte
(
"receipts-block-"
)
oldBlockHashPrefix
=
[]
byte
(
"block-hash-"
)
// [deprecated by the header/block split, remove eventually]
)
// encodeBlockNumber encodes a block number as big endian uint64
func
encodeBlockNumber
(
number
uint64
)
[]
byte
{
enc
:=
make
([]
byte
,
8
)
binary
.
BigEndian
.
PutUint64
(
enc
,
number
)
return
enc
}
// GetCanonicalHash retrieves a hash assigned to a canonical block number.
func
GetCanonicalHash
(
db
ethdb
.
Database
,
number
uint64
)
common
.
Hash
{
data
,
_
:=
db
.
Get
(
append
(
blockNumPrefix
,
big
.
NewInt
(
int64
(
number
))
.
Bytes
()
...
))
data
,
_
:=
db
.
Get
(
append
(
append
(
headerPrefix
,
encodeBlockNumber
(
number
)
...
),
numSuffix
...
))
if
len
(
data
)
==
0
{
data
,
_
=
db
.
Get
(
append
(
oldBlockNumPrefix
,
big
.
NewInt
(
int64
(
number
))
.
Bytes
()
...
))
if
len
(
data
)
==
0
{
return
common
.
Hash
{}
}
}
return
common
.
BytesToHash
(
data
)
}
// missingNumber is returned by GetBlockNumber if no header with the
// given block hash has been stored in the database
const
missingNumber
=
uint64
(
0xffffffffffffffff
)
// GetBlockNumber returns the block number assigned to a block hash
// if the corresponding header is present in the database
func
GetBlockNumber
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
uint64
{
data
,
_
:=
db
.
Get
(
append
(
blockHashPrefix
,
hash
.
Bytes
()
...
))
if
len
(
data
)
!=
8
{
data
,
_
:=
db
.
Get
(
append
(
append
(
oldBlockPrefix
,
hash
.
Bytes
()
...
),
oldHeaderSuffix
...
))
if
len
(
data
)
==
0
{
return
missingNumber
}
header
:=
new
(
types
.
Header
)
if
err
:=
rlp
.
Decode
(
bytes
.
NewReader
(
data
),
header
);
err
!=
nil
{
glog
.
Fatalf
(
"failed to decode block header: %v"
,
err
)
}
return
header
.
Number
.
Uint64
()
}
return
binary
.
BigEndian
.
Uint64
(
data
)
}
// GetHeadHeaderHash retrieves the hash of the current canonical head block's
// header. The difference between this and GetHeadBlockHash is that whereas the
// last block hash is only updated upon a full block import, the last header
...
...
@@ -100,15 +138,18 @@ func GetHeadFastBlockHash(db ethdb.Database) common.Hash {
// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil
// if the header's not found.
func
GetHeaderRLP
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
rlp
.
RawValue
{
data
,
_
:=
db
.
Get
(
append
(
append
(
blockPrefix
,
hash
[
:
]
...
),
headerSuffix
...
))
func
GetHeaderRLP
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
rlp
.
RawValue
{
data
,
_
:=
db
.
Get
(
append
(
append
(
headerPrefix
,
encodeBlockNumber
(
number
)
...
),
hash
.
Bytes
()
...
))
if
len
(
data
)
==
0
{
data
,
_
=
db
.
Get
(
append
(
append
(
oldBlockPrefix
,
hash
.
Bytes
()
...
),
oldHeaderSuffix
...
))
}
return
data
}
// GetHeader retrieves the block header corresponding to the hash, nil if none
// found.
func
GetHeader
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
*
types
.
Header
{
data
:=
GetHeaderRLP
(
db
,
hash
)
func
GetHeader
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
*
types
.
Header
{
data
:=
GetHeaderRLP
(
db
,
hash
,
number
)
if
len
(
data
)
==
0
{
return
nil
}
...
...
@@ -121,15 +162,18 @@ func GetHeader(db ethdb.Database, hash common.Hash) *types.Header {
}
// GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
func
GetBodyRLP
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
rlp
.
RawValue
{
data
,
_
:=
db
.
Get
(
append
(
append
(
blockPrefix
,
hash
[
:
]
...
),
bodySuffix
...
))
func
GetBodyRLP
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
rlp
.
RawValue
{
data
,
_
:=
db
.
Get
(
append
(
append
(
bodyPrefix
,
encodeBlockNumber
(
number
)
...
),
hash
.
Bytes
()
...
))
if
len
(
data
)
==
0
{
data
,
_
=
db
.
Get
(
append
(
append
(
oldBlockPrefix
,
hash
.
Bytes
()
...
),
oldBodySuffix
...
))
}
return
data
}
// GetBody retrieves the block body (transactons, uncles) corresponding to the
// hash, nil if none found.
func
GetBody
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
*
types
.
Body
{
data
:=
GetBodyRLP
(
db
,
hash
)
func
GetBody
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
*
types
.
Body
{
data
:=
GetBodyRLP
(
db
,
hash
,
number
)
if
len
(
data
)
==
0
{
return
nil
}
...
...
@@ -143,11 +187,14 @@ func GetBody(db ethdb.Database, hash common.Hash) *types.Body {
// GetTd retrieves a block's total difficulty corresponding to the hash, nil if
// none found.
func
GetTd
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
*
big
.
Int
{
data
,
_
:=
db
.
Get
(
append
(
append
(
blockPrefix
,
hash
.
Bytes
()
...
),
tdSuffix
...
))
func
GetTd
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
*
big
.
Int
{
data
,
_
:=
db
.
Get
(
append
(
append
(
append
(
headerPrefix
,
encodeBlockNumber
(
number
)
...
),
hash
[
:
]
...
),
tdSuffix
...
))
if
len
(
data
)
==
0
{
data
,
_
=
db
.
Get
(
append
(
append
(
oldBlockPrefix
,
hash
.
Bytes
()
...
),
oldTdSuffix
...
))
if
len
(
data
)
==
0
{
return
nil
}
}
td
:=
new
(
big
.
Int
)
if
err
:=
rlp
.
Decode
(
bytes
.
NewReader
(
data
),
td
);
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"invalid block total difficulty RLP for hash %x: %v"
,
hash
,
err
)
...
...
@@ -158,13 +205,13 @@ func GetTd(db ethdb.Database, hash common.Hash) *big.Int {
// GetBlock retrieves an entire block corresponding to the hash, assembling it
// back from the stored header and body.
func
GetBlock
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
*
types
.
Block
{
func
GetBlock
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
*
types
.
Block
{
// Retrieve the block header and body contents
header
:=
GetHeader
(
db
,
hash
)
header
:=
GetHeader
(
db
,
hash
,
number
)
if
header
==
nil
{
return
nil
}
body
:=
GetBody
(
db
,
hash
)
body
:=
GetBody
(
db
,
hash
,
number
)
if
body
==
nil
{
return
nil
}
...
...
@@ -174,11 +221,14 @@ func GetBlock(db ethdb.Database, hash common.Hash) *types.Block {
// GetBlockReceipts retrieves the receipts generated by the transactions included
// in a block given by its hash.
func
GetBlockReceipts
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
types
.
Receipts
{
data
,
_
:=
db
.
Get
(
append
(
blockReceiptsPrefix
,
hash
[
:
]
...
))
func
GetBlockReceipts
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
types
.
Receipts
{
data
,
_
:=
db
.
Get
(
append
(
append
(
blockReceiptsPrefix
,
encodeBlockNumber
(
number
)
...
),
hash
[
:
]
...
))
if
len
(
data
)
==
0
{
data
,
_
=
db
.
Get
(
append
(
oldBlockReceiptsPrefix
,
hash
.
Bytes
()
...
))
if
len
(
data
)
==
0
{
return
nil
}
}
storageReceipts
:=
[]
*
types
.
ReceiptForStorage
{}
if
err
:=
rlp
.
DecodeBytes
(
data
,
&
storageReceipts
);
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"invalid receipt array RLP for hash %x: %v"
,
hash
,
err
)
...
...
@@ -235,10 +285,9 @@ func GetReceipt(db ethdb.Database, txHash common.Hash) *types.Receipt {
// WriteCanonicalHash stores the canonical hash for the given block number.
func
WriteCanonicalHash
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
error
{
key
:=
append
(
blockNumPrefix
,
big
.
NewInt
(
int64
(
number
))
.
Bytes
()
...
)
key
:=
append
(
append
(
headerPrefix
,
encodeBlockNumber
(
number
)
...
),
numSuffix
...
)
if
err
:=
db
.
Put
(
key
,
hash
.
Bytes
());
err
!=
nil
{
glog
.
Fatalf
(
"failed to store number to hash mapping into database: %v"
,
err
)
return
err
}
return
nil
}
...
...
@@ -247,7 +296,6 @@ func WriteCanonicalHash(db ethdb.Database, hash common.Hash, number uint64) erro
func
WriteHeadHeaderHash
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
error
{
if
err
:=
db
.
Put
(
headHeaderKey
,
hash
.
Bytes
());
err
!=
nil
{
glog
.
Fatalf
(
"failed to store last header's hash into database: %v"
,
err
)
return
err
}
return
nil
}
...
...
@@ -256,7 +304,6 @@ func WriteHeadHeaderHash(db ethdb.Database, hash common.Hash) error {
func
WriteHeadBlockHash
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
error
{
if
err
:=
db
.
Put
(
headBlockKey
,
hash
.
Bytes
());
err
!=
nil
{
glog
.
Fatalf
(
"failed to store last block's hash into database: %v"
,
err
)
return
err
}
return
nil
}
...
...
@@ -265,7 +312,6 @@ func WriteHeadBlockHash(db ethdb.Database, hash common.Hash) error {
func
WriteHeadFastBlockHash
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
error
{
if
err
:=
db
.
Put
(
headFastKey
,
hash
.
Bytes
());
err
!=
nil
{
glog
.
Fatalf
(
"failed to store last fast block's hash into database: %v"
,
err
)
return
err
}
return
nil
}
...
...
@@ -276,40 +322,44 @@ func WriteHeader(db ethdb.Database, header *types.Header) error {
if
err
!=
nil
{
return
err
}
key
:=
append
(
append
(
blockPrefix
,
header
.
Hash
()
.
Bytes
()
...
),
headerSuffix
...
)
hash
:=
header
.
Hash
()
.
Bytes
()
num
:=
header
.
Number
.
Uint64
()
encNum
:=
encodeBlockNumber
(
num
)
key
:=
append
(
blockHashPrefix
,
hash
...
)
if
err
:=
db
.
Put
(
key
,
encNum
);
err
!=
nil
{
glog
.
Fatalf
(
"failed to store hash to number mapping into database: %v"
,
err
)
}
key
=
append
(
append
(
headerPrefix
,
encNum
...
),
hash
...
)
if
err
:=
db
.
Put
(
key
,
data
);
err
!=
nil
{
glog
.
Fatalf
(
"failed to store header into database: %v"
,
err
)
return
err
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"stored header #%v [%x…]"
,
header
.
Number
,
h
eader
.
Hash
()
.
Bytes
()
[
:
4
])
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"stored header #%v [%x…]"
,
header
.
Number
,
h
ash
[
:
4
])
return
nil
}
// WriteBody serializes the body of a block into the database.
func
WriteBody
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
body
*
types
.
Body
)
error
{
func
WriteBody
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
,
body
*
types
.
Body
)
error
{
data
,
err
:=
rlp
.
EncodeToBytes
(
body
)
if
err
!=
nil
{
return
err
}
key
:=
append
(
append
(
b
lockPrefix
,
hash
.
Bytes
()
...
),
bodySuffix
...
)
key
:=
append
(
append
(
b
odyPrefix
,
encodeBlockNumber
(
number
)
...
),
hash
.
Bytes
()
...
)
if
err
:=
db
.
Put
(
key
,
data
);
err
!=
nil
{
glog
.
Fatalf
(
"failed to store block body into database: %v"
,
err
)
return
err
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"stored block body [%x…]"
,
hash
.
Bytes
()[
:
4
])
return
nil
}
// WriteTd serializes the total difficulty of a block into the database.
func
WriteTd
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
td
*
big
.
Int
)
error
{
func
WriteTd
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
,
td
*
big
.
Int
)
error
{
data
,
err
:=
rlp
.
EncodeToBytes
(
td
)
if
err
!=
nil
{
return
err
}
key
:=
append
(
append
(
blockPrefix
,
hash
.
Bytes
()
...
),
tdSuffix
...
)
key
:=
append
(
append
(
append
(
headerPrefix
,
encodeBlockNumber
(
number
)
...
)
,
hash
.
Bytes
()
...
),
tdSuffix
...
)
if
err
:=
db
.
Put
(
key
,
data
);
err
!=
nil
{
glog
.
Fatalf
(
"failed to store block total difficulty into database: %v"
,
err
)
return
err
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"stored block total difficulty [%x…]: %v"
,
hash
.
Bytes
()[
:
4
],
td
)
return
nil
...
...
@@ -318,7 +368,7 @@ func WriteTd(db ethdb.Database, hash common.Hash, td *big.Int) error {
// WriteBlock serializes a block into the database, header and body separately.
func
WriteBlock
(
db
ethdb
.
Database
,
block
*
types
.
Block
)
error
{
// Store the body first to retain database consistency
if
err
:=
WriteBody
(
db
,
block
.
Hash
(),
block
.
Body
());
err
!=
nil
{
if
err
:=
WriteBody
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
block
.
Body
());
err
!=
nil
{
return
err
}
// Store the header too, signaling full block ownership
...
...
@@ -331,7 +381,7 @@ func WriteBlock(db ethdb.Database, block *types.Block) error {
// WriteBlockReceipts stores all the transaction receipts belonging to a block
// as a single receipt slice. This is used during chain reorganisations for
// rescheduling dropped transactions.
func
WriteBlockReceipts
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
receipts
types
.
Receipts
)
error
{
func
WriteBlockReceipts
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
,
receipts
types
.
Receipts
)
error
{
// Convert the receipts into their storage form and serialize them
storageReceipts
:=
make
([]
*
types
.
ReceiptForStorage
,
len
(
receipts
))
for
i
,
receipt
:=
range
receipts
{
...
...
@@ -342,9 +392,9 @@ func WriteBlockReceipts(db ethdb.Database, hash common.Hash, receipts types.Rece
return
err
}
// Store the flattened receipt slice
if
err
:=
db
.
Put
(
append
(
blockReceiptsPrefix
,
hash
.
Bytes
()
...
),
bytes
);
err
!=
nil
{
key
:=
append
(
append
(
blockReceiptsPrefix
,
encodeBlockNumber
(
number
)
...
),
hash
.
Bytes
()
...
)
if
err
:=
db
.
Put
(
key
,
bytes
);
err
!=
nil
{
glog
.
Fatalf
(
"failed to store block receipts into database: %v"
,
err
)
return
err
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"stored block receipts [%x…]"
,
hash
.
Bytes
()[
:
4
])
return
nil
...
...
@@ -388,7 +438,6 @@ func WriteTransactions(db ethdb.Database, block *types.Block) error {
// Write the scheduled data into the database
if
err
:=
batch
.
Write
();
err
!=
nil
{
glog
.
Fatalf
(
"failed to store transactions into database: %v"
,
err
)
return
err
}
return
nil
}
...
...
@@ -411,42 +460,42 @@ func WriteReceipts(db ethdb.Database, receipts types.Receipts) error {
// Write the scheduled data into the database
if
err
:=
batch
.
Write
();
err
!=
nil
{
glog
.
Fatalf
(
"failed to store receipts into database: %v"
,
err
)
return
err
}
return
nil
}
// DeleteCanonicalHash removes the number to hash canonical mapping.
func
DeleteCanonicalHash
(
db
ethdb
.
Database
,
number
uint64
)
{
db
.
Delete
(
append
(
blockNumPrefix
,
big
.
NewInt
(
int64
(
number
))
.
Bytes
()
...
))
db
.
Delete
(
append
(
append
(
headerPrefix
,
encodeBlockNumber
(
number
)
...
),
numSuffix
...
))
}
// DeleteHeader removes all block header data associated with a hash.
func
DeleteHeader
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
{
db
.
Delete
(
append
(
append
(
blockPrefix
,
hash
.
Bytes
()
...
),
headerSuffix
...
))
func
DeleteHeader
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
{
db
.
Delete
(
append
(
blockHashPrefix
,
hash
.
Bytes
()
...
))
db
.
Delete
(
append
(
append
(
headerPrefix
,
encodeBlockNumber
(
number
)
...
),
hash
.
Bytes
()
...
))
}
// DeleteBody removes all block body data associated with a hash.
func
DeleteBody
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
{
db
.
Delete
(
append
(
append
(
b
lockPrefix
,
hash
.
Bytes
()
...
),
bodySuffix
...
))
func
DeleteBody
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
{
db
.
Delete
(
append
(
append
(
b
odyPrefix
,
encodeBlockNumber
(
number
)
...
),
hash
.
Bytes
()
...
))
}
// DeleteTd removes all block total difficulty data associated with a hash.
func
DeleteTd
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
{
db
.
Delete
(
append
(
append
(
blockPrefix
,
hash
.
Bytes
()
...
),
tdSuffix
...
))
func
DeleteTd
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
{
db
.
Delete
(
append
(
append
(
append
(
headerPrefix
,
encodeBlockNumber
(
number
)
...
)
,
hash
.
Bytes
()
...
),
tdSuffix
...
))
}
// DeleteBlock removes all block data associated with a hash.
func
DeleteBlock
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
{
DeleteBlockReceipts
(
db
,
hash
)
DeleteHeader
(
db
,
hash
)
DeleteBody
(
db
,
hash
)
DeleteTd
(
db
,
hash
)
func
DeleteBlock
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
{
DeleteBlockReceipts
(
db
,
hash
,
number
)
DeleteHeader
(
db
,
hash
,
number
)
DeleteBody
(
db
,
hash
,
number
)
DeleteTd
(
db
,
hash
,
number
)
}
// DeleteBlockReceipts removes all receipt data associated with a block hash.
func
DeleteBlockReceipts
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
{
db
.
Delete
(
append
(
blockReceiptsPrefix
,
hash
.
Bytes
()
...
))
func
DeleteBlockReceipts
(
db
ethdb
.
Database
,
hash
common
.
Hash
,
number
uint64
)
{
db
.
Delete
(
append
(
append
(
blockReceiptsPrefix
,
encodeBlockNumber
(
number
)
...
)
,
hash
.
Bytes
()
...
))
}
// DeleteTransaction removes all transaction data associated with a hash.
...
...
@@ -466,7 +515,7 @@ func DeleteReceipt(db ethdb.Database, hash common.Hash) {
// access the old combined block representation. It will be dropped after the
// network transitions to eth/63.
func
GetBlockByHashOld
(
db
ethdb
.
Database
,
hash
common
.
Hash
)
*
types
.
Block
{
data
,
_
:=
db
.
Get
(
append
(
b
lockHashPrefix
,
hash
[
:
]
...
))
data
,
_
:=
db
.
Get
(
append
(
oldB
lockHashPrefix
,
hash
[
:
]
...
))
if
len
(
data
)
==
0
{
return
nil
}
...
...
core/database_util_test.go
View file @
f9917c8c
...
...
@@ -89,20 +89,20 @@ func TestHeaderStorage(t *testing.T) {
db
,
_
:=
ethdb
.
NewMemDatabase
()
// Create a test header to move around the database and make sure it's really new
header
:=
&
types
.
Header
{
Extra
:
[]
byte
(
"test header"
)}
if
entry
:=
GetHeader
(
db
,
header
.
Hash
());
entry
!=
nil
{
header
:=
&
types
.
Header
{
Number
:
big
.
NewInt
(
42
),
Extra
:
[]
byte
(
"test header"
)}
if
entry
:=
GetHeader
(
db
,
header
.
Hash
()
,
header
.
Number
.
Uint64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Non existent header returned: %v"
,
entry
)
}
// Write and verify the header in the database
if
err
:=
WriteHeader
(
db
,
header
);
err
!=
nil
{
t
.
Fatalf
(
"Failed to write header into database: %v"
,
err
)
}
if
entry
:=
GetHeader
(
db
,
header
.
Hash
());
entry
==
nil
{
if
entry
:=
GetHeader
(
db
,
header
.
Hash
()
,
header
.
Number
.
Uint64
()
);
entry
==
nil
{
t
.
Fatalf
(
"Stored header not found"
)
}
else
if
entry
.
Hash
()
!=
header
.
Hash
()
{
t
.
Fatalf
(
"Retrieved header mismatch: have %v, want %v"
,
entry
,
header
)
}
if
entry
:=
GetHeaderRLP
(
db
,
header
.
Hash
());
entry
==
nil
{
if
entry
:=
GetHeaderRLP
(
db
,
header
.
Hash
()
,
header
.
Number
.
Uint64
()
);
entry
==
nil
{
t
.
Fatalf
(
"Stored header RLP not found"
)
}
else
{
hasher
:=
sha3
.
NewKeccak256
()
...
...
@@ -113,8 +113,8 @@ func TestHeaderStorage(t *testing.T) {
}
}
// Delete the header and verify the execution
DeleteHeader
(
db
,
header
.
Hash
())
if
entry
:=
GetHeader
(
db
,
header
.
Hash
());
entry
!=
nil
{
DeleteHeader
(
db
,
header
.
Hash
()
,
header
.
Number
.
Uint64
()
)
if
entry
:=
GetHeader
(
db
,
header
.
Hash
()
,
header
.
Number
.
Uint64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Deleted header returned: %v"
,
entry
)
}
}
...
...
@@ -130,19 +130,19 @@ func TestBodyStorage(t *testing.T) {
rlp
.
Encode
(
hasher
,
body
)
hash
:=
common
.
BytesToHash
(
hasher
.
Sum
(
nil
))
if
entry
:=
GetBody
(
db
,
hash
);
entry
!=
nil
{
if
entry
:=
GetBody
(
db
,
hash
,
0
);
entry
!=
nil
{
t
.
Fatalf
(
"Non existent body returned: %v"
,
entry
)
}
// Write and verify the body in the database
if
err
:=
WriteBody
(
db
,
hash
,
body
);
err
!=
nil
{
if
err
:=
WriteBody
(
db
,
hash
,
0
,
body
);
err
!=
nil
{
t
.
Fatalf
(
"Failed to write body into database: %v"
,
err
)
}
if
entry
:=
GetBody
(
db
,
hash
);
entry
==
nil
{
if
entry
:=
GetBody
(
db
,
hash
,
0
);
entry
==
nil
{
t
.
Fatalf
(
"Stored body not found"
)
}
else
if
types
.
DeriveSha
(
types
.
Transactions
(
entry
.
Transactions
))
!=
types
.
DeriveSha
(
types
.
Transactions
(
body
.
Transactions
))
||
types
.
CalcUncleHash
(
entry
.
Uncles
)
!=
types
.
CalcUncleHash
(
body
.
Uncles
)
{
t
.
Fatalf
(
"Retrieved body mismatch: have %v, want %v"
,
entry
,
body
)
}
if
entry
:=
GetBodyRLP
(
db
,
hash
);
entry
==
nil
{
if
entry
:=
GetBodyRLP
(
db
,
hash
,
0
);
entry
==
nil
{
t
.
Fatalf
(
"Stored body RLP not found"
)
}
else
{
hasher
:=
sha3
.
NewKeccak256
()
...
...
@@ -153,8 +153,8 @@ func TestBodyStorage(t *testing.T) {
}
}
// Delete the body and verify the execution
DeleteBody
(
db
,
hash
)
if
entry
:=
GetBody
(
db
,
hash
);
entry
!=
nil
{
DeleteBody
(
db
,
hash
,
0
)
if
entry
:=
GetBody
(
db
,
hash
,
0
);
entry
!=
nil
{
t
.
Fatalf
(
"Deleted body returned: %v"
,
entry
)
}
}
...
...
@@ -170,43 +170,43 @@ func TestBlockStorage(t *testing.T) {
TxHash
:
types
.
EmptyRootHash
,
ReceiptHash
:
types
.
EmptyRootHash
,
})
if
entry
:=
GetBlock
(
db
,
block
.
Hash
());
entry
!=
nil
{
if
entry
:=
GetBlock
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Non existent block returned: %v"
,
entry
)
}
if
entry
:=
GetHeader
(
db
,
block
.
Hash
());
entry
!=
nil
{
if
entry
:=
GetHeader
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Non existent header returned: %v"
,
entry
)
}
if
entry
:=
GetBody
(
db
,
block
.
Hash
());
entry
!=
nil
{
if
entry
:=
GetBody
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Non existent body returned: %v"
,
entry
)
}
// Write and verify the block in the database
if
err
:=
WriteBlock
(
db
,
block
);
err
!=
nil
{
t
.
Fatalf
(
"Failed to write block into database: %v"
,
err
)
}
if
entry
:=
GetBlock
(
db
,
block
.
Hash
());
entry
==
nil
{
if
entry
:=
GetBlock
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
==
nil
{
t
.
Fatalf
(
"Stored block not found"
)
}
else
if
entry
.
Hash
()
!=
block
.
Hash
()
{
t
.
Fatalf
(
"Retrieved block mismatch: have %v, want %v"
,
entry
,
block
)
}
if
entry
:=
GetHeader
(
db
,
block
.
Hash
());
entry
==
nil
{
if
entry
:=
GetHeader
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
==
nil
{
t
.
Fatalf
(
"Stored header not found"
)
}
else
if
entry
.
Hash
()
!=
block
.
Header
()
.
Hash
()
{
t
.
Fatalf
(
"Retrieved header mismatch: have %v, want %v"
,
entry
,
block
.
Header
())
}
if
entry
:=
GetBody
(
db
,
block
.
Hash
());
entry
==
nil
{
if
entry
:=
GetBody
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
==
nil
{
t
.
Fatalf
(
"Stored body not found"
)
}
else
if
types
.
DeriveSha
(
types
.
Transactions
(
entry
.
Transactions
))
!=
types
.
DeriveSha
(
block
.
Transactions
())
||
types
.
CalcUncleHash
(
entry
.
Uncles
)
!=
types
.
CalcUncleHash
(
block
.
Uncles
())
{
t
.
Fatalf
(
"Retrieved body mismatch: have %v, want %v"
,
entry
,
block
.
Body
())
}
// Delete the block and verify the execution
DeleteBlock
(
db
,
block
.
Hash
())
if
entry
:=
GetBlock
(
db
,
block
.
Hash
());
entry
!=
nil
{
DeleteBlock
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
)
if
entry
:=
GetBlock
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Deleted block returned: %v"
,
entry
)
}
if
entry
:=
GetHeader
(
db
,
block
.
Hash
());
entry
!=
nil
{
if
entry
:=
GetHeader
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Deleted header returned: %v"
,
entry
)
}
if
entry
:=
GetBody
(
db
,
block
.
Hash
());
entry
!=
nil
{
if
entry
:=
GetBody
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Deleted body returned: %v"
,
entry
)
}
}
...
...
@@ -224,28 +224,28 @@ func TestPartialBlockStorage(t *testing.T) {
if
err
:=
WriteHeader
(
db
,
block
.
Header
());
err
!=
nil
{
t
.
Fatalf
(
"Failed to write header into database: %v"
,
err
)
}
if
entry
:=
GetBlock
(
db
,
block
.
Hash
());
entry
!=
nil
{
if
entry
:=
GetBlock
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Non existent block returned: %v"
,
entry
)
}
DeleteHeader
(
db
,
block
.
Hash
())
DeleteHeader
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
)
// Store a body and check that it's not recognized as a block
if
err
:=
WriteBody
(
db
,
block
.
Hash
(),
block
.
Body
());
err
!=
nil
{
if
err
:=
WriteBody
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
block
.
Body
());
err
!=
nil
{
t
.
Fatalf
(
"Failed to write body into database: %v"
,
err
)
}
if
entry
:=
GetBlock
(
db
,
block
.
Hash
());
entry
!=
nil
{
if
entry
:=
GetBlock
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
!=
nil
{
t
.
Fatalf
(
"Non existent block returned: %v"
,
entry
)
}
DeleteBody
(
db
,
block
.
Hash
())
DeleteBody
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
)
// Store a header and a body separately and check reassembly
if
err
:=
WriteHeader
(
db
,
block
.
Header
());
err
!=
nil
{
t
.
Fatalf
(
"Failed to write header into database: %v"
,
err
)
}
if
err
:=
WriteBody
(
db
,
block
.
Hash
(),
block
.
Body
());
err
!=
nil
{
if
err
:=
WriteBody
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
block
.
Body
());
err
!=
nil
{
t
.
Fatalf
(
"Failed to write body into database: %v"
,
err
)
}
if
entry
:=
GetBlock
(
db
,
block
.
Hash
());
entry
==
nil
{
if
entry
:=
GetBlock
(
db
,
block
.
Hash
()
,
block
.
NumberU64
()
);
entry
==
nil
{
t
.
Fatalf
(
"Stored block not found"
)
}
else
if
entry
.
Hash
()
!=
block
.
Hash
()
{
t
.
Fatalf
(
"Retrieved block mismatch: have %v, want %v"
,
entry
,
block
)
...
...
@@ -258,21 +258,21 @@ func TestTdStorage(t *testing.T) {
// Create a test TD to move around the database and make sure it's really new
hash
,
td
:=
common
.
Hash
{},
big
.
NewInt
(
314
)
if
entry
:=
GetTd
(
db
,
hash
);
entry
!=
nil
{
if
entry
:=
GetTd
(
db
,
hash
,
0
);
entry
!=
nil
{
t
.
Fatalf
(
"Non existent TD returned: %v"
,
entry
)
}
// Write and verify the TD in the database
if
err
:=
WriteTd
(
db
,
hash
,
td
);
err
!=
nil
{
if
err
:=
WriteTd
(
db
,
hash
,
0
,
td
);
err
!=
nil
{
t
.
Fatalf
(
"Failed to write TD into database: %v"
,
err
)
}
if
entry
:=
GetTd
(
db
,
hash
);
entry
==
nil
{
if
entry
:=
GetTd
(
db
,
hash
,
0
);
entry
==
nil
{
t
.
Fatalf
(
"Stored TD not found"
)
}
else
if
entry
.
Cmp
(
td
)
!=
0
{
t
.
Fatalf
(
"Retrieved TD mismatch: have %v, want %v"
,
entry
,
td
)
}
// Delete the TD and verify the execution
DeleteTd
(
db
,
hash
)
if
entry
:=
GetTd
(
db
,
hash
);
entry
!=
nil
{
DeleteTd
(
db
,
hash
,
0
)
if
entry
:=
GetTd
(
db
,
hash
,
0
);
entry
!=
nil
{
t
.
Fatalf
(
"Deleted TD returned: %v"
,
entry
)
}
}
...
...
@@ -473,14 +473,14 @@ func TestBlockReceiptStorage(t *testing.T) {
// Check that no receipt entries are in a pristine database
hash
:=
common
.
BytesToHash
([]
byte
{
0x03
,
0x14
})
if
rs
:=
GetBlockReceipts
(
db
,
hash
);
len
(
rs
)
!=
0
{
if
rs
:=
GetBlockReceipts
(
db
,
hash
,
0
);
len
(
rs
)
!=
0
{
t
.
Fatalf
(
"non existent receipts returned: %v"
,
rs
)
}
// Insert the receipt slice into the database and check presence
if
err
:=
WriteBlockReceipts
(
db
,
hash
,
receipts
);
err
!=
nil
{
if
err
:=
WriteBlockReceipts
(
db
,
hash
,
0
,
receipts
);
err
!=
nil
{
t
.
Fatalf
(
"failed to write block receipts: %v"
,
err
)
}
if
rs
:=
GetBlockReceipts
(
db
,
hash
);
len
(
rs
)
==
0
{
if
rs
:=
GetBlockReceipts
(
db
,
hash
,
0
);
len
(
rs
)
==
0
{
t
.
Fatalf
(
"no receipts returned"
)
}
else
{
for
i
:=
0
;
i
<
len
(
receipts
);
i
++
{
...
...
@@ -493,8 +493,8 @@ func TestBlockReceiptStorage(t *testing.T) {
}
}
// Delete the receipt slice and check purge
DeleteBlockReceipts
(
db
,
hash
)
if
rs
:=
GetBlockReceipts
(
db
,
hash
);
len
(
rs
)
!=
0
{
DeleteBlockReceipts
(
db
,
hash
,
0
)
if
rs
:=
GetBlockReceipts
(
db
,
hash
,
0
);
len
(
rs
)
!=
0
{
t
.
Fatalf
(
"deleted receipts returned: %v"
,
rs
)
}
}
...
...
@@ -597,7 +597,7 @@ func TestMipmapChain(t *testing.T) {
if
err
:=
WriteHeadBlockHash
(
db
,
block
.
Hash
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
}
if
err
:=
WriteBlockReceipts
(
db
,
block
.
Hash
(),
receipts
[
i
]);
err
!=
nil
{
if
err
:=
WriteBlockReceipts
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
receipts
[
i
]);
err
!=
nil
{
t
.
Fatal
(
"error writing block receipts:"
,
err
)
}
}
...
...
core/genesis.go
View file @
f9917c8c
...
...
@@ -88,7 +88,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
Root
:
root
,
},
nil
,
nil
,
nil
)
if
block
:=
GetBlock
(
chainDb
,
block
.
Hash
());
block
!=
nil
{
if
block
:=
GetBlock
(
chainDb
,
block
.
Hash
()
,
block
.
NumberU64
()
);
block
!=
nil
{
glog
.
V
(
logger
.
Info
)
.
Infoln
(
"Genesis block already in chain. Writing canonical number"
)
err
:=
WriteCanonicalHash
(
chainDb
,
block
.
Hash
(),
block
.
NumberU64
())
if
err
!=
nil
{
...
...
@@ -100,13 +100,13 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
if
err
:=
stateBatch
.
Write
();
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot write state: %v"
,
err
)
}
if
err
:=
WriteTd
(
chainDb
,
block
.
Hash
(),
difficulty
);
err
!=
nil
{
if
err
:=
WriteTd
(
chainDb
,
block
.
Hash
(),
block
.
NumberU64
(),
difficulty
);
err
!=
nil
{
return
nil
,
err
}
if
err
:=
WriteBlock
(
chainDb
,
block
);
err
!=
nil
{
return
nil
,
err
}
if
err
:=
WriteBlockReceipts
(
chainDb
,
block
.
Hash
(),
nil
);
err
!=
nil
{
if
err
:=
WriteBlockReceipts
(
chainDb
,
block
.
Hash
(),
block
.
NumberU64
(),
nil
);
err
!=
nil
{
return
nil
,
err
}
if
err
:=
WriteCanonicalHash
(
chainDb
,
block
.
Hash
(),
block
.
NumberU64
());
err
!=
nil
{
...
...
core/headerchain.go
View file @
f9917c8c
...
...
@@ -35,6 +35,12 @@ import (
"github.com/hashicorp/golang-lru"
)
const
(
headerCacheLimit
=
512
tdCacheLimit
=
1024
numberCacheLimit
=
2048
)
// HeaderChain implements the basic block header chain logic that is shared by
// core.BlockChain and light.LightChain. It is not usable in itself, only as
// a part of either structure.
...
...
@@ -51,6 +57,7 @@ type HeaderChain struct {
headerCache
*
lru
.
Cache
// Cache for the most recent block headers
tdCache
*
lru
.
Cache
// Cache for the most recent block total difficulties
numberCache
*
lru
.
Cache
// Cache for the most recent block numbers
procInterrupt
func
()
bool
...
...
@@ -68,6 +75,7 @@ type getHeaderValidatorFn func() HeaderValidator
func
NewHeaderChain
(
chainDb
ethdb
.
Database
,
config
*
ChainConfig
,
getValidator
getHeaderValidatorFn
,
procInterrupt
func
()
bool
)
(
*
HeaderChain
,
error
)
{
headerCache
,
_
:=
lru
.
New
(
headerCacheLimit
)
tdCache
,
_
:=
lru
.
New
(
tdCacheLimit
)
numberCache
,
_
:=
lru
.
New
(
numberCacheLimit
)
// Seed a fast but crypto originating random generator
seed
,
err
:=
crand
.
Int
(
crand
.
Reader
,
big
.
NewInt
(
math
.
MaxInt64
))
...
...
@@ -80,6 +88,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *ChainConfig, getValidator ge
chainDb
:
chainDb
,
headerCache
:
headerCache
,
tdCache
:
tdCache
,
numberCache
:
numberCache
,
procInterrupt
:
procInterrupt
,
rand
:
mrand
.
New
(
mrand
.
NewSource
(
seed
.
Int64
())),
getValidator
:
getValidator
,
...
...
@@ -97,7 +106,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *ChainConfig, getValidator ge
hc
.
currentHeader
=
hc
.
genesisHeader
if
head
:=
GetHeadBlockHash
(
chainDb
);
head
!=
(
common
.
Hash
{})
{
if
chead
:=
hc
.
GetHeader
(
head
);
chead
!=
nil
{
if
chead
:=
hc
.
GetHeader
ByHash
(
head
);
chead
!=
nil
{
hc
.
currentHeader
=
chead
}
}
...
...
@@ -106,6 +115,19 @@ func NewHeaderChain(chainDb ethdb.Database, config *ChainConfig, getValidator ge
return
hc
,
nil
}
// GetBlockNumber retrieves the block number belonging to the given hash
// from the cache or database
func
(
hc
*
HeaderChain
)
GetBlockNumber
(
hash
common
.
Hash
)
uint64
{
if
cached
,
ok
:=
hc
.
numberCache
.
Get
(
hash
);
ok
{
return
cached
.
(
uint64
)
}
number
:=
GetBlockNumber
(
hc
.
chainDb
,
hash
)
if
number
!=
missingNumber
{
hc
.
numberCache
.
Add
(
hash
,
number
)
}
return
number
}
// WriteHeader writes a header into the local chain, given that its parent is
// already known. If the total difficulty of the newly inserted header becomes
// greater than the current known TD, the canonical chain is re-routed.
...
...
@@ -122,11 +144,11 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
number
=
header
.
Number
.
Uint64
()
)
// Calculate the total difficulty of the header
ptd
:=
hc
.
GetTd
(
header
.
ParentHash
)
ptd
:=
hc
.
GetTd
(
header
.
ParentHash
,
number
-
1
)
if
ptd
==
nil
{
return
NonStatTy
,
ParentError
(
header
.
ParentHash
)
}
localTd
:=
hc
.
GetTd
(
hc
.
currentHeaderHash
)
localTd
:=
hc
.
GetTd
(
hc
.
currentHeaderHash
,
hc
.
currentHeader
.
Number
.
Uint64
()
)
externTd
:=
new
(
big
.
Int
)
.
Add
(
header
.
Difficulty
,
ptd
)
// If the total difficulty is higher than our known, add it to the canonical chain
...
...
@@ -134,21 +156,25 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
if
externTd
.
Cmp
(
localTd
)
>
0
||
(
externTd
.
Cmp
(
localTd
)
==
0
&&
mrand
.
Float64
()
<
0.5
)
{
// Delete any canonical number assignments above the new head
for
i
:=
number
+
1
;
GetCanonicalHash
(
hc
.
chainDb
,
i
)
!=
(
common
.
Hash
{});
i
++
{
for
i
:=
number
+
1
;
;
i
++
{
hash
:=
GetCanonicalHash
(
hc
.
chainDb
,
i
)
if
hash
==
(
common
.
Hash
{})
{
break
}
DeleteCanonicalHash
(
hc
.
chainDb
,
i
)
}
// Overwrite any stale canonical number assignments
var
(
headHash
=
header
.
ParentHash
head
Header
=
hc
.
GetHeader
(
headHash
)
head
Number
=
headHeader
.
Number
.
Uint64
(
)
head
Number
=
header
.
Number
.
Uint64
()
-
1
head
Header
=
hc
.
GetHeader
(
headHash
,
headNumber
)
)
for
GetCanonicalHash
(
hc
.
chainDb
,
headNumber
)
!=
headHash
{
WriteCanonicalHash
(
hc
.
chainDb
,
headHash
,
headNumber
)
headHash
=
headHeader
.
ParentHash
head
Header
=
hc
.
GetHeader
(
headHash
)
head
Number
=
headHeader
.
Number
.
Uint64
(
)
head
Number
=
headHeader
.
Number
.
Uint64
()
-
1
head
Header
=
hc
.
GetHeader
(
headHash
,
headNumber
)
}
// Extend the canonical chain with the new header
if
err
:=
WriteCanonicalHash
(
hc
.
chainDb
,
hash
,
number
);
err
!=
nil
{
...
...
@@ -164,13 +190,14 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
status
=
SideStatTy
}
// Irrelevant of the canonical status, write the header itself to the database
if
err
:=
hc
.
WriteTd
(
hash
,
externTd
);
err
!=
nil
{
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
.
numberCache
.
Add
(
hash
,
number
)
return
}
...
...
@@ -239,7 +266,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
var
err
error
if
index
==
0
{
err
=
hc
.
getValidator
()
.
ValidateHeader
(
header
,
hc
.
GetHeader
(
header
.
ParentHash
),
checkPow
)
err
=
hc
.
getValidator
()
.
ValidateHeader
(
header
,
hc
.
GetHeader
(
header
.
ParentHash
,
header
.
Number
.
Uint64
()
-
1
),
checkPow
)
}
else
{
err
=
hc
.
getValidator
()
.
ValidateHeader
(
header
,
chain
[
index
-
1
],
checkPow
)
}
...
...
@@ -300,7 +327,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
// hash, fetching towards the genesis block.
func
(
hc
*
HeaderChain
)
GetBlockHashesFromHash
(
hash
common
.
Hash
,
max
uint64
)
[]
common
.
Hash
{
// Get the origin header from which to fetch
header
:=
hc
.
GetHeader
(
hash
)
header
:=
hc
.
GetHeader
ByHash
(
hash
)
if
header
==
nil
{
return
nil
}
...
...
@@ -308,7 +335,7 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
chain
:=
make
([]
common
.
Hash
,
0
,
max
)
for
i
:=
uint64
(
0
);
i
<
max
;
i
++
{
next
:=
header
.
ParentHash
if
header
=
hc
.
GetHeader
(
next
);
header
==
nil
{
if
header
=
hc
.
GetHeader
(
next
,
header
.
Number
.
Uint64
()
-
1
);
header
==
nil
{
break
}
chain
=
append
(
chain
,
next
)
...
...
@@ -320,13 +347,13 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
}
// GetTd retrieves a block's total difficulty in the canonical chain from the
// database by hash, caching it if found.
func
(
hc
*
HeaderChain
)
GetTd
(
hash
common
.
Hash
)
*
big
.
Int
{
// database by hash
and number
, caching it if found.
func
(
hc
*
HeaderChain
)
GetTd
(
hash
common
.
Hash
,
number
uint64
)
*
big
.
Int
{
// Short circuit if the td's already in the cache, retrieve otherwise
if
cached
,
ok
:=
hc
.
tdCache
.
Get
(
hash
);
ok
{
return
cached
.
(
*
big
.
Int
)
}
td
:=
GetTd
(
hc
.
chainDb
,
hash
)
td
:=
GetTd
(
hc
.
chainDb
,
hash
,
number
)
if
td
==
nil
{
return
nil
}
...
...
@@ -335,24 +362,30 @@ func (hc *HeaderChain) GetTd(hash common.Hash) *big.Int {
return
td
}
// GetTdByHash retrieves a block's total difficulty in the canonical chain from the
// database by hash, caching it if found.
func
(
hc
*
HeaderChain
)
GetTdByHash
(
hash
common
.
Hash
)
*
big
.
Int
{
return
hc
.
GetTd
(
hash
,
hc
.
GetBlockNumber
(
hash
))
}
// WriteTd stores a block's total difficulty into the database, also caching it
// along the way.
func
(
hc
*
HeaderChain
)
WriteTd
(
hash
common
.
Hash
,
td
*
big
.
Int
)
error
{
if
err
:=
WriteTd
(
hc
.
chainDb
,
hash
,
td
);
err
!=
nil
{
func
(
hc
*
HeaderChain
)
WriteTd
(
hash
common
.
Hash
,
number
uint64
,
td
*
big
.
Int
)
error
{
if
err
:=
WriteTd
(
hc
.
chainDb
,
hash
,
number
,
td
);
err
!=
nil
{
return
err
}
hc
.
tdCache
.
Add
(
hash
,
new
(
big
.
Int
)
.
Set
(
td
))
return
nil
}
// GetHeader retrieves a block header from the database by hash
, caching it if
// found.
func
(
hc
*
HeaderChain
)
GetHeader
(
hash
common
.
Hash
)
*
types
.
Header
{
// GetHeader retrieves a block header from the database by hash
and number,
//
caching it if
found.
func
(
hc
*
HeaderChain
)
GetHeader
(
hash
common
.
Hash
,
number
uint64
)
*
types
.
Header
{
// Short circuit if the header's already in the cache, retrieve otherwise
if
header
,
ok
:=
hc
.
headerCache
.
Get
(
hash
);
ok
{
return
header
.
(
*
types
.
Header
)
}
header
:=
GetHeader
(
hc
.
chainDb
,
hash
)
header
:=
GetHeader
(
hc
.
chainDb
,
hash
,
number
)
if
header
==
nil
{
return
nil
}
...
...
@@ -361,10 +394,16 @@ func (hc *HeaderChain) GetHeader(hash common.Hash) *types.Header {
return
header
}
// GetHeaderByHash retrieves a block header from the database by hash, caching it if
// found.
func
(
hc
*
HeaderChain
)
GetHeaderByHash
(
hash
common
.
Hash
)
*
types
.
Header
{
return
hc
.
GetHeader
(
hash
,
hc
.
GetBlockNumber
(
hash
))
}
// HasHeader checks if a block header is present in the database or not, caching
// it if present.
func
(
hc
*
HeaderChain
)
HasHeader
(
hash
common
.
Hash
)
bool
{
return
hc
.
GetHeader
(
hash
)
!=
nil
return
hc
.
GetHeader
ByHash
(
hash
)
!=
nil
}
// GetHeaderByNumber retrieves a block header from the database by number,
...
...
@@ -374,7 +413,7 @@ func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
if
hash
==
(
common
.
Hash
{})
{
return
nil
}
return
hc
.
GetHeader
(
hash
)
return
hc
.
GetHeader
(
hash
,
number
)
}
// CurrentHeader retrieves the current head header of the canonical chain. The
...
...
@@ -394,7 +433,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
// DeleteCallback is a callback function that is called by SetHead before
// each header is deleted.
type
DeleteCallback
func
(
common
.
Hash
)
type
DeleteCallback
func
(
common
.
Hash
,
uint64
)
// SetHead rewinds the local chain to a new head. Everything above the new head
// will be deleted and the new one set.
...
...
@@ -406,12 +445,13 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
for
hc
.
currentHeader
!=
nil
&&
hc
.
currentHeader
.
Number
.
Uint64
()
>
head
{
hash
:=
hc
.
currentHeader
.
Hash
()
num
:=
hc
.
currentHeader
.
Number
.
Uint64
()
if
delFn
!=
nil
{
delFn
(
hash
)
delFn
(
hash
,
num
)
}
DeleteHeader
(
hc
.
chainDb
,
hash
)
DeleteTd
(
hc
.
chainDb
,
hash
)
hc
.
currentHeader
=
hc
.
GetHeader
(
hc
.
currentHeader
.
ParentHash
)
DeleteHeader
(
hc
.
chainDb
,
hash
,
num
)
DeleteTd
(
hc
.
chainDb
,
hash
,
num
)
hc
.
currentHeader
=
hc
.
GetHeader
(
hc
.
currentHeader
.
ParentHash
,
hc
.
currentHeader
.
Number
.
Uint64
()
-
1
)
}
// Roll back the canonical chain numbering
for
i
:=
height
;
i
>
head
;
i
--
{
...
...
@@ -420,6 +460,7 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
// Clear out any stale content from the caches
hc
.
headerCache
.
Purge
()
hc
.
tdCache
.
Purge
()
hc
.
numberCache
.
Purge
()
if
hc
.
currentHeader
==
nil
{
hc
.
currentHeader
=
hc
.
genesisHeader
...
...
core/vm_env.go
View file @
f9917c8c
...
...
@@ -30,7 +30,7 @@ import (
// to query for information.
func
GetHashFn
(
ref
common
.
Hash
,
chain
*
BlockChain
)
func
(
n
uint64
)
common
.
Hash
{
return
func
(
n
uint64
)
common
.
Hash
{
for
block
:=
chain
.
GetBlock
(
ref
);
block
!=
nil
;
block
=
chain
.
GetBlock
(
block
.
ParentHash
()
)
{
for
block
:=
chain
.
GetBlock
ByHash
(
ref
);
block
!=
nil
;
block
=
chain
.
GetBlock
(
block
.
ParentHash
(),
block
.
NumberU64
()
-
1
)
{
if
block
.
NumberU64
()
==
n
{
return
block
.
Hash
()
}
...
...
eth/api.go
View file @
f9917c8c
...
...
@@ -594,7 +594,7 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(blockNr rpc.BlockNumber, fullTx b
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
// detail, otherwise only the transaction hash is returned.
func
(
s
*
PublicBlockChainAPI
)
GetBlockByHash
(
blockHash
common
.
Hash
,
fullTx
bool
)
(
map
[
string
]
interface
{},
error
)
{
if
block
:=
s
.
bc
.
GetBlock
(
blockHash
);
block
!=
nil
{
if
block
:=
s
.
bc
.
GetBlock
ByHash
(
blockHash
);
block
!=
nil
{
return
s
.
rpcOutputBlock
(
block
,
true
,
fullTx
)
}
return
nil
,
nil
...
...
@@ -618,7 +618,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(blockNr rpc.BlockNum
// GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. When fullTx is true
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
func
(
s
*
PublicBlockChainAPI
)
GetUncleByBlockHashAndIndex
(
blockHash
common
.
Hash
,
index
rpc
.
HexNumber
)
(
map
[
string
]
interface
{},
error
)
{
if
block
:=
s
.
bc
.
GetBlock
(
blockHash
);
block
!=
nil
{
if
block
:=
s
.
bc
.
GetBlock
ByHash
(
blockHash
);
block
!=
nil
{
uncles
:=
block
.
Uncles
()
if
index
.
Int
()
<
0
||
index
.
Int
()
>=
len
(
uncles
)
{
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"uncle block on index %d not found for block %s"
,
index
.
Int
(),
blockHash
.
Hex
())
...
...
@@ -640,7 +640,7 @@ func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(blockNr rpc.BlockNumber
// GetUncleCountByBlockHash returns number of uncles in the block for the given block hash
func
(
s
*
PublicBlockChainAPI
)
GetUncleCountByBlockHash
(
blockHash
common
.
Hash
)
*
rpc
.
HexNumber
{
if
block
:=
s
.
bc
.
GetBlock
(
blockHash
);
block
!=
nil
{
if
block
:=
s
.
bc
.
GetBlock
ByHash
(
blockHash
);
block
!=
nil
{
return
rpc
.
NewHexNumber
(
len
(
block
.
Uncles
()))
}
return
nil
...
...
@@ -814,7 +814,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
"stateRoot"
:
b
.
Root
(),
"miner"
:
b
.
Coinbase
(),
"difficulty"
:
rpc
.
NewHexNumber
(
b
.
Difficulty
()),
"totalDifficulty"
:
rpc
.
NewHexNumber
(
s
.
bc
.
GetTd
(
b
.
Hash
())),
"totalDifficulty"
:
rpc
.
NewHexNumber
(
s
.
bc
.
GetTd
(
b
.
Hash
()
,
b
.
NumberU64
()
)),
"extraData"
:
fmt
.
Sprintf
(
"0x%x"
,
b
.
Extra
()),
"size"
:
rpc
.
NewHexNumber
(
b
.
Size
()
.
Int64
()),
"gasLimit"
:
rpc
.
NewHexNumber
(
b
.
GasLimit
()),
...
...
@@ -1004,7 +1004,7 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(blockNr rpc.
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
func
(
s
*
PublicTransactionPoolAPI
)
GetBlockTransactionCountByHash
(
blockHash
common
.
Hash
)
*
rpc
.
HexNumber
{
if
block
:=
s
.
bc
.
GetBlock
(
blockHash
);
block
!=
nil
{
if
block
:=
s
.
bc
.
GetBlock
ByHash
(
blockHash
);
block
!=
nil
{
return
rpc
.
NewHexNumber
(
len
(
block
.
Transactions
()))
}
return
nil
...
...
@@ -1020,7 +1020,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(blockNr r
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
func
(
s
*
PublicTransactionPoolAPI
)
GetTransactionByBlockHashAndIndex
(
blockHash
common
.
Hash
,
index
rpc
.
HexNumber
)
(
*
RPCTransaction
,
error
)
{
if
block
:=
s
.
bc
.
GetBlock
(
blockHash
);
block
!=
nil
{
if
block
:=
s
.
bc
.
GetBlock
ByHash
(
blockHash
);
block
!=
nil
{
return
newRPCTransactionFromBlockIndex
(
block
,
index
.
Int
())
}
return
nil
,
nil
...
...
@@ -1080,7 +1080,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByHash(txHash common.Hash) (*RP
return
nil
,
nil
}
if
block
:=
s
.
bc
.
GetBlock
(
blockHash
);
block
!=
nil
{
if
block
:=
s
.
bc
.
GetBlock
ByHash
(
blockHash
);
block
!=
nil
{
return
newRPCTransaction
(
block
,
txHash
)
}
...
...
@@ -1705,7 +1705,7 @@ func (api *PrivateDebugAPI) TraceBlockByNumber(number uint64, config *vm.Config)
// TraceBlockByHash processes the block by hash.
func
(
api
*
PrivateDebugAPI
)
TraceBlockByHash
(
hash
common
.
Hash
,
config
*
vm
.
Config
)
BlockTraceResult
{
// Fetch the block that we aim to reprocess
block
:=
api
.
eth
.
BlockChain
()
.
GetBlock
(
hash
)
block
:=
api
.
eth
.
BlockChain
()
.
GetBlock
ByHash
(
hash
)
if
block
==
nil
{
return
BlockTraceResult
{
Error
:
fmt
.
Sprintf
(
"block #%x not found"
,
hash
)}
}
...
...
@@ -1745,10 +1745,10 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, config *vm.Config) (b
config
.
Debug
=
true
// make sure debug is set.
config
.
Logger
.
Collector
=
collector
if
err
:=
core
.
ValidateHeader
(
api
.
config
,
blockchain
.
AuxValidator
(),
block
.
Header
(),
blockchain
.
GetHeader
(
block
.
ParentHash
()),
true
,
false
);
err
!=
nil
{
if
err
:=
core
.
ValidateHeader
(
api
.
config
,
blockchain
.
AuxValidator
(),
block
.
Header
(),
blockchain
.
GetHeader
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
),
true
,
false
);
err
!=
nil
{
return
false
,
collector
.
traces
,
err
}
statedb
,
err
:=
state
.
New
(
blockchain
.
GetBlock
(
block
.
ParentHash
())
.
Root
(),
api
.
eth
.
ChainDb
())
statedb
,
err
:=
state
.
New
(
blockchain
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
)
.
Root
(),
api
.
eth
.
ChainDb
())
if
err
!=
nil
{
return
false
,
collector
.
traces
,
err
}
...
...
@@ -1757,7 +1757,7 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, config *vm.Config) (b
if
err
!=
nil
{
return
false
,
collector
.
traces
,
err
}
if
err
:=
validator
.
ValidateState
(
block
,
blockchain
.
GetBlock
(
block
.
ParentHash
()),
statedb
,
receipts
,
usedGas
);
err
!=
nil
{
if
err
:=
validator
.
ValidateState
(
block
,
blockchain
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
),
statedb
,
receipts
,
usedGas
);
err
!=
nil
{
return
false
,
collector
.
traces
,
err
}
return
true
,
collector
.
traces
,
nil
...
...
@@ -1841,12 +1841,12 @@ func (api *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logger *vm.LogC
if
tx
==
nil
{
return
nil
,
fmt
.
Errorf
(
"transaction %x not found"
,
txHash
)
}
block
:=
api
.
eth
.
BlockChain
()
.
GetBlock
(
blockHash
)
block
:=
api
.
eth
.
BlockChain
()
.
GetBlock
ByHash
(
blockHash
)
if
block
==
nil
{
return
nil
,
fmt
.
Errorf
(
"block %x not found"
,
blockHash
)
}
// Create the state database to mutate and eventually trace
parent
:=
api
.
eth
.
BlockChain
()
.
GetBlock
(
block
.
ParentHash
())
parent
:=
api
.
eth
.
BlockChain
()
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
)
if
parent
==
nil
{
return
nil
,
fmt
.
Errorf
(
"block parent %x not found"
,
block
.
ParentHash
())
}
...
...
eth/backend.go
View file @
f9917c8c
...
...
@@ -18,7 +18,6 @@
package
eth
import
(
"bytes"
"errors"
"fmt"
"math/big"
...
...
@@ -47,7 +46,6 @@ import (
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
)
...
...
@@ -105,8 +103,8 @@ type Config struct {
type
Ethereum
struct
{
chainConfig
*
core
.
ChainConfig
// Channel for shutting down the ethereum
s
hutdownChan
chan
bool
shutdownChan
chan
bool
// Channel for shutting down the ethereum
s
topDbUpgrade
func
()
// stop chain db sequential key upgrade
// DB interfaces
chainDb
ethdb
.
Database
// Block chain database
...
...
@@ -161,6 +159,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if
err
:=
addMipmapBloomBins
(
chainDb
);
err
!=
nil
{
return
nil
,
err
}
stopDbUpgrade
:=
upgradeSequentialKeys
(
chainDb
)
dappDb
,
err
:=
ctx
.
OpenDatabase
(
"dapp"
,
config
.
DatabaseCache
,
config
.
DatabaseHandles
)
if
err
!=
nil
{
...
...
@@ -185,7 +184,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
chainDb
=
config
.
TestGenesisState
}
if
config
.
TestGenesisBlock
!=
nil
{
core
.
WriteTd
(
chainDb
,
config
.
TestGenesisBlock
.
Hash
(),
config
.
TestGenesisBlock
.
Difficulty
())
core
.
WriteTd
(
chainDb
,
config
.
TestGenesisBlock
.
Hash
(),
config
.
TestGenesisBlock
.
NumberU64
(),
config
.
TestGenesisBlock
.
Difficulty
())
core
.
WriteBlock
(
chainDb
,
config
.
TestGenesisBlock
)
core
.
WriteCanonicalHash
(
chainDb
,
config
.
TestGenesisBlock
.
Hash
(),
config
.
TestGenesisBlock
.
NumberU64
())
core
.
WriteHeadBlockHash
(
chainDb
,
config
.
TestGenesisBlock
.
Hash
())
...
...
@@ -202,6 +201,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth
:=
&
Ethereum
{
shutdownChan
:
make
(
chan
bool
),
stopDbUpgrade
:
stopDbUpgrade
,
chainDb
:
chainDb
,
dappDb
:
dappDb
,
eventMux
:
ctx
.
EventMux
,
...
...
@@ -238,7 +238,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
// load the genesis block or write a new one if no genesis
// block is prenent in the database.
genesis
:=
core
.
GetBlock
(
chainDb
,
core
.
GetCanonicalHash
(
chainDb
,
0
))
genesis
:=
core
.
GetBlock
(
chainDb
,
core
.
GetCanonicalHash
(
chainDb
,
0
)
,
0
)
if
genesis
==
nil
{
genesis
,
err
=
core
.
WriteDefaultGenesisBlock
(
chainDb
)
if
err
!=
nil
{
...
...
@@ -415,6 +415,9 @@ func (s *Ethereum) Start(srvr *p2p.Server) error {
// Stop implements node.Service, terminating all internal goroutines used by the
// Ethereum protocol.
func
(
s
*
Ethereum
)
Stop
()
error
{
if
s
.
stopDbUpgrade
!=
nil
{
s
.
stopDbUpgrade
()
}
s
.
blockchain
.
Stop
()
s
.
protocolManager
.
Stop
()
s
.
txPool
.
Stop
()
...
...
@@ -526,104 +529,3 @@ func dagFiles(epoch uint64) (string, string) {
dag
:=
fmt
.
Sprintf
(
"full-R%d-%x"
,
ethashRevision
,
seedHash
[
:
8
])
return
dag
,
"full-R"
+
dag
}
// upgradeChainDatabase ensures that the chain database stores block split into
// separate header and body entries.
func
upgradeChainDatabase
(
db
ethdb
.
Database
)
error
{
// Short circuit if the head block is stored already as separate header and body
data
,
err
:=
db
.
Get
([]
byte
(
"LastBlock"
))
if
err
!=
nil
{
return
nil
}
head
:=
common
.
BytesToHash
(
data
)
if
block
:=
core
.
GetBlockByHashOld
(
db
,
head
);
block
==
nil
{
return
nil
}
// At least some of the database is still the old format, upgrade (skip the head block!)
glog
.
V
(
logger
.
Info
)
.
Info
(
"Old database detected, upgrading..."
)
if
db
,
ok
:=
db
.
(
*
ethdb
.
LDBDatabase
);
ok
{
blockPrefix
:=
[]
byte
(
"block-hash-"
)
for
it
:=
db
.
NewIterator
();
it
.
Next
();
{
// Skip anything other than a combined block
if
!
bytes
.
HasPrefix
(
it
.
Key
(),
blockPrefix
)
{
continue
}
// Skip the head block (merge last to signal upgrade completion)
if
bytes
.
HasSuffix
(
it
.
Key
(),
head
.
Bytes
())
{
continue
}
// Load the block, split and serialize (order!)
block
:=
core
.
GetBlockByHashOld
(
db
,
common
.
BytesToHash
(
bytes
.
TrimPrefix
(
it
.
Key
(),
blockPrefix
)))
if
err
:=
core
.
WriteTd
(
db
,
block
.
Hash
(),
block
.
DeprecatedTd
());
err
!=
nil
{
return
err
}
if
err
:=
core
.
WriteBody
(
db
,
block
.
Hash
(),
block
.
Body
());
err
!=
nil
{
return
err
}
if
err
:=
core
.
WriteHeader
(
db
,
block
.
Header
());
err
!=
nil
{
return
err
}
if
err
:=
db
.
Delete
(
it
.
Key
());
err
!=
nil
{
return
err
}
}
// Lastly, upgrade the head block, disabling the upgrade mechanism
current
:=
core
.
GetBlockByHashOld
(
db
,
head
)
if
err
:=
core
.
WriteTd
(
db
,
current
.
Hash
(),
current
.
DeprecatedTd
());
err
!=
nil
{
return
err
}
if
err
:=
core
.
WriteBody
(
db
,
current
.
Hash
(),
current
.
Body
());
err
!=
nil
{
return
err
}
if
err
:=
core
.
WriteHeader
(
db
,
current
.
Header
());
err
!=
nil
{
return
err
}
}
return
nil
}
func
addMipmapBloomBins
(
db
ethdb
.
Database
)
(
err
error
)
{
const
mipmapVersion
uint
=
2
// check if the version is set. We ignore data for now since there's
// only one version so we can easily ignore it for now
var
data
[]
byte
data
,
_
=
db
.
Get
([]
byte
(
"setting-mipmap-version"
))
if
len
(
data
)
>
0
{
var
version
uint
if
err
:=
rlp
.
DecodeBytes
(
data
,
&
version
);
err
==
nil
&&
version
==
mipmapVersion
{
return
nil
}
}
defer
func
()
{
if
err
==
nil
{
var
val
[]
byte
val
,
err
=
rlp
.
EncodeToBytes
(
mipmapVersion
)
if
err
==
nil
{
err
=
db
.
Put
([]
byte
(
"setting-mipmap-version"
),
val
)
}
return
}
}()
latestBlock
:=
core
.
GetBlock
(
db
,
core
.
GetHeadBlockHash
(
db
))
if
latestBlock
==
nil
{
// clean database
return
}
tstart
:=
time
.
Now
()
glog
.
V
(
logger
.
Info
)
.
Infoln
(
"upgrading db log bloom bins"
)
for
i
:=
uint64
(
0
);
i
<=
latestBlock
.
NumberU64
();
i
++
{
hash
:=
core
.
GetCanonicalHash
(
db
,
i
)
if
(
hash
==
common
.
Hash
{})
{
return
fmt
.
Errorf
(
"chain db corrupted. Could not find block %d."
,
i
)
}
core
.
WriteMipmapBloom
(
db
,
i
,
core
.
GetBlockReceipts
(
db
,
hash
))
}
glog
.
V
(
logger
.
Info
)
.
Infoln
(
"upgrade completed in"
,
time
.
Since
(
tstart
))
return
nil
}
eth/backend_test.go
View file @
f9917c8c
...
...
@@ -61,7 +61,7 @@ func TestMipmapUpgrade(t *testing.T) {
if
err
:=
core
.
WriteHeadBlockHash
(
db
,
block
.
Hash
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
}
if
err
:=
core
.
WriteBlockReceipts
(
db
,
block
.
Hash
(),
receipts
[
i
]);
err
!=
nil
{
if
err
:=
core
.
WriteBlockReceipts
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
receipts
[
i
]);
err
!=
nil
{
t
.
Fatal
(
"error writing block receipts:"
,
err
)
}
}
...
...
eth/db_upgrade.go
0 → 100644
View file @
f9917c8c
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package eth implements the Ethereum protocol.
package
eth
import
(
"bytes"
"encoding/binary"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp"
)
var
useSequentialKeys
=
[]
byte
(
"dbUpgrade_20160530sequentialKeys"
)
// upgradeSequentialKeys checks the chain database version and
// starts a background process to make upgrades if necessary.
// Returns a stop function that blocks until the process has
// been safely stopped.
func
upgradeSequentialKeys
(
db
ethdb
.
Database
)
(
stopFn
func
())
{
data
,
_
:=
db
.
Get
(
useSequentialKeys
)
if
len
(
data
)
>
0
&&
data
[
0
]
==
42
{
return
nil
// already converted
}
if
data
,
_
:=
db
.
Get
([]
byte
(
"LastHeader"
));
len
(
data
)
==
0
{
db
.
Put
(
useSequentialKeys
,
[]
byte
{
42
})
return
nil
// empty database, nothing to do
}
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Upgrading chain database to use sequential keys"
)
stopChn
:=
make
(
chan
struct
{})
stoppedChn
:=
make
(
chan
struct
{})
go
func
()
{
stopFn
:=
func
()
bool
{
select
{
case
<-
time
.
After
(
time
.
Microsecond
*
100
)
:
// make sure other processes don't get starved
case
<-
stopChn
:
return
true
}
return
false
}
err
,
stopped
:=
upgradeSequentialCanonicalNumbers
(
db
,
stopFn
)
if
err
==
nil
&&
!
stopped
{
err
,
stopped
=
upgradeSequentialBlocks
(
db
,
stopFn
)
}
if
err
==
nil
&&
!
stopped
{
err
,
stopped
=
upgradeSequentialOrphanedReceipts
(
db
,
stopFn
)
}
if
err
==
nil
&&
!
stopped
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Database conversion successful"
)
db
.
Put
(
useSequentialKeys
,
[]
byte
{
42
})
}
if
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Database conversion failed: %v"
,
err
)
}
close
(
stoppedChn
)
}()
return
func
()
{
close
(
stopChn
)
<-
stoppedChn
}
}
// upgradeSequentialCanonicalNumbers reads all old format canonical numbers from
// the database, writes them in new format and deletes the old ones if successful.
func
upgradeSequentialCanonicalNumbers
(
db
ethdb
.
Database
,
stopFn
func
()
bool
)
(
error
,
bool
)
{
prefix
:=
[]
byte
(
"block-num-"
)
it
:=
db
.
(
*
ethdb
.
LDBDatabase
)
.
NewIterator
()
it
.
Seek
(
prefix
)
cnt
:=
0
for
bytes
.
HasPrefix
(
it
.
Key
(),
prefix
)
{
keyPtr
:=
it
.
Key
()
if
len
(
keyPtr
)
<
20
{
cnt
++
if
cnt
%
100000
==
0
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"converting %d canonical numbers..."
,
cnt
)
}
number
:=
big
.
NewInt
(
0
)
.
SetBytes
(
keyPtr
[
10
:
])
.
Uint64
()
newKey
:=
[]
byte
(
"h12345678n"
)
binary
.
BigEndian
.
PutUint64
(
newKey
[
1
:
9
],
number
)
if
err
:=
db
.
Put
(
newKey
,
it
.
Value
());
err
!=
nil
{
return
err
,
false
}
if
err
:=
db
.
Delete
(
keyPtr
);
err
!=
nil
{
return
err
,
false
}
}
if
stopFn
()
{
return
nil
,
true
}
it
.
Next
()
}
if
cnt
>
0
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"converted %d canonical numbers..."
,
cnt
)
}
return
nil
,
false
}
// upgradeSequentialBlocks reads all old format block headers, bodies, TDs and block
// receipts from the database, writes them in new format and deletes the old ones
// if successful.
func
upgradeSequentialBlocks
(
db
ethdb
.
Database
,
stopFn
func
()
bool
)
(
error
,
bool
)
{
prefix
:=
[]
byte
(
"block-"
)
it
:=
db
.
(
*
ethdb
.
LDBDatabase
)
.
NewIterator
()
it
.
Seek
(
prefix
)
cnt
:=
0
for
bytes
.
HasPrefix
(
it
.
Key
(),
prefix
)
{
keyPtr
:=
it
.
Key
()
if
len
(
keyPtr
)
>=
38
{
cnt
++
if
cnt
%
10000
==
0
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"converting %d blocks..."
,
cnt
)
}
// convert header, body, td and block receipts
var
keyPrefix
[
38
]
byte
copy
(
keyPrefix
[
:
],
keyPtr
[
0
:
38
])
hash
:=
keyPrefix
[
6
:
38
]
if
err
:=
upgradeSequentialBlockData
(
db
,
hash
);
err
!=
nil
{
return
err
,
false
}
// delete old db entries belonging to this hash
for
bytes
.
HasPrefix
(
it
.
Key
(),
keyPrefix
[
:
])
{
if
err
:=
db
.
Delete
(
it
.
Key
());
err
!=
nil
{
return
err
,
false
}
it
.
Next
()
}
if
err
:=
db
.
Delete
(
append
([]
byte
(
"receipts-block-"
),
hash
...
));
err
!=
nil
{
return
err
,
false
}
}
else
{
it
.
Next
()
}
if
stopFn
()
{
return
nil
,
true
}
}
if
cnt
>
0
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"converted %d blocks..."
,
cnt
)
}
return
nil
,
false
}
// upgradeSequentialOrphanedReceipts removes any old format block receipts from the
// database that did not have a corresponding block
func
upgradeSequentialOrphanedReceipts
(
db
ethdb
.
Database
,
stopFn
func
()
bool
)
(
error
,
bool
)
{
prefix
:=
[]
byte
(
"receipts-block-"
)
it
:=
db
.
(
*
ethdb
.
LDBDatabase
)
.
NewIterator
()
it
.
Seek
(
prefix
)
cnt
:=
0
for
bytes
.
HasPrefix
(
it
.
Key
(),
prefix
)
{
// phase 2 already converted receipts belonging to existing
// blocks, just remove if there's anything left
cnt
++
if
err
:=
db
.
Delete
(
it
.
Key
());
err
!=
nil
{
return
err
,
false
}
if
stopFn
()
{
return
nil
,
true
}
it
.
Next
()
}
if
cnt
>
0
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"removed %d orphaned block receipts..."
,
cnt
)
}
return
nil
,
false
}
// upgradeSequentialBlockData upgrades the header, body, td and block receipts
// database entries belonging to a single hash (doesn't delete old data).
func
upgradeSequentialBlockData
(
db
ethdb
.
Database
,
hash
[]
byte
)
error
{
// get old chain data and block number
headerRLP
,
_
:=
db
.
Get
(
append
(
append
([]
byte
(
"block-"
),
hash
...
),
[]
byte
(
"-header"
)
...
))
if
len
(
headerRLP
)
==
0
{
return
nil
}
header
:=
new
(
types
.
Header
)
if
err
:=
rlp
.
Decode
(
bytes
.
NewReader
(
headerRLP
),
header
);
err
!=
nil
{
return
err
}
number
:=
header
.
Number
.
Uint64
()
bodyRLP
,
_
:=
db
.
Get
(
append
(
append
([]
byte
(
"block-"
),
hash
...
),
[]
byte
(
"-body"
)
...
))
tdRLP
,
_
:=
db
.
Get
(
append
(
append
([]
byte
(
"block-"
),
hash
...
),
[]
byte
(
"-td"
)
...
))
receiptsRLP
,
_
:=
db
.
Get
(
append
([]
byte
(
"receipts-block-"
),
hash
...
))
// store new hash -> number association
encNum
:=
make
([]
byte
,
8
)
binary
.
BigEndian
.
PutUint64
(
encNum
,
number
)
if
err
:=
db
.
Put
(
append
([]
byte
(
"H"
),
hash
...
),
encNum
);
err
!=
nil
{
return
err
}
// store new chain data
if
err
:=
db
.
Put
(
append
(
append
([]
byte
(
"h"
),
encNum
...
),
hash
...
),
headerRLP
);
err
!=
nil
{
return
err
}
if
len
(
tdRLP
)
!=
0
{
if
err
:=
db
.
Put
(
append
(
append
(
append
([]
byte
(
"h"
),
encNum
...
),
hash
...
),
[]
byte
(
"t"
)
...
),
tdRLP
);
err
!=
nil
{
return
err
}
}
if
len
(
bodyRLP
)
!=
0
{
if
err
:=
db
.
Put
(
append
(
append
([]
byte
(
"b"
),
encNum
...
),
hash
...
),
bodyRLP
);
err
!=
nil
{
return
err
}
}
if
len
(
receiptsRLP
)
!=
0
{
if
err
:=
db
.
Put
(
append
(
append
([]
byte
(
"r"
),
encNum
...
),
hash
...
),
receiptsRLP
);
err
!=
nil
{
return
err
}
}
return
nil
}
// upgradeChainDatabase ensures that the chain database stores block split into
// separate header and body entries.
func
upgradeChainDatabase
(
db
ethdb
.
Database
)
error
{
// Short circuit if the head block is stored already as separate header and body
data
,
err
:=
db
.
Get
([]
byte
(
"LastBlock"
))
if
err
!=
nil
{
return
nil
}
head
:=
common
.
BytesToHash
(
data
)
if
block
:=
core
.
GetBlockByHashOld
(
db
,
head
);
block
==
nil
{
return
nil
}
// At least some of the database is still the old format, upgrade (skip the head block!)
glog
.
V
(
logger
.
Info
)
.
Info
(
"Old database detected, upgrading..."
)
if
db
,
ok
:=
db
.
(
*
ethdb
.
LDBDatabase
);
ok
{
blockPrefix
:=
[]
byte
(
"block-hash-"
)
for
it
:=
db
.
NewIterator
();
it
.
Next
();
{
// Skip anything other than a combined block
if
!
bytes
.
HasPrefix
(
it
.
Key
(),
blockPrefix
)
{
continue
}
// Skip the head block (merge last to signal upgrade completion)
if
bytes
.
HasSuffix
(
it
.
Key
(),
head
.
Bytes
())
{
continue
}
// Load the block, split and serialize (order!)
block
:=
core
.
GetBlockByHashOld
(
db
,
common
.
BytesToHash
(
bytes
.
TrimPrefix
(
it
.
Key
(),
blockPrefix
)))
if
err
:=
core
.
WriteTd
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
block
.
DeprecatedTd
());
err
!=
nil
{
return
err
}
if
err
:=
core
.
WriteBody
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
block
.
Body
());
err
!=
nil
{
return
err
}
if
err
:=
core
.
WriteHeader
(
db
,
block
.
Header
());
err
!=
nil
{
return
err
}
if
err
:=
db
.
Delete
(
it
.
Key
());
err
!=
nil
{
return
err
}
}
// Lastly, upgrade the head block, disabling the upgrade mechanism
current
:=
core
.
GetBlockByHashOld
(
db
,
head
)
if
err
:=
core
.
WriteTd
(
db
,
current
.
Hash
(),
current
.
NumberU64
(),
current
.
DeprecatedTd
());
err
!=
nil
{
return
err
}
if
err
:=
core
.
WriteBody
(
db
,
current
.
Hash
(),
current
.
NumberU64
(),
current
.
Body
());
err
!=
nil
{
return
err
}
if
err
:=
core
.
WriteHeader
(
db
,
current
.
Header
());
err
!=
nil
{
return
err
}
}
return
nil
}
func
addMipmapBloomBins
(
db
ethdb
.
Database
)
(
err
error
)
{
const
mipmapVersion
uint
=
2
// check if the version is set. We ignore data for now since there's
// only one version so we can easily ignore it for now
var
data
[]
byte
data
,
_
=
db
.
Get
([]
byte
(
"setting-mipmap-version"
))
if
len
(
data
)
>
0
{
var
version
uint
if
err
:=
rlp
.
DecodeBytes
(
data
,
&
version
);
err
==
nil
&&
version
==
mipmapVersion
{
return
nil
}
}
defer
func
()
{
if
err
==
nil
{
var
val
[]
byte
val
,
err
=
rlp
.
EncodeToBytes
(
mipmapVersion
)
if
err
==
nil
{
err
=
db
.
Put
([]
byte
(
"setting-mipmap-version"
),
val
)
}
return
}
}()
latestHash
:=
core
.
GetHeadBlockHash
(
db
)
latestBlock
:=
core
.
GetBlock
(
db
,
latestHash
,
core
.
GetBlockNumber
(
db
,
latestHash
))
if
latestBlock
==
nil
{
// clean database
return
}
tstart
:=
time
.
Now
()
glog
.
V
(
logger
.
Info
)
.
Infoln
(
"upgrading db log bloom bins"
)
for
i
:=
uint64
(
0
);
i
<=
latestBlock
.
NumberU64
();
i
++
{
hash
:=
core
.
GetCanonicalHash
(
db
,
i
)
if
(
hash
==
common
.
Hash
{})
{
return
fmt
.
Errorf
(
"chain db corrupted. Could not find block %d."
,
i
)
}
core
.
WriteMipmapBloom
(
db
,
i
,
core
.
GetBlockReceipts
(
db
,
hash
,
i
))
}
glog
.
V
(
logger
.
Info
)
.
Infoln
(
"upgrade completed in"
,
time
.
Since
(
tstart
))
return
nil
}
eth/filters/api.go
View file @
f9917c8c
...
...
@@ -361,7 +361,7 @@ func (args *NewFilterArgs) UnmarshalJSON(data []byte) error {
if
len
(
raw
)
>=
2
&&
raw
[
0
]
==
'0'
&&
(
raw
[
1
]
==
'x'
||
raw
[
1
]
==
'X'
)
{
raw
=
raw
[
2
:
]
}
if
len
(
raw
)
!=
2
*
common
.
HashLength
{
if
len
(
raw
)
!=
2
*
common
.
HashLength
{
return
common
.
Hash
{},
errors
.
New
(
"invalid topic(s)"
)
}
if
decAddr
,
err
:=
hex
.
DecodeString
(
raw
);
err
==
nil
{
...
...
eth/filters/filter.go
View file @
f9917c8c
...
...
@@ -72,7 +72,8 @@ func (self *Filter) SetTopics(topics [][]common.Hash) {
// Run filters logs with the current parameters set
func
(
self
*
Filter
)
Find
()
vm
.
Logs
{
latestBlock
:=
core
.
GetBlock
(
self
.
db
,
core
.
GetHeadBlockHash
(
self
.
db
))
latestHash
:=
core
.
GetHeadBlockHash
(
self
.
db
)
latestBlock
:=
core
.
GetBlock
(
self
.
db
,
latestHash
,
core
.
GetBlockNumber
(
self
.
db
,
latestHash
))
var
beginBlockNo
uint64
=
uint64
(
self
.
begin
)
if
self
.
begin
==
-
1
{
beginBlockNo
=
latestBlock
.
NumberU64
()
...
...
@@ -127,7 +128,7 @@ func (self *Filter) getLogs(start, end uint64) (logs vm.Logs) {
for
i
:=
start
;
i
<=
end
;
i
++
{
hash
:=
core
.
GetCanonicalHash
(
self
.
db
,
i
)
if
hash
!=
(
common
.
Hash
{})
{
block
=
core
.
GetBlock
(
self
.
db
,
hash
)
block
=
core
.
GetBlock
(
self
.
db
,
hash
,
i
)
}
else
{
// block not found
return
logs
}
...
...
@@ -137,7 +138,7 @@ func (self *Filter) getLogs(start, end uint64) (logs vm.Logs) {
if
self
.
bloomFilter
(
block
)
{
// Get the logs of the block
var
(
receipts
=
core
.
GetBlockReceipts
(
self
.
db
,
block
.
Hash
())
receipts
=
core
.
GetBlockReceipts
(
self
.
db
,
block
.
Hash
()
,
i
)
unfiltered
vm
.
Logs
)
for
_
,
receipt
:=
range
receipts
{
...
...
eth/filters/filter_test.go
View file @
f9917c8c
...
...
@@ -94,7 +94,7 @@ func BenchmarkMipmaps(b *testing.B) {
if
err
:=
core
.
WriteHeadBlockHash
(
db
,
block
.
Hash
());
err
!=
nil
{
b
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
}
if
err
:=
core
.
WriteBlockReceipts
(
db
,
block
.
Hash
(),
receipts
[
i
]);
err
!=
nil
{
if
err
:=
core
.
WriteBlockReceipts
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
receipts
[
i
]);
err
!=
nil
{
b
.
Fatal
(
"error writing block receipts:"
,
err
)
}
}
...
...
@@ -196,7 +196,7 @@ func TestFilters(t *testing.T) {
if
err
:=
core
.
WriteHeadBlockHash
(
db
,
block
.
Hash
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
}
if
err
:=
core
.
WriteBlockReceipts
(
db
,
block
.
Hash
(),
receipts
[
i
]);
err
!=
nil
{
if
err
:=
core
.
WriteBlockReceipts
(
db
,
block
.
Hash
(),
block
.
NumberU64
(),
receipts
[
i
]);
err
!=
nil
{
t
.
Fatal
(
"error writing block receipts:"
,
err
)
}
}
...
...
eth/gasprice.go
View file @
f9917c8c
...
...
@@ -166,7 +166,7 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
func
(
self
*
GasPriceOracle
)
lowestPrice
(
block
*
types
.
Block
)
*
big
.
Int
{
gasUsed
:=
big
.
NewInt
(
0
)
receipts
:=
core
.
GetBlockReceipts
(
self
.
eth
.
ChainDb
(),
block
.
Hash
())
receipts
:=
core
.
GetBlockReceipts
(
self
.
eth
.
ChainDb
(),
block
.
Hash
()
,
block
.
NumberU64
()
)
if
len
(
receipts
)
>
0
{
if
cgu
:=
receipts
[
len
(
receipts
)
-
1
]
.
CumulativeGasUsed
;
cgu
!=
nil
{
gasUsed
=
receipts
[
len
(
receipts
)
-
1
]
.
CumulativeGasUsed
...
...
eth/handler.go
View file @
f9917c8c
...
...
@@ -152,9 +152,9 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int,
return
nil
,
errIncompatibleConfig
}
// Construct the different synchronisation mechanisms
manager
.
downloader
=
downloader
.
New
(
chaindb
,
manager
.
eventMux
,
blockchain
.
HasHeader
,
blockchain
.
HasBlockAndState
,
blockchain
.
GetHeader
,
blockchain
.
GetBlock
,
blockchain
.
CurrentHeader
,
blockchain
.
CurrentBlock
,
blockchain
.
CurrentFastBlock
,
blockchain
.
FastSyncCommitHead
,
blockchain
.
GetTd
,
blockchain
.
InsertHeaderChain
,
manager
.
insertChain
,
blockchain
.
InsertReceiptChain
,
blockchain
.
Rollback
,
manager
.
downloader
=
downloader
.
New
(
chaindb
,
manager
.
eventMux
,
blockchain
.
HasHeader
,
blockchain
.
HasBlockAndState
,
blockchain
.
GetHeader
ByHash
,
blockchain
.
GetBlock
ByHash
,
blockchain
.
CurrentHeader
,
blockchain
.
CurrentBlock
,
blockchain
.
CurrentFastBlock
,
blockchain
.
FastSyncCommitHead
,
blockchain
.
GetTd
ByHash
,
blockchain
.
InsertHeaderChain
,
manager
.
insertChain
,
blockchain
.
InsertReceiptChain
,
blockchain
.
Rollback
,
manager
.
removePeer
)
validator
:=
func
(
block
*
types
.
Block
,
parent
*
types
.
Block
)
error
{
...
...
@@ -167,7 +167,7 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int,
atomic
.
StoreUint32
(
&
manager
.
synced
,
1
)
// Mark initial sync done on any fetcher import
return
manager
.
insertChain
(
blocks
)
}
manager
.
fetcher
=
fetcher
.
New
(
blockchain
.
GetBlock
,
validator
,
manager
.
BroadcastBlock
,
heighter
,
inserter
,
manager
.
removePeer
)
manager
.
fetcher
=
fetcher
.
New
(
blockchain
.
GetBlock
ByHash
,
validator
,
manager
.
BroadcastBlock
,
heighter
,
inserter
,
manager
.
removePeer
)
if
blockchain
.
Genesis
()
.
Hash
()
.
Hex
()
==
defaultGenesisHash
&&
networkId
==
1
{
glog
.
V
(
logger
.
Debug
)
.
Infoln
(
"Bad Block Reporting is enabled"
)
...
...
@@ -382,7 +382,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return
errResp
(
ErrDecode
,
"msg %v: %v"
,
msg
,
err
)
}
// Retrieve the requested block, stopping if enough was found
if
block
:=
pm
.
blockchain
.
GetBlock
(
hash
);
block
!=
nil
{
if
block
:=
pm
.
blockchain
.
GetBlock
ByHash
(
hash
);
block
!=
nil
{
blocks
=
append
(
blocks
,
block
)
bytes
+=
block
.
Size
()
}
...
...
@@ -425,13 +425,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Retrieve the next header satisfying the query
var
origin
*
types
.
Header
if
hashMode
{
origin
=
pm
.
blockchain
.
GetHeader
(
query
.
Origin
.
Hash
)
origin
=
pm
.
blockchain
.
GetHeader
ByHash
(
query
.
Origin
.
Hash
)
}
else
{
origin
=
pm
.
blockchain
.
GetHeaderByNumber
(
query
.
Origin
.
Number
)
}
if
origin
==
nil
{
break
}
number
:=
origin
.
Number
.
Uint64
()
headers
=
append
(
headers
,
origin
)
bytes
+=
estHeaderRlpSize
...
...
@@ -440,8 +441,9 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
case
query
.
Origin
.
Hash
!=
(
common
.
Hash
{})
&&
query
.
Reverse
:
// Hash based traversal towards the genesis block
for
i
:=
0
;
i
<
int
(
query
.
Skip
)
+
1
;
i
++
{
if
header
:=
pm
.
blockchain
.
GetHeader
(
query
.
Origin
.
Hash
);
header
!=
nil
{
if
header
:=
pm
.
blockchain
.
GetHeader
(
query
.
Origin
.
Hash
,
number
);
header
!=
nil
{
query
.
Origin
.
Hash
=
header
.
ParentHash
number
--
}
else
{
unknown
=
true
break
...
...
@@ -602,9 +604,9 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return
errResp
(
ErrDecode
,
"msg %v: %v"
,
msg
,
err
)
}
// Retrieve the requested block's receipts, skipping if unknown to us
results
:=
core
.
GetBlockReceipts
(
pm
.
chaindb
,
hash
)
results
:=
core
.
GetBlockReceipts
(
pm
.
chaindb
,
hash
,
core
.
GetBlockNumber
(
pm
.
chaindb
,
hash
)
)
if
results
==
nil
{
if
header
:=
pm
.
blockchain
.
GetHeader
(
hash
);
header
==
nil
||
header
.
ReceiptHash
!=
types
.
EmptyRootHash
{
if
header
:=
pm
.
blockchain
.
GetHeader
ByHash
(
hash
);
header
==
nil
||
header
.
ReceiptHash
!=
types
.
EmptyRootHash
{
continue
}
}
...
...
@@ -697,7 +699,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Update the peers total difficulty if needed, schedule a download if gapped
if
request
.
TD
.
Cmp
(
p
.
Td
())
>
0
{
p
.
SetTd
(
request
.
TD
)
td
:=
pm
.
blockchain
.
GetTd
(
pm
.
blockchain
.
CurrentBlock
()
.
Hash
())
currentBlock
:=
pm
.
blockchain
.
CurrentBlock
()
td
:=
pm
.
blockchain
.
GetTd
(
currentBlock
.
Hash
(),
currentBlock
.
NumberU64
())
if
request
.
TD
.
Cmp
(
new
(
big
.
Int
)
.
Add
(
td
,
request
.
Block
.
Difficulty
()))
>
0
{
go
pm
.
synchronise
(
p
)
}
...
...
@@ -738,8 +741,8 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
if
propagate
{
// Calculate the TD of the block (it's not imported yet, so block.Td is not valid)
var
td
*
big
.
Int
if
parent
:=
pm
.
blockchain
.
GetBlock
(
block
.
ParentHash
());
parent
!=
nil
{
td
=
new
(
big
.
Int
)
.
Add
(
block
.
Difficulty
(),
pm
.
blockchain
.
GetTd
(
block
.
ParentHash
()))
if
parent
:=
pm
.
blockchain
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
);
parent
!=
nil
{
td
=
new
(
big
.
Int
)
.
Add
(
block
.
Difficulty
(),
pm
.
blockchain
.
GetTd
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
))
}
else
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"propagating dangling block #%d [%x]"
,
block
.
NumberU64
(),
hash
[
:
4
])
return
...
...
@@ -807,10 +810,11 @@ type EthNodeInfo struct {
// NodeInfo retrieves some protocol metadata about the running host node.
func
(
self
*
ProtocolManager
)
NodeInfo
()
*
EthNodeInfo
{
currentBlock
:=
self
.
blockchain
.
CurrentBlock
()
return
&
EthNodeInfo
{
Network
:
self
.
networkId
,
Difficulty
:
self
.
blockchain
.
GetTd
(
self
.
blockchain
.
CurrentBlock
()
.
Hash
()),
Difficulty
:
self
.
blockchain
.
GetTd
(
currentBlock
.
Hash
(),
currentBlock
.
NumberU64
()),
Genesis
:
self
.
blockchain
.
Genesis
()
.
Hash
(),
Head
:
self
.
blockchain
.
CurrentBlock
()
.
Hash
(),
Head
:
currentBlock
.
Hash
(),
}
}
eth/handler_test.go
View file @
f9917c8c
...
...
@@ -91,7 +91,7 @@ func testGetBlockHashes(t *testing.T, protocol int) {
// Assemble the hash response we would like to receive
resp
:=
make
([]
common
.
Hash
,
tt
.
result
)
if
len
(
resp
)
>
0
{
from
:=
pm
.
blockchain
.
GetBlock
(
tt
.
origin
)
.
NumberU64
()
-
1
from
:=
pm
.
blockchain
.
GetBlock
ByHash
(
tt
.
origin
)
.
NumberU64
()
-
1
for
j
:=
0
;
j
<
len
(
resp
);
j
++
{
resp
[
j
]
=
pm
.
blockchain
.
GetBlockByNumber
(
uint64
(
int
(
from
)
-
j
))
.
Hash
()
}
...
...
@@ -204,7 +204,7 @@ func testGetBlocks(t *testing.T, protocol int) {
for
j
,
hash
:=
range
tt
.
explicit
{
hashes
=
append
(
hashes
,
hash
)
if
tt
.
available
[
j
]
&&
len
(
blocks
)
<
tt
.
expected
{
blocks
=
append
(
blocks
,
pm
.
blockchain
.
GetBlock
(
hash
))
blocks
=
append
(
blocks
,
pm
.
blockchain
.
GetBlock
ByHash
(
hash
))
}
}
// Send the hash request and verify the response
...
...
@@ -339,7 +339,7 @@ func testGetBlockHeaders(t *testing.T, protocol int) {
// Collect the headers to expect in the response
headers
:=
[]
*
types
.
Header
{}
for
_
,
hash
:=
range
tt
.
expect
{
headers
=
append
(
headers
,
pm
.
blockchain
.
GetBlock
(
hash
)
.
Header
())
headers
=
append
(
headers
,
pm
.
blockchain
.
GetBlock
ByHash
(
hash
)
.
Header
())
}
// Send the hash request and verify the response
p2p
.
Send
(
peer
.
app
,
0x03
,
tt
.
query
)
...
...
@@ -420,7 +420,7 @@ func testGetBlockBodies(t *testing.T, protocol int) {
for
j
,
hash
:=
range
tt
.
explicit
{
hashes
=
append
(
hashes
,
hash
)
if
tt
.
available
[
j
]
&&
len
(
bodies
)
<
tt
.
expected
{
block
:=
pm
.
blockchain
.
GetBlock
(
hash
)
block
:=
pm
.
blockchain
.
GetBlock
ByHash
(
hash
)
bodies
=
append
(
bodies
,
&
blockBody
{
Transactions
:
block
.
Transactions
(),
Uncles
:
block
.
Uncles
()})
}
}
...
...
@@ -572,7 +572,7 @@ func testGetReceipt(t *testing.T, protocol int) {
block
:=
pm
.
blockchain
.
GetBlockByNumber
(
i
)
hashes
=
append
(
hashes
,
block
.
Hash
())
receipts
=
append
(
receipts
,
core
.
GetBlockReceipts
(
pm
.
chaindb
,
block
.
Hash
()))
receipts
=
append
(
receipts
,
core
.
GetBlockReceipts
(
pm
.
chaindb
,
block
.
Hash
()
,
block
.
NumberU64
()
))
}
// Send the hash request and verify the response
p2p
.
Send
(
peer
.
app
,
0x0f
,
hashes
)
...
...
eth/sync.go
View file @
f9917c8c
...
...
@@ -162,7 +162,8 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
return
}
// Make sure the peer's TD is higher than our own. If not drop.
td
:=
pm
.
blockchain
.
GetTd
(
pm
.
blockchain
.
CurrentBlock
()
.
Hash
())
currentBlock
:=
pm
.
blockchain
.
CurrentBlock
()
td
:=
pm
.
blockchain
.
GetTd
(
currentBlock
.
Hash
(),
currentBlock
.
NumberU64
())
if
peer
.
Td
()
.
Cmp
(
td
)
<=
0
{
return
}
...
...
miner/worker.go
View file @
f9917c8c
...
...
@@ -272,7 +272,7 @@ func (self *worker) wait() {
go
self
.
mux
.
Post
(
core
.
NewMinedBlockEvent
{
Block
:
block
})
}
else
{
work
.
state
.
Commit
()
parent
:=
self
.
chain
.
GetBlock
(
block
.
ParentHash
())
parent
:=
self
.
chain
.
GetBlock
(
block
.
ParentHash
()
,
block
.
NumberU64
()
-
1
)
if
parent
==
nil
{
glog
.
V
(
logger
.
Error
)
.
Infoln
(
"Invalid block found during mining"
)
continue
...
...
@@ -319,7 +319,7 @@ func (self *worker) wait() {
self
.
mux
.
Post
(
core
.
ChainHeadEvent
{
Block
:
block
})
self
.
mux
.
Post
(
logs
)
}
if
err
:=
core
.
WriteBlockReceipts
(
self
.
chainDb
,
block
.
Hash
(),
receipts
);
err
!=
nil
{
if
err
:=
core
.
WriteBlockReceipts
(
self
.
chainDb
,
block
.
Hash
(),
block
.
NumberU64
(),
receipts
);
err
!=
nil
{
glog
.
V
(
logger
.
Warn
)
.
Infoln
(
"error writing block receipts:"
,
err
)
}
}(
block
,
work
.
state
.
Logs
(),
work
.
receipts
)
...
...
tests/block_test_util.go
View file @
f9917c8c
...
...
@@ -164,7 +164,7 @@ func runBlockTest(homesteadBlock *big.Int, test *BlockTest) error {
return
fmt
.
Errorf
(
"InsertPreState: %v"
,
err
)
}
core
.
WriteTd
(
db
,
test
.
Genesis
.
Hash
(),
test
.
Genesis
.
Difficulty
())
core
.
WriteTd
(
db
,
test
.
Genesis
.
Hash
(),
0
,
test
.
Genesis
.
Difficulty
())
core
.
WriteBlock
(
db
,
test
.
Genesis
)
core
.
WriteCanonicalHash
(
db
,
test
.
Genesis
.
Hash
(),
test
.
Genesis
.
NumberU64
())
core
.
WriteHeadBlockHash
(
db
,
test
.
Genesis
.
Hash
())
...
...
@@ -412,7 +412,7 @@ func (test *BlockTest) ValidateImportedHeaders(cm *core.BlockChain, validBlocks
// block-by-block, so we can only validate imported headers after
// all blocks have been processed by ChainManager, as they may not
// be part of the longest chain until last block is imported.
for
b
:=
cm
.
CurrentBlock
();
b
!=
nil
&&
b
.
NumberU64
()
!=
0
;
b
=
cm
.
GetBlock
(
b
.
Header
()
.
ParentHash
)
{
for
b
:=
cm
.
CurrentBlock
();
b
!=
nil
&&
b
.
NumberU64
()
!=
0
;
b
=
cm
.
GetBlock
ByHash
(
b
.
Header
()
.
ParentHash
)
{
bHash
:=
common
.
Bytes2Hex
(
b
.
Hash
()
.
Bytes
())
// hex without 0x prefix
if
err
:=
validateHeader
(
bmap
[
bHash
]
.
BlockHeader
,
b
.
Header
());
err
!=
nil
{
return
fmt
.
Errorf
(
"Imported block header validation failed: %v"
,
err
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment