+func (c *Chain) detachBlock(detachBlockHeader *types.BlockHeader, consensusResult *state.ConsensusResult, utxoView *state.UtxoViewpoint) (*types.Block, error) {
+ detachHash := detachBlockHeader.Hash()
+ block, err := c.store.GetBlock(&detachHash)
+ if err != nil {
+ return block, err
+ }
+
+ detachBlock := types.MapBlock(block)
+ if err := consensusResult.DetachBlock(block); err != nil {
+ return block, err
+ }
+
+ if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
+ return block, err
+ }
+
+ txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
+ if err != nil {
+ return block, err
+ }
+
+ if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
+ return block, err
+ }
+
+ for _, p := range c.subProtocols {
+ if err := p.DetachBlock(block); err != nil {
+ return block, errors.Wrap(err, p.Name(), "sub protocol detach block")
+ }
+ }
+
+ log.WithFields(log.Fields{"module": logModule, "height": detachBlockHeader.Height, "hash": detachHash.String()}).Debug("detach from mainchain")
+ return block, nil
+}
+
+func (c *Chain) syncSubProtocols() error {
+ for _, p := range c.subProtocols {
+ if err := c.syncProtocolStatus(p); err != nil {
+ return errors.Wrap(err, p.Name(), "sync sub protocol status")
+ }
+ }
+ return nil
+}
+
+// Rollback rollback the chain from one blockHeight to targetBlockHeight
+// WARNING: we recommend to use this only in commond line
+func (c *Chain) Rollback(targetHeight uint64) error {
+ c.cond.L.Lock()
+ defer c.cond.L.Unlock()
+