Gracefully exit geth command(#4)

This commit is contained in:
Elizabeth 2019-02-11 16:08:18 -06:00 committed by GitHub
parent b2ba24509b
commit 61f2ddfcc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 123 additions and 33 deletions

View File

@ -49,34 +49,69 @@ func (StateDiffService) APIs() []rpc.API {
return []rpc.API{} return []rpc.API{}
} }
func (sds *StateDiffService) Loop(events chan core.ChainEvent) { func (sds *StateDiffService) Loop(chainEventCh chan core.ChainEvent) {
for elem := range events { chainEventSub := sds.BlockChain.SubscribeChainEvent(chainEventCh)
currentBlock := elem.Block defer chainEventSub.Unsubscribe()
parentHash := currentBlock.ParentHash()
parentBlock := sds.BlockChain.GetBlockByHash(parentHash)
stateDiffLocation, err := sds.Extractor.ExtractStateDiff(*parentBlock, *currentBlock) blocksCh := make(chan *types.Block, 10)
if err != nil { errCh := chainEventSub.Err()
log.Error("Error extracting statediff", "block number", currentBlock.Number(), "error", err) quitCh := make(chan struct{})
} else {
log.Info("Statediff extracted", "block number", currentBlock.Number(), "location", stateDiffLocation) go func() {
HandleChainEventChLoop:
for {
select {
//Notify chain event channel of events
case chainEvent := <-chainEventCh:
log.Debug("Event received from chainEventCh", "event", chainEvent)
blocksCh <- chainEvent.Block
//if node stopped
case err := <-errCh:
log.Warn("Error from chain event subscription, breaking loop.", "error", err)
break HandleChainEventChLoop
}
}
close(quitCh)
}()
//loop through chain events until no more
HandleBlockChLoop:
for {
select {
case block := <-blocksCh:
currentBlock := block
parentHash := currentBlock.ParentHash()
parentBlock := sds.BlockChain.GetBlockByHash(parentHash)
if parentBlock == nil {
log.Error("Parent block is nil, skipping this block",
"parent block hash", parentHash.String(),
"current block number", currentBlock.Number())
break HandleBlockChLoop
}
stateDiffLocation, err := sds.Extractor.ExtractStateDiff(*parentBlock, *currentBlock)
if err != nil {
log.Error("Error extracting statediff", "block number", currentBlock.Number(), "error", err)
} else {
log.Info("Statediff extracted", "block number", currentBlock.Number(), "location", stateDiffLocation)
}
case <-quitCh:
log.Debug("Quitting the statediff block channel")
return
} }
} }
} }
var eventsChannel chan core.ChainEvent
func (sds *StateDiffService) Start(server *p2p.Server) error { func (sds *StateDiffService) Start(server *p2p.Server) error {
log.Info("Starting statediff service") log.Info("Starting statediff service")
eventsChannel := make(chan core.ChainEvent, 10)
sds.BlockChain.SubscribeChainEvent(eventsChannel) chainEventCh := make(chan core.ChainEvent, 10)
go sds.Loop(eventsChannel) go sds.Loop(chainEventCh)
return nil return nil
} }
func (StateDiffService) Stop() error { func (StateDiffService) Stop() error {
log.Info("Stopping statediff service") log.Info("Stopping statediff service")
close(eventsChannel)
return nil return nil
} }

View File

