github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/protocol/casper/casper.go (about) 1 package casper 2 3 import ( 4 "sync" 5 6 log "github.com/sirupsen/logrus" 7 8 "github.com/bytom/bytom/common" 9 "github.com/bytom/bytom/consensus" 10 "github.com/bytom/bytom/errors" 11 "github.com/bytom/bytom/protocol/bc" 12 "github.com/bytom/bytom/protocol/state" 13 ) 14 15 var ( 16 logModule = "casper" 17 18 errPubKeyIsNotValidator = errors.New("pub key is not in validators of target checkpoint") 19 errVoteToGrowingCheckpoint = errors.New("validator publish vote to growing checkpoint") 20 errVoteToSameCheckpoint = errors.New("source height and target height in verification is equals") 21 errSameHeightInVerification = errors.New("validator publish two distinct votes for the same target height") 22 errSpanHeightInVerification = errors.New("validator publish vote within the span of its other votes") 23 ) 24 25 // RollbackMsg sent the rollback msg to chain core 26 type RollbackMsg struct { 27 BestHash bc.Hash 28 Reply chan error 29 } 30 31 type msgQueue interface { 32 Post(interface{}) error 33 } 34 35 // Casper is BFT based proof of stack consensus algorithm, it provides safety and liveness in theory, 36 // it's design mainly refers to https://github.com/ethereum/research/blob/master/papers/casper-basics/casper_basics.pdf 37 type Casper struct { 38 mu sync.RWMutex 39 store state.Store 40 msgQueue msgQueue 41 tree *treeNode 42 43 // block hash -> previous checkpoint hash 44 prevCheckpointCache *common.Cache 45 // block hash + pubKey -> verification 46 verificationCache *common.Cache 47 48 rollbackCh chan *RollbackMsg 49 newEpochCh chan bc.Hash 50 } 51 52 // NewCasper create a new instance of Casper 53 // argument checkpoints load the checkpoints from leveldb 54 // the first element of checkpoints must genesis checkpoint or the last finalized checkpoint in order to reduce memory space 55 // the others must be successors of first one 56 func NewCasper(store state.Store, queue msgQueue, checkpoints []*state.Checkpoint) *Casper { 57 if checkpoints[0].Height != 0 && checkpoints[0].Status != state.Finalized { 58 log.WithFields(log.Fields{"module": logModule}).Panic("first element of checkpoints must genesis or in finalized status") 59 } 60 61 casper := &Casper{ 62 store: store, 63 msgQueue: queue, 64 tree: makeTree(checkpoints[0], checkpoints[1:]), 65 prevCheckpointCache: common.NewCache(1024), 66 verificationCache: common.NewCache(1024), 67 rollbackCh: make(chan *RollbackMsg, 64), 68 newEpochCh: make(chan bc.Hash, 64), 69 } 70 go casper.authVerificationLoop() 71 return casper 72 } 73 74 // LastFinalized return the block height and block hash which is finalized at last 75 func (c *Casper) LastFinalized() (uint64, bc.Hash) { 76 c.mu.RLock() 77 defer c.mu.RUnlock() 78 79 root := c.tree.Checkpoint 80 return root.Height, root.Hash 81 } 82 83 // LastJustified return the block height and block hash which is justified at last 84 func (c *Casper) LastJustified() (uint64, bc.Hash) { 85 c.mu.RLock() 86 defer c.mu.RUnlock() 87 node := c.tree.lastJustified() 88 return node.Height, node.Hash 89 } 90 91 func (c *Casper) RollbackCh() <-chan *RollbackMsg { 92 return c.rollbackCh 93 } 94 95 // Validators return the validators by specified block hash 96 // e.g. if the block num of epoch is 100, and the block height corresponding to the block hash is 130, then will return the voting results of height in 0~100 97 func (c *Casper) validators(blockHash *bc.Hash) (map[string]*state.Validator, error) { 98 checkpoint, err := c.ParentCheckpoint(blockHash) 99 if err != nil { 100 return nil, err 101 } 102 103 return checkpoint.EffectiveValidators(), nil 104 } 105 106 func (c *Casper) ParentCheckpoint(blockHash *bc.Hash) (*state.Checkpoint, error) { 107 hash, err := c.parentCheckpointHash(blockHash) 108 if err != nil { 109 return nil, err 110 } 111 112 return c.store.GetCheckpoint(hash) 113 } 114 115 func (c *Casper) ParentCheckpointByPrevHash(prevBlockHash *bc.Hash) (*state.Checkpoint, error) { 116 hash, err := c.parentCheckpointHashByPrevHash(prevBlockHash) 117 if err != nil { 118 return nil, err 119 } 120 121 return c.store.GetCheckpoint(hash) 122 } 123 124 func (c *Casper) BestChain() bc.Hash { 125 c.mu.RLock() 126 defer c.mu.RUnlock() 127 return c.bestChain() 128 } 129 130 func (c *Casper) bestChain() bc.Hash { 131 // root is init justified 132 bestNode, _ := c.tree.bestNode(c.tree.Height) 133 return bestNode.Hash 134 } 135 136 func (c *Casper) parentCheckpointHash(blockHash *bc.Hash) (*bc.Hash, error) { 137 if data, ok := c.prevCheckpointCache.Get(*blockHash); ok { 138 return data.(*bc.Hash), nil 139 } 140 141 block, err := c.store.GetBlockHeader(blockHash) 142 if err != nil { 143 return nil, err 144 } 145 146 result, err := c.parentCheckpointHashByPrevHash(&block.PreviousBlockHash) 147 if err != nil { 148 return nil, err 149 } 150 151 c.prevCheckpointCache.Add(*blockHash, result) 152 return result, nil 153 } 154 155 func (c *Casper) parentCheckpointHashByPrevHash(prevBlockHash *bc.Hash) (*bc.Hash, error) { 156 for iterHash := prevBlockHash; ; { 157 block, err := c.store.GetBlockHeader(iterHash) 158 if err != nil { 159 return nil, err 160 } 161 162 if mod := block.Height % consensus.ActiveNetParams.BlocksOfEpoch; mod == 0 { 163 return iterHash, nil 164 } else if mod == 1 { 165 return &block.PreviousBlockHash, nil 166 } 167 168 if data, ok := c.prevCheckpointCache.Get(*iterHash); ok { 169 c.prevCheckpointCache.Add(*prevBlockHash, data) 170 return data.(*bc.Hash), nil 171 } 172 173 iterHash = &block.PreviousBlockHash 174 } 175 }