github.com/aergoio/aergo@v1.3.1/consensus/impl/sbp/sbp.go (about) 1 package sbp 2 3 import ( 4 "runtime" 5 "time" 6 7 "github.com/aergoio/aergo-lib/log" 8 bc "github.com/aergoio/aergo/chain" 9 "github.com/aergoio/aergo/config" 10 "github.com/aergoio/aergo/consensus" 11 "github.com/aergoio/aergo/consensus/chain" 12 "github.com/aergoio/aergo/contract" 13 "github.com/aergoio/aergo/internal/enc" 14 "github.com/aergoio/aergo/pkg/component" 15 "github.com/aergoio/aergo/state" 16 "github.com/aergoio/aergo/types" 17 ) 18 19 const ( 20 slotQueueMax = 100 21 ) 22 23 var logger *log.Logger 24 25 func init() { 26 logger = log.NewLogger("sbp") 27 } 28 29 type txExec struct { 30 execTx bc.TxExecFn 31 } 32 33 func newTxExec(cdb consensus.ChainDB, blockNo types.BlockNo, ts int64, prevHash []byte, chainID []byte) chain.TxOp { 34 // Block hash not determined yet 35 return &txExec{ 36 execTx: bc.NewTxExecutor(nil, contract.ChainAccessor(cdb), blockNo, ts, prevHash, contract.BlockFactory, chainID), 37 } 38 } 39 40 func (te *txExec) Apply(bState *state.BlockState, tx types.Transaction) error { 41 err := te.execTx(bState, tx) 42 return err 43 } 44 45 // SimpleBlockFactory implments a simple block factory which generate block each cfg.Consensus.BlockInterval. 46 // 47 // This can be used for testing purpose. 48 type SimpleBlockFactory struct { 49 *component.ComponentHub 50 consensus.ChainDB 51 jobQueue chan interface{} 52 blockInterval time.Duration 53 maxBlockBodySize uint32 54 txOp chain.TxOp 55 quit chan interface{} 56 sdb *state.ChainStateDB 57 prevBlock *types.Block 58 } 59 60 // GetName returns the name of the consensus. 61 func GetName() string { 62 return consensus.ConsensusName[consensus.ConsensusSBP] 63 } 64 65 // GetConstructor build and returns consensus.Constructor from New function. 66 func GetConstructor(cfg *config.Config, hub *component.ComponentHub, cdb consensus.ChainDB, 67 sdb *state.ChainStateDB) consensus.Constructor { 68 return func() (consensus.Consensus, error) { 69 return New(cfg.Consensus, hub, cdb, sdb) 70 } 71 } 72 73 // New returns a SimpleBlockFactory. 74 func New(cfg *config.ConsensusConfig, hub *component.ComponentHub, cdb consensus.ChainDB, 75 sdb *state.ChainStateDB) (*SimpleBlockFactory, error) { 76 s := &SimpleBlockFactory{ 77 ComponentHub: hub, 78 ChainDB: cdb, 79 jobQueue: make(chan interface{}, slotQueueMax), 80 blockInterval: consensus.BlockInterval, 81 maxBlockBodySize: chain.MaxBlockBodySize(), 82 quit: make(chan interface{}), 83 sdb: sdb, 84 } 85 86 s.txOp = chain.NewCompTxOp( 87 chain.TxOpFn(func(bState *state.BlockState, txIn types.Transaction) error { 88 select { 89 case <-s.quit: 90 return chain.ErrQuit 91 default: 92 return nil 93 } 94 }), 95 ) 96 97 return s, nil 98 } 99 100 // Ticker returns a time.Ticker for the main consensus loop. 101 func (s *SimpleBlockFactory) Ticker() *time.Ticker { 102 return time.NewTicker(s.blockInterval) 103 } 104 105 // QueueJob send a block triggering information to jq. 106 func (s *SimpleBlockFactory) QueueJob(now time.Time, jq chan<- interface{}) { 107 if b, _ := s.GetBestBlock(); b != nil { 108 if s.prevBlock != nil && s.prevBlock.BlockNo() == b.BlockNo() { 109 logger.Debug().Msg("previous block not connected. skip to generate block") 110 return 111 } 112 s.prevBlock = b 113 jq <- b 114 } 115 } 116 117 func (s *SimpleBlockFactory) GetType() consensus.ConsensusType { 118 return consensus.ConsensusSBP 119 } 120 121 // IsTransactionValid checks the onsensus level validity of a transaction 122 func (s *SimpleBlockFactory) IsTransactionValid(tx *types.Tx) bool { 123 // SimpleBlockFactory has no tx valid check. 124 return true 125 } 126 127 // VerifyTimestamp checks the validity of the block timestamp. 128 func (s *SimpleBlockFactory) VerifyTimestamp(*types.Block) bool { 129 // SimpleBlockFactory don't need to check timestamp. 130 return true 131 } 132 133 // VerifySign checks the consensus level validity of a block. 134 func (s *SimpleBlockFactory) VerifySign(*types.Block) error { 135 // SimpleBlockFactory has no block signature. 136 return nil 137 } 138 139 // IsBlockValid checks the consensus level validity of a block. 140 func (s *SimpleBlockFactory) IsBlockValid(*types.Block, *types.Block) error { 141 // SimpleBlockFactory has no block valid check. 142 return nil 143 } 144 145 // QuitChan returns the channel from which consensus-related goroutines check 146 // when shutdown is initiated. 147 func (s *SimpleBlockFactory) QuitChan() chan interface{} { 148 return s.quit 149 } 150 151 // Update has nothging to do. 152 func (s *SimpleBlockFactory) Update(block *types.Block) { 153 } 154 155 // Save has nothging to do. 156 func (s *SimpleBlockFactory) Save(tx consensus.TxWriter) error { 157 return nil 158 } 159 160 // BlockFactory returns s itself. 161 func (s *SimpleBlockFactory) BlockFactory() consensus.BlockFactory { 162 return s 163 } 164 165 // NeedReorganization has nothing to do. 166 func (s *SimpleBlockFactory) NeedReorganization(rootNo types.BlockNo) bool { 167 return true 168 } 169 170 // Start run a simple block factory service. 171 func (s *SimpleBlockFactory) Start() { 172 defer logger.Info().Msg("shutdown initiated. stop the service") 173 174 runtime.LockOSThread() 175 176 for { 177 select { 178 case e := <-s.jobQueue: 179 if prevBlock, ok := e.(*types.Block); ok { 180 blockState := s.sdb.NewBlockState(prevBlock.GetHeader().GetBlocksRootHash()) 181 182 ts := time.Now().UnixNano() 183 184 txOp := chain.NewCompTxOp( 185 s.txOp, 186 newTxExec(s.ChainDB, prevBlock.GetHeader().GetBlockNo()+1, ts, prevBlock.GetHash(), prevBlock.GetHeader().GetChainID()), 187 ) 188 189 block, err := chain.GenerateBlock(s, prevBlock, blockState, txOp, ts, false) 190 if err == chain.ErrQuit { 191 return 192 } else if err != nil { 193 logger.Info().Err(err).Msg("failed to produce block") 194 continue 195 } 196 logger.Info().Uint64("no", block.GetHeader().GetBlockNo()).Str("hash", block.ID()). 197 Str("TrieRoot", enc.ToString(block.GetHeader().GetBlocksRootHash())). 198 Err(err).Msg("block produced") 199 200 chain.ConnectBlock(s, block, blockState, time.Second) 201 } 202 case <-s.quit: 203 return 204 } 205 } 206 } 207 208 // JobQueue returns the queue for block production triggering. 209 func (s *SimpleBlockFactory) JobQueue() chan<- interface{} { 210 return s.jobQueue 211 } 212 213 // Info retuns an empty string since SBP has no valuable consensus-related 214 // information. 215 func (s *SimpleBlockFactory) Info() string { 216 return consensus.NewInfo(GetName()).AsJSON() 217 } 218 219 func (s *SimpleBlockFactory) ConsensusInfo() *types.ConsensusInfo { 220 return &types.ConsensusInfo{Type: GetName()} 221 } 222 223 var dummyRaft consensus.DummyRaftAccessor 224 225 func (s *SimpleBlockFactory) RaftAccessor() consensus.AergoRaftAccessor { 226 return &dummyRaft 227 } 228 229 func (s *SimpleBlockFactory) NeedNotify() bool { 230 return true 231 } 232 233 func (s *SimpleBlockFactory) HasWAL() bool { 234 return false 235 } 236 237 func (s *SimpleBlockFactory) IsForkEnable() bool { 238 return true 239 } 240 241 func (s *SimpleBlockFactory) IsConnectedBlock(block *types.Block) bool { 242 _, err := s.ChainDB.GetBlock(block.BlockHash()) 243 if err == nil { 244 return true 245 } 246 247 return false 248 } 249 250 func (s *SimpleBlockFactory) ConfChange(req *types.MembershipChange) (*consensus.Member, error) { 251 return nil, consensus.ErrNotSupportedMethod 252 } 253 254 func (s *SimpleBlockFactory) ConfChangeInfo(requestID uint64) (*types.ConfChangeProgress, error) { 255 return nil, consensus.ErrNotSupportedMethod 256 } 257 258 func (s *SimpleBlockFactory) MakeConfChangeProposal(req *types.MembershipChange) (*consensus.ConfChangePropose, error) { 259 return nil, consensus.ErrNotSupportedMethod 260 } 261 262 func (s *SimpleBlockFactory) ClusterInfo(bestBlockHash []byte) *types.GetClusterInfoResponse { 263 return &types.GetClusterInfoResponse{ChainID: nil, Error: consensus.ErrNotSupportedMethod.Error(), MbrAttrs: nil, HardStateInfo: nil} 264 } 265 266 func ValidateGenesis(genesis *types.Genesis) error { 267 return nil 268 }