@ -9,16 +9,17 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
service2 "github.com/ethereum/go-ethereum/statediff/service" s "github.com/ethereum/go-ethereum/statediff/service"
"github.com/ethereum/go-ethereum/statediff/testhelpers/mocks" "github.com/ethereum/go-ethereum/statediff/testhelpers/mocks"
) )
func TestServiceLoop(t *testing.T) { func TestServiceLoop(t *testing.T) {
testServiceLoop(t) testErrorInChainEventLoop(t)
testErrorInBlockLoop(t)
} }
var ( var (
eventsChannel = make(chan core.ChainEvent, 10) eventsChannel = make(chan core.ChainEvent, 1)
parentHeader1 = types.Header{Number: big.NewInt(rand.Int63())} parentHeader1 = types.Header{Number: big.NewInt(rand.Int63())}
parentHeader2 = types.Header{Number: big.NewInt(rand.Int63())} parentHeader2 = types.Header{Number: big.NewInt(rand.Int63())}
@ -31,29 +32,30 @@ var (
header1 = types.Header{ParentHash: parentHash1} header1 = types.Header{ParentHash: parentHash1}
header2 = types.Header{ParentHash: parentHash2} header2 = types.Header{ParentHash: parentHash2}
header3 = types.Header{ParentHash: common.HexToHash("parent hash")}
block1 = types.NewBlock(&header1, nil, nil, nil) block1 = types.NewBlock(&header1, nil, nil, nil)
block2 = types.NewBlock(&header2, nil, nil, nil) block2 = types.NewBlock(&header2, nil, nil, nil)
block3 = types.NewBlock(&header3, nil, nil, nil)
event1 = core.ChainEvent{Block: block1} event1 = core.ChainEvent{Block: block1}
event2 = core.ChainEvent{Block: block2} event2 = core.ChainEvent{Block: block2}
event3 = core.ChainEvent{Block: block3}
) )
func testServiceLoop(t *testing.T) { func testErrorInChainEventLoop(t *testing.T) {
eventsChannel <- event1 //the first chain event causes and error (in blockchain mock)
eventsChannel <- event2
extractor := mocks.Extractor{} extractor := mocks.Extractor{}
close(eventsChannel)
blockChain := mocks.BlockChain{} blockChain := mocks.BlockChain{}
service := service2.StateDiffService{ service := s.StateDiffService{
Builder: nil, Builder: nil,
Extractor: &extractor, Extractor: &extractor,
BlockChain: &blockChain, BlockChain: &blockChain,
} }
blockChain.SetParentBlockToReturn([]*types.Block{parentBlock1, parentBlock2}) blockChain.SetParentBlocksToReturn([]*types.Block{parentBlock1, parentBlock2})
blockChain.SetChainEvents([]core.ChainEvent{event1, event2, event3})
service.Loop(eventsChannel) service.Loop(eventsChannel)
//parent and current blocks are passed to the extractor //parent and current blocks are passed to the extractor
@ -75,3 +77,31 @@ func testServiceLoop(t *testing.T) {
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", blockChain.ParentHashesLookedUp, expectedHashes) t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", blockChain.ParentHashesLookedUp, expectedHashes)
} }
} }
func testErrorInBlockLoop(t *testing.T) {
//second block's parent block can't be found
extractor := mocks.Extractor{}
blockChain := mocks.BlockChain{}
service := s.StateDiffService{
Builder: nil,
Extractor: &extractor,
BlockChain: &blockChain,
}
blockChain.SetParentBlocksToReturn([]*types.Block{parentBlock1, nil})
blockChain.SetChainEvents([]core.ChainEvent{event1, event2})
service.Loop(eventsChannel)
//only the first current block (and it's parent) are passed to the extractor
expectedCurrentBlocks := []types.Block{*block1}
if !reflect.DeepEqual(extractor.CurrentBlocks, expectedCurrentBlocks) {
t.Error("Test failure:", t.Name())
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", extractor.CurrentBlocks, expectedCurrentBlocks)
}
expectedParentBlocks := []types.Block{*parentBlock1}
if !reflect.DeepEqual(extractor.ParentBlocks, expectedParentBlocks) {
t.Error("Test failure:", t.Name())
t.Logf("Actual does not equal expected.\nactual:%+v\nexpected: %+v", extractor.CurrentBlocks, expectedParentBlocks)
}
}

View File

@ -1,6 +1,8 @@
package mocks package mocks
import ( import (
"errors"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -11,24 +13,47 @@ type BlockChain struct {
ParentHashesLookedUp []common.Hash ParentHashesLookedUp []common.Hash
parentBlocksToReturn []*types.Block parentBlocksToReturn []*types.Block
callCount int callCount int
ChainEvents []core.ChainEvent
} }
func (mc *BlockChain) SetParentBlockToReturn(blocks []*types.Block) { func (mc *BlockChain) SetParentBlocksToReturn(blocks []*types.Block) {
mc.parentBlocksToReturn = blocks mc.parentBlocksToReturn = blocks
} }
func (mc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block { func (mc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block {
mc.ParentHashesLookedUp = append(mc.ParentHashesLookedUp, hash) mc.ParentHashesLookedUp = append(mc.ParentHashesLookedUp, hash)
var parentBlock types.Block var parentBlock *types.Block
if len(mc.parentBlocksToReturn) > 0 { if len(mc.parentBlocksToReturn) > 0 {
parentBlock = *mc.parentBlocksToReturn[mc.callCount] parentBlock = mc.parentBlocksToReturn[mc.callCount]
} }
mc.callCount++ mc.callCount++
return &parentBlock return parentBlock
} }
func (BlockChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { func (bc *BlockChain) SetChainEvents(chainEvents []core.ChainEvent) {
panic("implement me") bc.ChainEvents = chainEvents
}
func (bc *BlockChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
subErr := errors.New("Subscription Error")
var eventCounter int
subscription := event.NewSubscription(func(quit <-chan struct{}) error {
for _, chainEvent := range bc.ChainEvents {
if eventCounter > 1 {
return subErr
}
select {
case ch <- chainEvent:
case <-quit:
return nil
}
eventCounter++
}
return nil
})
return subscription
} }