github.com/aergoio/aergo@v1.3.1/consensus/chain/block.go (about) 1 package chain 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/aergoio/aergo/internal/enc" 7 "github.com/aergoio/aergo/p2p/p2putil" 8 "time" 9 10 "github.com/aergoio/aergo/chain" 11 "github.com/aergoio/aergo/message" 12 "github.com/aergoio/aergo/pkg/component" 13 "github.com/aergoio/aergo/state" 14 "github.com/aergoio/aergo/types" 15 ) 16 17 var ( 18 // ErrQuit indicates that shutdown is initiated. 19 ErrQuit = errors.New("shutdown initiated") 20 errBlockSizeLimit = errors.New("the transactions included exceeded the block size limit") 21 ErrBlockEmpty = errors.New("no transactions in block") 22 ErrSyncChain = errors.New("failed to sync request") 23 ) 24 25 // ErrTimeout can be used to indicatefor any kind of timeout. 26 type ErrTimeout struct { 27 Kind string 28 Timeout int64 29 } 30 31 func (e ErrTimeout) Error() string { 32 if e.Timeout != 0 { 33 return fmt.Sprintf("%s timeout (%v)", e.Kind, e.Timeout) 34 } 35 return e.Kind + " timeout" 36 } 37 38 // ErrBlockConnect indicates a error indicating a failed block connected 39 // request. 40 type ErrBlockConnect struct { 41 id string 42 prevID string 43 ec error 44 } 45 46 func (e ErrBlockConnect) Error() string { 47 return fmt.Sprintf("failed to connect block (%s): id=%s, prev id=%s", e.ec.Error(), e.id, e.prevID) 48 } 49 50 // GetBestBlock returns the current best block from chainservice 51 func GetBestBlock(hs component.ICompSyncRequester) *types.Block { 52 result, err := hs.RequestFuture(message.ChainSvc, &message.GetBestBlock{}, time.Second, 53 "consensus/util/info.GetBestBlock").Result() 54 if err != nil { 55 logger.Error().Err(err).Msg("failed to get best block info") 56 return nil 57 } 58 return result.(message.GetBestBlockRsp).Block 59 } 60 61 // MaxBlockBodySize returns the maximum block body size. 62 func MaxBlockBodySize() uint32 { 63 return chain.MaxBlockBodySize() 64 } 65 66 // GenerateBlock generate & return a new block 67 func GenerateBlock(hs component.ICompSyncRequester, prevBlock *types.Block, bState *state.BlockState, txOp TxOp, ts int64, skipEmpty bool) (*types.Block, error) { 68 transactions, err := GatherTXs(hs, bState, txOp, MaxBlockBodySize()) 69 if err != nil { 70 return nil, err 71 } 72 73 txs := make([]*types.Tx, 0) 74 for _, x := range transactions { 75 txs = append(txs, x.GetTx()) 76 } 77 78 if len(txs) == 0 && skipEmpty { 79 logger.Debug().Msg("BF: empty block is skipped") 80 return nil, ErrBlockEmpty 81 } 82 83 block := types.NewBlock(prevBlock, bState.GetRoot(), bState.Receipts(), txs, chain.CoinbaseAccount, ts) 84 if len(txs) != 0 && logger.IsDebugEnabled() { 85 logger.Debug(). 86 Str("txroothash", types.EncodeB64(block.GetHeader().GetTxsRootHash())). 87 Int("hashed", len(txs)). 88 Msg("BF: tx root hash") 89 } 90 91 return block, nil 92 } 93 94 // ConnectBlock send an AddBlock request to the chain service. 95 func ConnectBlock(hs component.ICompSyncRequester, block *types.Block, blockState *state.BlockState, timeout time.Duration) error { 96 // blockState does not include a valid BlockHash since it is constructed 97 // from an incomplete block. So set it here. 98 _, err := hs.RequestFuture(message.ChainSvc, &message.AddBlock{PeerID: "", Block: block, Bstate: blockState}, 99 timeout, "consensus/chain/info.ConnectBlock").Result() 100 if err != nil { 101 logger.Error().Err(err).Uint64("no", block.Header.BlockNo). 102 Str("hash", block.ID()). 103 Str("prev", block.PrevID()). 104 Msg("failed to connect block") 105 106 return &ErrBlockConnect{id: block.ID(), prevID: block.PrevID(), ec: err} 107 } 108 109 return nil 110 } 111 112 func SyncChain(hs *component.ComponentHub, targetHash []byte, targetNo types.BlockNo, peerID types.PeerID) error { 113 logger.Info().Str("peer", p2putil.ShortForm(peerID)).Uint64("no", targetNo). 114 Str("hash", enc.ToString(targetHash)).Msg("request to sync for consensus") 115 116 notiC := make(chan error) 117 hs.Tell(message.SyncerSvc, &message.SyncStart{PeerID: peerID, TargetNo: targetNo, NotifyC: notiC}) 118 119 // wait end of sync every 1sec 120 select { 121 case err := <-notiC: 122 if err != nil { 123 logger.Error().Err(err).Uint64("no", targetNo). 124 Str("hash", enc.ToString(targetHash)). 125 Msg("failed to sync") 126 127 return err 128 } 129 } 130 131 logger.Info().Str("peer", p2putil.ShortForm(peerID)).Msg("succeeded to sync for consensus") 132 // TODO check best block is equal to target Hash/no 133 return nil 134 }