X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=protocol%2Fblock.go;h=0eafe2799eebc33cfb5f35a3fd9f2e479a1dd2f4;hb=5d074a5954520a5d385683a1fc254df70fa9d25c;hp=f91c33d9a5a60b3045bb96949cea39c9d4e48008;hpb=e57f41f037f3f37fd7253e34f8a04e60a125e634;p=bytom%2Fvapor.git diff --git a/protocol/block.go b/protocol/block.go index f91c33d9..0eafe279 100644 --- a/protocol/block.go +++ b/protocol/block.go @@ -1,17 +1,11 @@ package protocol import ( - "encoding/json" - - "github.com/vapor/protocol/vm" - log "github.com/sirupsen/logrus" - "github.com/vapor/common" - "github.com/vapor/consensus" - engine "github.com/vapor/consensus/consensus" - dpos "github.com/vapor/consensus/consensus/dpos" + "github.com/vapor/config" "github.com/vapor/errors" + "github.com/vapor/event" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" "github.com/vapor/protocol/state" @@ -28,7 +22,10 @@ var ( // BlockExist check is a block in chain or orphan func (c *Chain) BlockExist(hash *bc.Hash) bool { - return c.index.BlockExist(hash) || c.orphanManage.BlockExist(hash) + if _, err := c.store.GetBlockHeader(hash); err == nil { + return true + } + return c.orphanManage.BlockExist(hash) } // GetBlockByHash return a block by given hash @@ -36,49 +33,59 @@ func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) { return c.store.GetBlock(hash) } -// GetBlockByHeight return a block header by given height +// GetBlockByHeight return a block by given height func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) { - node := c.index.NodeByHeight(height) - if node == nil { - return nil, errors.New("can't find block in given height") + hash, err := c.store.GetMainChainHash(height) + if err != nil { + return nil, errors.Wrap(err, "can't find block in given height") } - return c.store.GetBlock(&node.Hash) + return c.store.GetBlock(hash) } // GetHeaderByHash return a block header by given hash func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) { - node := c.index.GetNode(hash) - if node == nil { - return nil, errors.New("can't find block header in given hash") - } - return node.BlockHeader(), nil + return c.store.GetBlockHeader(hash) } // GetHeaderByHeight return a block header by given height func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) { - node := c.index.NodeByHeight(height) - if node == nil { - return nil, errors.New("can't find block header in given height") + hash, err := c.store.GetMainChainHash(height) + if err != nil { + return nil, errors.Wrap(err, "can't find block header in given height") } - return node.BlockHeader(), nil + return c.store.GetBlockHeader(hash) } -func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) { - var attachNodes []*state.BlockNode - var detachNodes []*state.BlockNode +func (c *Chain) calcReorganizeChain(beginAttach *types.BlockHeader, beginDetach *types.BlockHeader) ([]*types.BlockHeader, []*types.BlockHeader, error) { + var err error + var attachBlockHeaders []*types.BlockHeader + var detachBlockHeaders []*types.BlockHeader - attachNode := node - for c.index.NodeByHeight(attachNode.Height) != attachNode { - attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...) - attachNode = attachNode.Parent - } + for attachBlockHeader, detachBlockHeader := beginAttach, beginDetach; detachBlockHeader.Hash() != attachBlockHeader.Hash(); { + var attachRollback, detachRollBack bool + if attachRollback = attachBlockHeader.Height >= detachBlockHeader.Height; attachRollback { + attachBlockHeaders = append([]*types.BlockHeader{attachBlockHeader}, attachBlockHeaders...) + } + + if detachRollBack = attachBlockHeader.Height <= detachBlockHeader.Height; detachRollBack { + detachBlockHeaders = append(detachBlockHeaders, detachBlockHeader) + } + + if attachRollback { + attachBlockHeader, err = c.store.GetBlockHeader(&attachBlockHeader.PreviousBlockHash) + if err != nil { + return nil, nil, err + } + } - detachNode := c.bestNode - for detachNode != attachNode { - detachNodes = append(detachNodes, detachNode) - detachNode = detachNode.Parent + if detachRollBack { + detachBlockHeader, err = c.store.GetBlockHeader(&detachBlockHeader.PreviousBlockHash) + if err != nil { + return nil, nil, err + } + } } - return attachNodes, detachNodes + return attachBlockHeaders, detachBlockHeaders, nil } func (c *Chain) connectBlock(block *types.Block) (err error) { @@ -94,30 +101,46 @@ func (c *Chain) connectBlock(block *types.Block) (err error) { if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil { return err } - node := c.index.GetNode(&bcBlock.ID) - if err := c.setState(node, utxoView); err != nil { + + voteResult, err := c.getBestVoteResult() + if err != nil { + return err + } + if err := voteResult.ApplyBlock(block); err != nil { return err } + + irrBlockHeader := c.bestIrrBlockHeader + if c.isIrreversible(&block.BlockHeader) && block.Height > irrBlockHeader.Height { + irrBlockHeader = &block.BlockHeader + } + + if err := c.setState(&block.BlockHeader, irrBlockHeader, []*types.BlockHeader{&block.BlockHeader}, utxoView, []*state.VoteResult{voteResult}); err != nil { + return err + } + for _, tx := range block.Transactions { - for key, value := range tx.Entries { - switch value.(type) { - case *bc.Claim: - c.store.SetWithdrawSpent(&key) - default: - continue - } - } c.txPool.RemoveTransaction(&tx.Tx.ID) } return nil } -func (c *Chain) reorganizeChain(node *state.BlockNode) error { - attachNodes, detachNodes := c.calcReorganizeNodes(node) +func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error { + attachBlockHeaders, detachBlockHeaders, err := c.calcReorganizeChain(blockHeader, c.bestBlockHeader) + if err != nil { + return err + } + utxoView := state.NewUtxoViewpoint() + voteResults := []*state.VoteResult{} + voteResult, err := c.getBestVoteResult() + if err != nil { + return err + } - for _, detachNode := range detachNodes { - b, err := c.store.GetBlock(&detachNode.Hash) + for _, detachBlockHeader := range detachBlockHeaders { + detachHash := detachBlockHeader.Hash() + b, err := c.store.GetBlock(&detachHash) if err != nil { return err } @@ -126,19 +149,28 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error { if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil { return err } + txStatus, err := c.GetTransactionStatus(&detachBlock.ID) if err != nil { return err } + if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil { return err } - log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain") + if err := voteResult.DetachBlock(b); err != nil { + return err + } + + blockHash := blockHeader.Hash() + log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("detach from mainchain") } - for _, attachNode := range attachNodes { - b, err := c.store.GetBlock(&attachNode.Hash) + irrBlockHeader := c.bestIrrBlockHeader + for _, attachBlockHeader := range attachBlockHeaders { + attachHash := attachBlockHeader.Hash() + b, err := c.store.GetBlock(&attachHash) if err != nil { return err } @@ -147,63 +179,71 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error { if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil { return err } + txStatus, err := c.GetTransactionStatus(&attachBlock.ID) if err != nil { return err } + if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil { return err } - log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain") - } + if err := voteResult.ApplyBlock(b); err != nil { + return err + } - return c.setState(node, utxoView) -} + if voteResult.IsFinalize() { + voteResults = append(voteResults, voteResult.Fork()) + } -func (c *Chain) consensusCheck(block *types.Block) error { - if err := dpos.GDpos.CheckBlockHeader(block.BlockHeader); err != nil { - return err - } + if c.isIrreversible(attachBlockHeader) && attachBlockHeader.Height > irrBlockHeader.Height { + irrBlockHeader = attachBlockHeader + } - if err := dpos.GDpos.IsValidBlockCheckIrreversibleBlock(block.Height, block.Hash()); err != nil { - return err + blockHash := blockHeader.Hash() + log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("attach from mainchain") } - if err := dpos.GDpos.CheckBlock(*block, true); err != nil { - return err + if len(detachBlockHeaders) > 0 && detachBlockHeaders[len(detachBlockHeaders)-1].Height <= c.bestIrrBlockHeader.Height && irrBlockHeader.Height <= c.bestIrrBlockHeader.Height { + return errors.New("rollback block below the height of irreversible block") } - return nil + voteResults = append(voteResults, voteResult.Fork()) + return c.setState(blockHeader, irrBlockHeader, attachBlockHeaders, utxoView, voteResults) } // SaveBlock will validate and save block into storage func (c *Chain) saveBlock(block *types.Block) error { - bcBlock := types.MapBlock(block) - parent := c.index.GetNode(&block.PreviousBlockHash) + if err := c.validateSign(block); err != nil { + return errors.Sub(ErrBadBlock, err) + } - if err := c.consensusCheck(block); err != nil { + parent, err := c.store.GetBlockHeader(&block.PreviousBlockHash) + if err != nil { return err } - if err := validation.ValidateBlock(bcBlock, parent, block); err != nil { + bcBlock := types.MapBlock(block) + if err := validation.ValidateBlock(bcBlock, parent); err != nil { return errors.Sub(ErrBadBlock, err) } - if err := c.ProcessDPoSConnectBlock(block); err != nil { - return err + signature, err := c.SignBlock(block) + if err != nil { + return errors.Sub(ErrBadBlock, err) } if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil { return err } - c.orphanManage.Delete(&bcBlock.ID) - node, err := state.NewBlockNode(&block.BlockHeader, parent) - if err != nil { - return err - } - c.index.AddNode(node) + if len(signature) != 0 { + xPub := config.CommonConfig.PrivateKey().XPub() + if err := c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: block.Hash(), Signature: signature, XPub: xPub[:]}); err != nil { + return err + } + } return nil } @@ -218,11 +258,11 @@ func (c *Chain) saveSubBlock(block *types.Block) *types.Block { for _, prevOrphan := range prevOrphans { orphanBlock, ok := c.orphanManage.Get(prevOrphan) if !ok { - log.WithFields(log.Fields{"hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage") + log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage") continue } if err := c.saveBlock(orphanBlock); err != nil { - log.WithFields(log.Fields{"hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block") + log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block") continue } @@ -262,11 +302,11 @@ func (c *Chain) blockProcesser() { func (c *Chain) processBlock(block *types.Block) (bool, error) { blockHash := block.Hash() if c.BlockExist(&blockHash) { - log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("block has been processed") + log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed") return c.orphanManage.BlockExist(&blockHash), nil } - if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil { + if _, err := c.store.GetBlockHeader(&block.PreviousBlockHash); err != nil { c.orphanManage.Add(block) return true, nil } @@ -276,154 +316,18 @@ func (c *Chain) processBlock(block *types.Block) (bool, error) { } bestBlock := c.saveSubBlock(block) - bestBlockHash := bestBlock.Hash() - bestNode := c.index.GetNode(&bestBlockHash) + bestBlockHeader := &bestBlock.BlockHeader - if bestNode.Parent == c.bestNode { - log.Debug("append block to the end of mainchain") + c.cond.L.Lock() + defer c.cond.L.Unlock() + if bestBlockHeader.PreviousBlockHash == c.bestBlockHeader.Hash() { + log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain") return false, c.connectBlock(bestBlock) } - if bestNode.Height > c.bestNode.Height { - log.Debug("start to reorganize chain") - return false, c.reorganizeChain(bestNode) + if bestBlockHeader.Height > c.bestBlockHeader.Height { + log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain") + return false, c.reorganizeChain(bestBlockHeader) } return false, nil } - -func (c *Chain) ProcessDPoSConnectBlock(block *types.Block) error { - mapTxFee := c.CalculateBalance(block, true) - if err := c.DoVoting(block, mapTxFee); err != nil { - return err - } - return nil -} - -func (c *Chain) DoVoting(block *types.Block, mapTxFee map[bc.Hash]uint64) error { - for _, tx := range block.Transactions { - to := tx.Outputs[0] - msg := &dpos.DposMsg{} - - if err := json.Unmarshal(tx.TxData.ReferenceData, &msg); err != nil { - continue - } - var ( - address common.Address - err error - ) - address, err = common.NewAddressWitnessPubKeyHash(to.ControlProgram[2:], &consensus.ActiveNetParams) - if err != nil { - address, err = common.NewAddressWitnessScriptHash(to.ControlProgram[2:], &consensus.ActiveNetParams) - if err != nil { - return errors.New("ControlProgram cannot be converted to address") - } - } - hash := block.Hash() - height := block.Height - switch msg.Type { - case vm.OP_DELEGATE: - continue - case vm.OP_REGISTE: - if mapTxFee[tx.Tx.ID] >= consensus.RegisrerForgerFee { - data := &dpos.RegisterForgerData{} - if err := json.Unmarshal(msg.Data, data); err != nil { - return err - } - c.engine.ProcessRegister(address.EncodeAddress(), data.Name, hash, height) - } - case vm.OP_VOTE: - if mapTxFee[tx.Tx.ID] >= consensus.VoteForgerFee { - data := &dpos.VoteForgerData{} - if err := json.Unmarshal(msg.Data, data); err != nil { - return err - } - c.engine.ProcessVote(address.EncodeAddress(), data.Forgers, hash, height) - } - case vm.OP_REVOKE: - if mapTxFee[tx.Tx.ID] >= consensus.CancelVoteForgerFee { - data := &dpos.CancelVoteForgerData{} - if err := json.Unmarshal(msg.Data, data); err != nil { - return err - } - c.engine.ProcessCancelVote(address.EncodeAddress(), data.Forgers, hash, height) - } - } - } - return nil -} - -func (c *Chain) CalculateBalance(block *types.Block, fIsAdd bool) map[bc.Hash]uint64 { - - addressBalances := []engine.AddressBalance{} - mapTxFee := make(map[bc.Hash]uint64) - var ( - address common.Address - err error - ) - - for _, tx := range block.Transactions { - fee := uint64(0) - for _, input := range tx.Inputs { - - if len(tx.TxData.Inputs) == 1 && - (tx.TxData.Inputs[0].InputType() == types.CoinbaseInputType || - tx.TxData.Inputs[0].InputType() == types.ClainPeginInputType) { - continue - } - - fee += input.Amount() - value := int64(input.Amount()) - address, err = common.NewAddressWitnessPubKeyHash(input.ControlProgram()[2:], &consensus.ActiveNetParams) - if err != nil { - address, err = common.NewAddressWitnessScriptHash(input.ControlProgram()[2:], &consensus.ActiveNetParams) - if err != nil { - continue - } - } - if fIsAdd { - value = 0 - value - } - addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value}) - } - for _, output := range tx.Outputs { - fee -= output.Amount - value := int64(output.Amount) - address, err = common.NewAddressWitnessPubKeyHash(output.ControlProgram[2:], &consensus.ActiveNetParams) - if err != nil { - address, err = common.NewAddressWitnessScriptHash(output.ControlProgram[2:], &consensus.ActiveNetParams) - if err != nil { - continue - } - } - if !fIsAdd { - value = 0 - value - } - addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value}) - } - mapTxFee[tx.Tx.ID] = fee - } - - c.engine.UpdateAddressBalance(addressBalances) - return mapTxFee -} - -func (c *Chain) RepairDPoSData(oldBlockHeight uint64, oldBlockHash bc.Hash) error { - block, err := c.GetBlockByHash(&oldBlockHash) - if err != nil { - return err - } - if block.Height != oldBlockHeight { - return errors.New("The module vote records data with a problem") - } - for i := block.Height + 1; i < c.bestNode.Height; i++ { - b, err := c.GetBlockByHeight(i) - if err != nil { - return err - } - if err := c.ProcessDPoSConnectBlock(b); err != nil { - return err - } - - } - return nil -}