6 "github.com/vapor/protocol/vm"
8 log "github.com/sirupsen/logrus"
10 "github.com/vapor/common"
11 "github.com/vapor/consensus"
12 engine "github.com/vapor/consensus/consensus"
13 dpos "github.com/vapor/consensus/consensus/dpos"
14 "github.com/vapor/errors"
15 "github.com/vapor/protocol/bc"
16 "github.com/vapor/protocol/bc/types"
17 "github.com/vapor/protocol/state"
18 "github.com/vapor/protocol/validation"
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 c.store.SetWithdrawSpent(&key)
110 c.txPool.RemoveTransaction(&tx.Tx.ID)
115 func (c *Chain) reorganizeChain(node *state.BlockNode) error {
116 attachNodes, detachNodes := c.calcReorganizeNodes(node)
117 utxoView := state.NewUtxoViewpoint()
119 for _, detachNode := range detachNodes {
120 b, err := c.store.GetBlock(&detachNode.Hash)
125 detachBlock := types.MapBlock(b)
126 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
129 txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
133 if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
137 log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
140 for _, attachNode := range attachNodes {
141 b, err := c.store.GetBlock(&attachNode.Hash)
146 attachBlock := types.MapBlock(b)
147 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
150 txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
154 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
158 log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
161 return c.setState(node, utxoView)
164 func (c *Chain) consensusCheck(block *types.Block) error {
165 if err := dpos.GDpos.CheckBlockHeader(block.BlockHeader); err != nil {
169 if err := dpos.GDpos.IsValidBlockCheckIrreversibleBlock(block.Height, block.Hash()); err != nil {
173 if err := dpos.GDpos.CheckBlock(*block, true); err != nil {
179 // SaveBlock will validate and save block into storage
180 func (c *Chain) saveBlock(block *types.Block) error {
181 bcBlock := types.MapBlock(block)
182 parent := c.index.GetNode(&block.PreviousBlockHash)
184 if err := c.consensusCheck(block); err != nil {
188 if err := validation.ValidateBlock(bcBlock, parent, block); err != nil {
189 return errors.Sub(ErrBadBlock, err)
192 if err := c.ProcessDPoSConnectBlock(block); err != nil {
196 if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
200 c.orphanManage.Delete(&bcBlock.ID)
201 node, err := state.NewBlockNode(&block.BlockHeader, parent)
206 c.index.AddNode(node)
210 func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
211 blockHash := block.Hash()
212 prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
218 for _, prevOrphan := range prevOrphans {
219 orphanBlock, ok := c.orphanManage.Get(prevOrphan)
221 log.WithFields(log.Fields{"hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
224 if err := c.saveBlock(orphanBlock); err != nil {
225 log.WithFields(log.Fields{"hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
229 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
230 bestBlock = subBestBlock
236 type processBlockResponse struct {
241 type processBlockMsg struct {
243 reply chan processBlockResponse
246 // ProcessBlock is the entry for chain update
247 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
248 reply := make(chan processBlockResponse, 1)
249 c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
251 return response.isOrphan, response.err
254 func (c *Chain) blockProcesser() {
255 for msg := range c.processBlockCh {
256 isOrphan, err := c.processBlock(msg.block)
257 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
261 // ProcessBlock is the entry for handle block insert
262 func (c *Chain) processBlock(block *types.Block) (bool, error) {
263 blockHash := block.Hash()
264 if c.BlockExist(&blockHash) {
265 log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
266 return c.orphanManage.BlockExist(&blockHash), nil
269 if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {
270 c.orphanManage.Add(block)
274 if err := c.saveBlock(block); err != nil {
278 bestBlock := c.saveSubBlock(block)
279 bestBlockHash := bestBlock.Hash()
280 bestNode := c.index.GetNode(&bestBlockHash)
282 if bestNode.Parent == c.bestNode {
283 log.Debug("append block to the end of mainchain")
284 return false, c.connectBlock(bestBlock)
287 if bestNode.Height > c.bestNode.Height {
288 log.Debug("start to reorganize chain")
289 return false, c.reorganizeChain(bestNode)
294 func (c *Chain) ProcessDPoSConnectBlock(block *types.Block) error {
295 mapTxFee := c.CalculateBalance(block, true)
296 if err := c.DoVoting(block, mapTxFee); err != nil {
302 func (c *Chain) DoVoting(block *types.Block, mapTxFee map[bc.Hash]uint64) error {
303 for _, tx := range block.Transactions {
305 msg := &dpos.DposMsg{}
307 if err := json.Unmarshal(tx.TxData.ReferenceData, &msg); err != nil {
311 address common.Address
314 address, err = common.NewAddressWitnessPubKeyHash(to.ControlProgram[2:], &consensus.ActiveNetParams)
316 address, err = common.NewAddressWitnessScriptHash(to.ControlProgram[2:], &consensus.ActiveNetParams)
318 return errors.New("ControlProgram cannot be converted to address")
322 height := block.Height
327 if mapTxFee[tx.Tx.ID] >= consensus.RegisrerForgerFee {
328 data := &dpos.RegisterForgerData{}
329 if err := json.Unmarshal(msg.Data, data); err != nil {
332 c.Engine.ProcessRegister(address.EncodeAddress(), data.Name, hash, height)
335 if mapTxFee[tx.Tx.ID] >= consensus.VoteForgerFee {
336 data := &dpos.VoteForgerData{}
337 if err := json.Unmarshal(msg.Data, data); err != nil {
340 c.Engine.ProcessVote(address.EncodeAddress(), data.Forgers, hash, height)
343 if mapTxFee[tx.Tx.ID] >= consensus.CancelVoteForgerFee {
344 data := &dpos.CancelVoteForgerData{}
345 if err := json.Unmarshal(msg.Data, data); err != nil {
348 c.Engine.ProcessCancelVote(address.EncodeAddress(), data.Forgers, hash, height)
355 func (c *Chain) CalculateBalance(block *types.Block, fIsAdd bool) map[bc.Hash]uint64 {
357 addressBalances := []engine.AddressBalance{}
358 mapTxFee := make(map[bc.Hash]uint64)
360 address common.Address
364 for _, tx := range block.Transactions {
366 for _, input := range tx.Inputs {
368 if len(tx.TxData.Inputs) == 1 &&
369 (tx.TxData.Inputs[0].InputType() == types.CoinbaseInputType ||
370 tx.TxData.Inputs[0].InputType() == types.ClainPeginInputType) {
374 fee += input.Amount()
375 value := int64(input.Amount())
376 address, err = common.NewAddressWitnessPubKeyHash(input.ControlProgram()[2:], &consensus.ActiveNetParams)
378 address, err = common.NewAddressWitnessScriptHash(input.ControlProgram()[2:], &consensus.ActiveNetParams)
386 addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value})
388 for _, output := range tx.Outputs {
390 value := int64(output.Amount)
391 address, err = common.NewAddressWitnessPubKeyHash(output.ControlProgram[2:], &consensus.ActiveNetParams)
393 address, err = common.NewAddressWitnessScriptHash(output.ControlProgram[2:], &consensus.ActiveNetParams)
401 addressBalances = append(addressBalances, engine.AddressBalance{address.EncodeAddress(), value})
403 mapTxFee[tx.Tx.ID] = fee
406 c.Engine.UpdateAddressBalance(addressBalances)
410 func (c *Chain) RepairDPoSData(oldBlockHeight uint64, oldBlockHash bc.Hash) error {
411 block, err := c.GetBlockByHash(&oldBlockHash)
415 if block.Height != oldBlockHeight {
416 return errors.New("The module vote records data with a problem")
418 for i := block.Height + 1; i < c.bestNode.Height; i++ {
419 b, err := c.GetBlockByHeight(i)
423 if err := c.ProcessDPoSConnectBlock(b); err != nil {