6 log "github.com/sirupsen/logrus"
8 "github.com/vapor/common"
9 "github.com/vapor/consensus"
10 engine "github.com/vapor/consensus/consensus"
11 dpos "github.com/vapor/consensus/consensus/dpos"
12 "github.com/vapor/errors"
13 "github.com/vapor/protocol/bc"
14 "github.com/vapor/protocol/bc/types"
15 "github.com/vapor/protocol/state"
16 "github.com/vapor/protocol/validation"
17 "github.com/vapor/protocol/vm"
18 "github.com/vapor/protocol/vm/vmutil"
22 // ErrBadBlock is returned when a block is invalid.
23 ErrBadBlock = errors.New("invalid block")
24 // ErrBadStateRoot is returned when the computed assets merkle root
25 // disagrees with the one declared in a block header.
26 ErrBadStateRoot = errors.New("invalid state merkle root")
29 // BlockExist check is a block in chain or orphan
30 func (c *Chain) BlockExist(hash *bc.Hash) bool {
31 return c.index.BlockExist(hash) || c.orphanManage.BlockExist(hash)
34 // GetBlockByHash return a block by given hash
35 func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) {
36 return c.store.GetBlock(hash)
39 // GetBlockByHeight return a block header by given height
40 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
41 node := c.index.NodeByHeight(height)
43 return nil, errors.New("can't find block in given height")
45 return c.store.GetBlock(&node.Hash)
48 // GetHeaderByHash return a block header by given hash
49 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
50 node := c.index.GetNode(hash)
52 return nil, errors.New("can't find block header in given hash")
54 return node.BlockHeader(), nil
57 // GetHeaderByHeight return a block header by given height
58 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
59 node := c.index.NodeByHeight(height)
61 return nil, errors.New("can't find block header in given height")
63 return node.BlockHeader(), nil
66 func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
67 var attachNodes []*state.BlockNode
68 var detachNodes []*state.BlockNode
71 for c.index.NodeByHeight(attachNode.Height) != attachNode {
72 attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...)
73 attachNode = attachNode.Parent
76 detachNode := c.bestNode
77 for detachNode != attachNode {
78 detachNodes = append(detachNodes, detachNode)
79 detachNode = detachNode.Parent
81 return attachNodes, detachNodes
84 func (c *Chain) connectBlock(block *types.Block) (err error) {
85 bcBlock := types.MapBlock(block)
86 if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil {
90 utxoView := state.NewUtxoViewpoint()
91 if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
94 if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil {
97 node := c.index.GetNode(&bcBlock.ID)
98 if err := c.setState(node, utxoView); err != nil {
101 for _, tx := range block.Transactions {
102 for key, value := range tx.Entries {
103 switch value.(type) {
105 if err := c.store.SetWithdrawSpent(&key); err != nil {
112 c.txPool.RemoveTransaction(&tx.Tx.ID)
117 func (c *Chain) reorganizeChain(node *state.BlockNode) error {
118 attachNodes, detachNodes := c.calcReorganizeNodes(node)
119 utxoView := state.NewUtxoViewpoint()
121 for _, detachNode := range detachNodes {
122 b, err := c.store.GetBlock(&detachNode.Hash)
127 detachBlock := types.MapBlock(b)
128 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
131 txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
135 if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
139 log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
142 for _, attachNode := range attachNodes {
143 b, err := c.store.GetBlock(&attachNode.Hash)
148 attachBlock := types.MapBlock(b)
149 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
152 txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
156 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
160 log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
163 return c.setState(node, utxoView)
166 func (c *Chain) consensusCheck(block *types.Block) error {
167 if err := dpos.GDpos.CheckBlockHeader(block.BlockHeader); err != nil {
171 if err := dpos.GDpos.IsValidBlockCheckIrreversibleBlock(block.Height, block.Hash()); err != nil {
175 if err := dpos.GDpos.CheckBlock(*block, true); err != nil {
181 // SaveBlock will validate and save block into storage
182 func (c *Chain) saveBlock(block *types.Block) error {
183 bcBlock := types.MapBlock(block)
184 parent := c.index.GetNode(&block.PreviousBlockHash)
186 if err := c.consensusCheck(block); err != nil {
190 if err := validation.ValidateBlock(bcBlock, parent, block); err != nil {
191 return errors.Sub(ErrBadBlock, err)
194 if err := c.ProcessDPoSConnectBlock(block); err != nil {
198 if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
202 c.orphanManage.Delete(&bcBlock.ID)
203 node, err := state.NewBlockNode(&block.BlockHeader, parent)
208 c.index.AddNode(node)
212 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
213 blockHash := block.Hash()
214 prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
220 for _, prevOrphan := range prevOrphans {
221 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
223 log.WithFields(log.Fields{"hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
226 if err := c.saveBlock(orphanBlock); err != nil {
227 log.WithFields(log.Fields{"hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
231 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
232 bestBlock = subBestBlock
238 type processBlockResponse struct {
243 type processBlockMsg struct {
245 reply chan processBlockResponse
248 // ProcessBlock is the entry for chain update
249 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
250 reply := make(chan processBlockResponse, 1)
251 c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
253 return response.isOrphan, response.err
256 func (c *Chain) blockProcesser() {
257 for msg := range c.processBlockCh {
258 isOrphan, err := c.processBlock(msg.block)
259 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
263 // ProcessBlock is the entry for handle block insert
264 func (c *Chain) processBlock(block *types.Block) (bool, error) {
265 blockHash := block.Hash()
266 if c.BlockExist(&blockHash) {
267 log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
268 return c.orphanManage.BlockExist(&blockHash), nil
271 if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {
272 c.orphanManage.Add(block)
276 if err := c.saveBlock(block); err != nil {
280 bestBlock := c.saveSubBlock(block)
281 bestBlockHash := bestBlock.Hash()
282 bestNode := c.index.GetNode(&bestBlockHash)
284 if bestNode.Parent == c.bestNode {
285 log.Debug("append block to the end of mainchain")
286 return false, c.connectBlock(bestBlock)
289 if bestNode.Height > c.bestNode.Height {
290 log.Debug("start to reorganize chain")
291 return false, c.reorganizeChain(bestNode)
296 func (c *Chain) ProcessDPoSConnectBlock(block *types.Block) error {
297 mapTxFee := c.CalculateBalance(block, true)
298 if err := c.DoVoting(block, mapTxFee); err != nil {
304 func (c *Chain) DoVoting(block *types.Block, mapTxFee map[bc.Hash]uint64) error {
305 for _, tx := range block.Transactions {
307 msg := &dpos.DposMsg{}
309 if err := json.Unmarshal(tx.TxData.ReferenceData, &msg); err != nil {
313 address common.Address
316 address, err = common.NewAddressWitnessPubKeyHash(to.ControlProgram[2:], &consensus.ActiveNetParams)
318 address, err = common.NewAddressWitnessScriptHash(to.ControlProgram[2:], &consensus.ActiveNetParams)
320 return errors.New("ControlProgram cannot be converted to address")
324 height := block.Height
329 if mapTxFee[tx.Tx.ID] >= consensus.RegisrerForgerFee {
330 data := &dpos.RegisterForgerData{}
331 if err := json.Unmarshal(msg.Data, data); err != nil {
334 c.Engine.ProcessRegister(address.EncodeAddress(), data.Name, hash, height)
337 if mapTxFee[tx.Tx.ID] >= consensus.VoteForgerFee {
338 data := &dpos.VoteForgerData{}
339 if err := json.Unmarshal(msg.Data, data); err != nil {
342 c.Engine.ProcessVote(address.EncodeAddress(), data.Forgers, hash, height)
345 if mapTxFee[tx.Tx.ID] >= consensus.CancelVoteForgerFee {
346 data := &dpos.CancelVoteForgerData{}
347 if err := json.Unmarshal(msg.Data, data); err != nil {
350 c.Engine.ProcessCancelVote(address.EncodeAddress(), data.Forgers, hash, height)
357 func (c *Chain) CalculateBalance(block *types.Block, fIsAdd bool) map[bc.Hash]uint64 {
359 addressBalances := []engine.AddressBalance{}
360 mapTxFee := make(map[bc.Hash]uint64)
362 address common.Address
366 for _, tx := range block.Transactions {
368 for _, input := range tx.Inputs {
369 if input.AssetID() != *consensus.BTMAssetID {
373 if len(tx.TxData.Inputs) == 1 &&
374 (tx.TxData.Inputs[0].InputType() == types.CoinbaseInputType ||
375 tx.TxData.Inputs[0].InputType() == types.ClainPeginInputType) {
379 fee += input.Amount()
380 value := int64(input.Amount())
381 address, err = common.NewAddressWitnessPubKeyHash(input.ControlProgram()[2:], &consensus.ActiveNetParams)
383 address, err = common.NewAddressWitnessScriptHash(input.ControlProgram()[2:], &consensus.ActiveNetParams)
391 addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value})
393 for _, output := range tx.Outputs {
395 if vmutil.IsUnspendable(output.ControlProgram) {
398 if *output.AssetId != *consensus.BTMAssetID {
401 value := int64(output.Amount)
402 address, err = common.NewAddressWitnessPubKeyHash(output.ControlProgram[2:], &consensus.ActiveNetParams)
404 address, err = common.NewAddressWitnessScriptHash(output.ControlProgram[2:], &consensus.ActiveNetParams)
412 addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value})
414 mapTxFee[tx.Tx.ID] = fee
417 c.Engine.UpdateAddressBalance(addressBalances)
421 func (c *Chain) RepairDPoSData(oldBlockHeight uint64, oldBlockHash bc.Hash) error {
422 block, err := c.GetBlockByHash(&oldBlockHash)
426 if block.Height != oldBlockHeight {
427 return errors.New("The module vote records data with a problem")
429 for i := block.Height + 1; i <= c.bestNode.Height; i++ {
430 b, err := c.GetBlockByHeight(i)
434 if err := c.ProcessDPoSConnectBlock(b); err != nil {