Commit c33cc382 authored by Péter Szilágyi's avatar Péter Szilágyi

core: support inserting pure header chains

parent 92f9a3e5
...@@ -369,13 +369,26 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs vm.Logs, err error) ...@@ -369,13 +369,26 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs vm.Logs, err error)
return logs, nil return logs, nil
} }
// ValidateHeader verifies the validity of a header, relying on the database and
// POW behind the block processor.
func (sm *BlockProcessor) ValidateHeader(header *types.Header, checkPow, uncle bool) error {
// Short circuit if the header's already known or its parent missing
if sm.bc.HasHeader(header.Hash()) {
return nil
}
if parent := sm.bc.GetHeader(header.ParentHash); parent == nil {
return ParentError(header.ParentHash)
} else {
return ValidateHeader(sm.Pow, header, parent, checkPow, uncle)
}
}
// See YP section 4.3.4. "Block Header Validity" // See YP section 4.3.4. "Block Header Validity"
// Validates a header. Returns an error if the header is invalid. // Validates a header. Returns an error if the header is invalid.
func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error { func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 { if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
return fmt.Errorf("Header extra data too long (%d)", len(header.Extra)) return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
} }
if uncle { if uncle {
if header.Time.Cmp(common.MaxBig) == 1 { if header.Time.Cmp(common.MaxBig) == 1 {
return BlockTSTooBigErr return BlockTSTooBigErr
......
This diff is collapsed.
This diff is collapsed.
...@@ -211,25 +211,49 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header { ...@@ -211,25 +211,49 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
} }
} }
// newCanonical creates a new deterministic canonical chain by running // newCanonical creates a chain database, and injects a deterministic canonical
// InsertChain on the result of makeChain. // chain. Depending on the full flag, if creates either a full block chain or a
func newCanonical(n int, db ethdb.Database) (*BlockProcessor, error) { // header only chain.
func newCanonical(n int, full bool) (ethdb.Database, *BlockProcessor, error) {
// Create te new chain database
db, _ := ethdb.NewMemDatabase()
evmux := &event.TypeMux{} evmux := &event.TypeMux{}
WriteTestNetGenesisBlock(db, 0) // Initialize a fresh chain with only a genesis block
chainman, _ := NewBlockChain(db, FakePow{}, evmux) genesis, _ := WriteTestNetGenesisBlock(db, 0)
bman := NewBlockProcessor(db, FakePow{}, chainman, evmux)
bman.bc.SetProcessor(bman) blockchain, _ := NewBlockChain(db, FakePow{}, evmux)
parent := bman.bc.CurrentBlock() processor := NewBlockProcessor(db, FakePow{}, blockchain, evmux)
processor.bc.SetProcessor(processor)
// Create and inject the requested chain
if n == 0 { if n == 0 {
return bman, nil return db, processor, nil
}
if full {
// Full block-chain requested
blocks := makeBlockChain(genesis, n, db, canonicalSeed)
_, err := blockchain.InsertChain(blocks)
return db, processor, err
}
// Header-only chain requested
headers := makeHeaderChain(genesis.Header(), n, db, canonicalSeed)
_, err := blockchain.InsertHeaderChain(headers, true)
return db, processor, err
}
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header {
blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, db, seed)
headers := make([]*types.Header, len(blocks))
for i, block := range blocks {
headers[i] = block.Header()
} }
lchain := makeChain(parent, n, db, canonicalSeed) return headers
_, err := bman.bc.InsertChain(lchain)
return bman, err
} }
func makeChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block { // makeBlockChain creates a deterministic chain of blocks rooted at parent.
func makeBlockChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block {
return GenerateChain(parent, db, n, func(i int, b *BlockGen) { return GenerateChain(parent, db, n, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
}) })
......
...@@ -184,7 +184,7 @@ var ( ...@@ -184,7 +184,7 @@ var (
// are ignored and set to values derived from the given txs, uncles // are ignored and set to values derived from the given txs, uncles
// and receipts. // and receipts.
func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt) *Block { func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt) *Block {
b := &Block{header: copyHeader(header), td: new(big.Int)} b := &Block{header: CopyHeader(header), td: new(big.Int)}
// TODO: panic if len(txs) != len(receipts) // TODO: panic if len(txs) != len(receipts)
if len(txs) == 0 { if len(txs) == 0 {
...@@ -210,7 +210,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* ...@@ -210,7 +210,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*
b.header.UncleHash = CalcUncleHash(uncles) b.header.UncleHash = CalcUncleHash(uncles)
b.uncles = make([]*Header, len(uncles)) b.uncles = make([]*Header, len(uncles))
for i := range uncles { for i := range uncles {
b.uncles[i] = copyHeader(uncles[i]) b.uncles[i] = CopyHeader(uncles[i])
} }
} }
...@@ -221,10 +221,12 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* ...@@ -221,10 +221,12 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*
// header data is copied, changes to header and to the field values // header data is copied, changes to header and to the field values
// will not affect the block. // will not affect the block.
func NewBlockWithHeader(header *Header) *Block { func NewBlockWithHeader(header *Header) *Block {
return &Block{header: copyHeader(header)} return &Block{header: CopyHeader(header)}
} }
func copyHeader(h *Header) *Header { // CopyHeader creates a deep copy of a block header to prevent side effects from
// modifying a header variable.
func CopyHeader(h *Header) *Header {
cpy := *h cpy := *h
if cpy.Time = new(big.Int); h.Time != nil { if cpy.Time = new(big.Int); h.Time != nil {
cpy.Time.Set(h.Time) cpy.Time.Set(h.Time)
...@@ -326,7 +328,7 @@ func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } ...@@ -326,7 +328,7 @@ func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
func (b *Block) UncleHash() common.Hash { return b.header.UncleHash } func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
func (b *Block) Header() *Header { return copyHeader(b.header) } func (b *Block) Header() *Header { return CopyHeader(b.header) }
func (b *Block) HashNoNonce() common.Hash { func (b *Block) HashNoNonce() common.Hash {
return b.header.HashNoNonce() return b.header.HashNoNonce()
...@@ -370,13 +372,13 @@ func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block { ...@@ -370,13 +372,13 @@ func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block {
// WithBody returns a new block with the given transaction and uncle contents. // WithBody returns a new block with the given transaction and uncle contents.
func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block {
block := &Block{ block := &Block{
header: copyHeader(b.header), header: CopyHeader(b.header),
transactions: make([]*Transaction, len(transactions)), transactions: make([]*Transaction, len(transactions)),
uncles: make([]*Header, len(uncles)), uncles: make([]*Header, len(uncles)),
} }
copy(block.transactions, transactions) copy(block.transactions, transactions)
for i := range uncles { for i := range uncles {
block.uncles[i] = copyHeader(uncles[i]) block.uncles[i] = CopyHeader(uncles[i])
} }
return block return block
} }
......
...@@ -464,7 +464,7 @@ func (s *Ethereum) NodeInfo() *NodeInfo { ...@@ -464,7 +464,7 @@ func (s *Ethereum) NodeInfo() *NodeInfo {
DiscPort: int(node.UDP), DiscPort: int(node.UDP),
TCPPort: int(node.TCP), TCPPort: int(node.TCP),
ListenAddr: s.net.ListenAddr, ListenAddr: s.net.ListenAddr,
Td: s.BlockChain().Td().String(), Td: s.BlockChain().GetTd(s.BlockChain().CurrentBlock().Hash()).String(),
} }
} }
......
...@@ -589,15 +589,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { ...@@ -589,15 +589,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} }
request.Block.ReceivedAt = msg.ReceivedAt request.Block.ReceivedAt = msg.ReceivedAt
// Mark the block's arrival for whatever reason
_, chainHead, _ := pm.blockchain.Status()
jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{
BlockHash: request.Block.Hash().Hex(),
BlockNumber: request.Block.Number(),
ChainHeadHash: chainHead.Hex(),
BlockPrevHash: request.Block.ParentHash().Hex(),
RemoteId: p.ID().String(),
})
// Mark the peer as owning the block and schedule it for import // Mark the peer as owning the block and schedule it for import
p.MarkBlock(request.Block.Hash()) p.MarkBlock(request.Block.Hash())
p.SetHead(request.Block.Hash()) p.SetHead(request.Block.Hash())
...@@ -607,7 +598,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { ...@@ -607,7 +598,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Update the peers total difficulty if needed, schedule a download if gapped // Update the peers total difficulty if needed, schedule a download if gapped
if request.TD.Cmp(p.Td()) > 0 { if request.TD.Cmp(p.Td()) > 0 {
p.SetTd(request.TD) p.SetTd(request.TD)
if request.TD.Cmp(new(big.Int).Add(pm.blockchain.Td(), request.Block.Difficulty())) > 0 { td := pm.blockchain.GetTd(pm.blockchain.CurrentBlock().Hash())
if request.TD.Cmp(new(big.Int).Add(td, request.Block.Difficulty())) > 0 {
go pm.synchronise(p) go pm.synchronise(p)
} }
} }
...@@ -624,12 +616,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { ...@@ -624,12 +616,6 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return errResp(ErrDecode, "transaction %d is nil", i) return errResp(ErrDecode, "transaction %d is nil", i)
} }
p.MarkTransaction(tx.Hash()) p.MarkTransaction(tx.Hash())
// Log it's arrival for later analysis
jsonlogger.LogJson(&logger.EthTxReceived{
TxHash: tx.Hash().Hex(),
RemoteId: p.ID().String(),
})
} }
pm.txpool.AddTransactions(txs) pm.txpool.AddTransactions(txs)
......
...@@ -160,7 +160,8 @@ func (pm *ProtocolManager) synchronise(peer *peer) { ...@@ -160,7 +160,8 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
return return
} }
// Make sure the peer's TD is higher than our own. If not drop. // Make sure the peer's TD is higher than our own. If not drop.
if peer.Td().Cmp(pm.blockchain.Td()) <= 0 { td := pm.blockchain.GetTd(pm.blockchain.CurrentBlock().Hash())
if peer.Td().Cmp(td) <= 0 {
return return
} }
// Otherwise try to sync with the downloader // Otherwise try to sync with the downloader
......
...@@ -146,13 +146,7 @@ func (self *debugApi) SetHead(req *shared.Request) (interface{}, error) { ...@@ -146,13 +146,7 @@ func (self *debugApi) SetHead(req *shared.Request) (interface{}, error) {
if err := self.codec.Decode(req.Params, &args); err != nil { if err := self.codec.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error()) return nil, shared.NewDecodeParamError(err.Error())
} }
self.ethereum.BlockChain().SetHead(uint64(args.BlockNumber))
block := self.xeth.EthBlockByNumber(args.BlockNumber)
if block == nil {
return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
}
self.ethereum.BlockChain().SetHead(block)
return nil, nil return nil, nil
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment