Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix verify header vbft peerinfo data race #1253

Merged
merged 4 commits into from
Jul 7, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
91 changes: 55 additions & 36 deletions core/store/ledgerstore/ledger_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ type LedgerStoreImp struct {
currBlockHash common.Uint256 //Current block hash
headerCache map[common.Uint256]*types.Header //BlockHash => Header
headerIndex map[uint32]common.Uint256 //Header index, Mapping header height => block hash
vbftPeerInfoheader map[string]uint32 //pubInfo save pubkey,peerindex
vbftPeerInfoblock map[string]uint32 //pubInfo save pubkey,peerindex
vbftPeerInfoMap map[uint32]map[string]uint32 //key:block height,value:peerInfo
lock sync.RWMutex
stateHashCheckHeight uint32

Expand All @@ -102,8 +101,7 @@ func NewLedgerStore(dataDir string, stateHashHeight uint32) (*LedgerStoreImp, er
ledgerStore := &LedgerStoreImp{
headerIndex: make(map[uint32]common.Uint256),
headerCache: make(map[common.Uint256]*types.Header, 0),
vbftPeerInfoheader: make(map[string]uint32),
vbftPeerInfoblock: make(map[string]uint32),
vbftPeerInfoMap: make(map[uint32]map[string]uint32),
savingBlockSemaphore: make(chan bool, 1),
stateHashCheckHeight: stateHashHeight,
}
Expand Down Expand Up @@ -206,8 +204,10 @@ func (this *LedgerStoreImp) InitLedgerStoreWithGenesisBlock(genesisBlock *types.
return err
}
var cfg *vconfig.ChainConfig
var chainConfigHeight uint32
if blkInfo.NewChainConfig != nil {
cfg = blkInfo.NewChainConfig
chainConfigHeight = header.Height
} else {
cfgHeader, err := this.GetHeaderByHeight(blkInfo.LastConfigBlockNum)
if err != nil {
Expand All @@ -221,16 +221,17 @@ func (this *LedgerStoreImp) InitLedgerStoreWithGenesisBlock(genesisBlock *types.
return fmt.Errorf("getNewChainConfig error block num:%d", blkInfo.LastConfigBlockNum)
}
cfg = Info.NewChainConfig
chainConfigHeight = cfgHeader.Height
}
this.lock.Lock()
this.vbftPeerInfoheader = make(map[string]uint32)
this.vbftPeerInfoblock = make(map[string]uint32)
vbftPeerInfo := make(map[string]uint32)
this.vbftPeerInfoMap = make(map[uint32]map[string]uint32)
for _, p := range cfg.Peers {
this.vbftPeerInfoheader[p.ID] = p.Index
this.vbftPeerInfoblock[p.ID] = p.Index
vbftPeerInfo[p.ID] = p.Index
}
this.vbftPeerInfoMap[chainConfigHeight] = vbftPeerInfo
this.lock.Unlock()
val, _ := json.Marshal(this.vbftPeerInfoblock)
val, _ := json.Marshal(vbftPeerInfo)
log.Infof("loading vbftPeerInfo at height: %s : %s", header.Height, string(val))
}
// check and fix imcompatible states
Expand Down Expand Up @@ -431,33 +432,57 @@ func (this *LedgerStoreImp) getHeaderCache(blockHash common.Uint256) *types.Head
return header
}

func (this *LedgerStoreImp) verifyHeader(header *types.Header, vbftPeerInfo map[string]uint32) (map[string]uint32, error) {
func (this *LedgerStoreImp) verifyHeader(header *types.Header) error {
if header.Height == 0 {
return vbftPeerInfo, nil
return nil
}
var prevHeader *types.Header
prevHeaderHash := header.PrevBlockHash
prevHeader, err := this.GetHeaderByHash(prevHeaderHash)
if err != nil && err != scom.ErrNotFound {
return vbftPeerInfo, fmt.Errorf("get prev header error %s", err)
return fmt.Errorf("get prev header error %s", err)
}
if prevHeader == nil {
return vbftPeerInfo, fmt.Errorf("cannot find pre header by blockHash %s", prevHeaderHash.ToHexString())
return fmt.Errorf("cannot find pre header by blockHash %s", prevHeaderHash.ToHexString())
}

if prevHeader.Height+1 != header.Height {
return vbftPeerInfo, fmt.Errorf("block height is incorrect")
return fmt.Errorf("block height is incorrect")
}

if prevHeader.Timestamp >= header.Timestamp {
return vbftPeerInfo, fmt.Errorf("block timestamp is incorrect")
return fmt.Errorf("block timestamp is incorrect")
}
consensusType := strings.ToLower(config.DefConfig.Genesis.ConsensusType)
if consensusType == "vbft" {
//check bookkeeppers
blkInfo, err := vconfig.VbftBlock(header)
if err != nil {
return err
}
var chainConfigHeight uint32
if blkInfo.NewChainConfig != nil {
prevBlockInfo, err := vconfig.VbftBlock(prevHeader)
if err != nil {
return err
}
if prevBlockInfo.NewChainConfig != nil {
chainConfigHeight = prevHeader.Height
} else {
chainConfigHeight = prevBlockInfo.LastConfigBlockNum
}
} else {
chainConfigHeight = blkInfo.LastConfigBlockNum
}
this.lock.RLock()
vbftPeerInfo, ok := this.vbftPeerInfoMap[chainConfigHeight]
if !ok {
this.lock.RUnlock()
return fmt.Errorf("chainconfig height:%d not found", chainConfigHeight)
}
this.lock.RUnlock()
m := len(vbftPeerInfo) - (len(vbftPeerInfo)*6)/7
if len(header.Bookkeepers) < m {
return vbftPeerInfo, fmt.Errorf("header Bookkeepers %d more than 6/7 len vbftPeerInfo%d", len(header.Bookkeepers), len(vbftPeerInfo))
return fmt.Errorf("header Bookkeepers %d more than 6/7 len vbftPeerInfo%d", len(header.Bookkeepers), len(vbftPeerInfo))
}
for _, bookkeeper := range header.Bookkeepers {
pubkey := vconfig.PubkeyID(bookkeeper)
Expand All @@ -466,45 +491,41 @@ func (this *LedgerStoreImp) verifyHeader(header *types.Header, vbftPeerInfo map[
val, _ := json.Marshal(vbftPeerInfo)
log.Errorf("verify header error: invalid pubkey :%v, height:%d, current vbftPeerInfo :%s",
pubkey, header.Height, string(val))

return vbftPeerInfo, fmt.Errorf("verify header error: invalid pubkey : %v", pubkey)
return fmt.Errorf("verify header error: invalid pubkey : %v", pubkey)
}
}
hash := header.Hash()
err = signature.VerifyMultiSignature(hash[:], header.Bookkeepers, m, header.SigData)
if err != nil {
log.Errorf("VerifyMultiSignature:%s,Bookkeepers:%d,pubkey:%d,heigh:%d", err, len(header.Bookkeepers), len(vbftPeerInfo), header.Height)
return vbftPeerInfo, err
}
blkInfo, err := vconfig.VbftBlock(header)
if err != nil {
return vbftPeerInfo, err
return err
}
if blkInfo.NewChainConfig != nil {
peerInfo := make(map[string]uint32)
for _, p := range blkInfo.NewChainConfig.Peers {
peerInfo[p.ID] = p.Index
}
return peerInfo, nil
this.lock.Lock()
this.vbftPeerInfoMap[header.Height] = peerInfo
xiemylogos marked this conversation as resolved.
Show resolved Hide resolved
this.lock.Unlock()
xiemylogos marked this conversation as resolved.
Show resolved Hide resolved
}
return vbftPeerInfo, nil
} else {
address, err := types.AddressFromBookkeepers(header.Bookkeepers)
if err != nil {
return vbftPeerInfo, err
return err
}
if prevHeader.NextBookkeeper != address {
return vbftPeerInfo, fmt.Errorf("bookkeeper address error")
return fmt.Errorf("bookkeeper address error")
}

m := len(header.Bookkeepers) - (len(header.Bookkeepers)-1)/3
hash := header.Hash()
err = signature.VerifyMultiSignature(hash[:], header.Bookkeepers, m, header.SigData)
if err != nil {
return vbftPeerInfo, err
return err
}
}
return vbftPeerInfo, nil
return nil
}

func (this *LedgerStoreImp) verifyCrossChainMsg(crossChainMsg *types.CrossChainMsg, bookkeepers []keypair.PublicKey) error {
Expand Down Expand Up @@ -533,8 +554,8 @@ func (this *LedgerStoreImp) AddHeader(header *types.Header) error {
if header.Height != nextHeaderHeight {
return fmt.Errorf("header height %d not equal next header height %d", header.Height, nextHeaderHeight)
}
var err error
this.vbftPeerInfoheader, err = this.verifyHeader(header, this.vbftPeerInfoheader)
err := this.verifyHeader(header)
//this.vbftPeerInfoheader, err = this.verifyHeader(header, this.vbftPeerInfoheader)
if err != nil {
return fmt.Errorf("verifyHeader error %s", err)
}
Expand Down Expand Up @@ -597,8 +618,7 @@ func (this *LedgerStoreImp) SubmitBlock(block *types.Block, ccMsg *types.CrossCh
return fmt.Errorf("block height %d not equal next block height %d", blockHeight, nextBlockHeight)
}

var err error
this.vbftPeerInfoblock, err = this.verifyHeader(block.Header, this.vbftPeerInfoblock)
err := this.verifyHeader(block.Header)
if err != nil {
return fmt.Errorf("verifyHeader error %s", err)
}
Expand Down Expand Up @@ -641,8 +661,7 @@ func (this *LedgerStoreImp) AddBlock(block *types.Block, ccMsg *types.CrossChain
if blockHeight != nextBlockHeight {
return fmt.Errorf("block height %d not equal next block height %d", blockHeight, nextBlockHeight)
}
var err error
this.vbftPeerInfoblock, err = this.verifyHeader(block.Header, this.vbftPeerInfoblock)
err := this.verifyHeader(block.Header)
if err != nil {
return fmt.Errorf("verifyHeader error %s", err)
}
Expand Down