github.com/klaytn/klaytn@v1.12.1/node/sc/sub_bridge_handler.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package sc 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "math/big" 24 25 "github.com/klaytn/klaytn/blockchain" 26 "github.com/klaytn/klaytn/blockchain/types" 27 "github.com/klaytn/klaytn/common" 28 "github.com/klaytn/klaytn/networks/p2p" 29 "github.com/klaytn/klaytn/params" 30 "github.com/klaytn/klaytn/rlp" 31 ) 32 33 const ( 34 SyncRequestInterval = 10 35 ) 36 37 var ( 38 ErrInvalidBlock = errors.New("block is invalid") 39 ErrUnknownBridgeContractAddr = errors.New("The given address was not found in the bridge contract list") 40 ) 41 42 // parentChainInfo handles the information of parent chain, which is needed from child chain. 43 type parentChainInfo struct { 44 Nonce uint64 45 GasPrice uint64 46 KIP71Config params.KIP71Config 47 IsMagmaEnabled bool 48 } 49 50 type InvalidParentChainTx struct { 51 TxHash common.Hash 52 ErrStr string 53 } 54 55 type SubBridgeHandler struct { 56 subbridge *SubBridge 57 // parentChainID is the first received chainID from parent chain peer. 58 // It will be reset to nil if there's no parent peer. 59 parentChainID *big.Int 60 // remoteGasPrice means gas price of parent chain, used to make a service chain transaction. 61 // Therefore, for now, it is only used by child chain side. 62 remoteGasPrice uint64 63 mainChainAccountNonce uint64 64 nonceSynced bool 65 chainTxPeriod uint64 66 67 latestTxCountAddedBlockNumber uint64 68 txCountStartingBlockNumber uint64 69 txCount uint64 // accumulated tx counts in blocks for each anchoring period. 70 71 // TODO-Klaytn-ServiceChain Need to limit the number independently? Or just managing the size of sentServiceChainTxs? 72 sentServiceChainTxsLimit uint64 73 74 skipSyncBlockCount int32 75 } 76 77 func NewSubBridgeHandler(main *SubBridge) (*SubBridgeHandler, error) { 78 return &SubBridgeHandler{ 79 subbridge: main, 80 parentChainID: new(big.Int).SetUint64(main.config.ParentChainID), 81 remoteGasPrice: uint64(0), 82 mainChainAccountNonce: uint64(0), 83 nonceSynced: false, 84 chainTxPeriod: main.config.AnchoringPeriod, 85 latestTxCountAddedBlockNumber: uint64(0), 86 sentServiceChainTxsLimit: main.config.SentChainTxsLimit, 87 }, nil 88 } 89 90 func (sbh *SubBridgeHandler) setParentChainID(chainId *big.Int) { 91 sbh.parentChainID = chainId 92 sbh.subbridge.bridgeAccounts.pAccount.SetChainID(chainId) 93 } 94 95 func (sbh *SubBridgeHandler) getParentChainID() *big.Int { 96 return sbh.parentChainID 97 } 98 99 func (sbh *SubBridgeHandler) LockParentOperator() { 100 sbh.subbridge.bridgeAccounts.pAccount.Lock() 101 } 102 103 func (sbh *SubBridgeHandler) UnLockParentOperator() { 104 sbh.subbridge.bridgeAccounts.pAccount.UnLock() 105 } 106 107 // getParentOperatorNonce returns the parent chain operator nonce of parent chain operator address. 108 func (sbh *SubBridgeHandler) getParentOperatorNonce() uint64 { 109 return sbh.subbridge.bridgeAccounts.pAccount.GetNonce() 110 } 111 112 // setParentOperatorNonce sets the parent chain operator nonce of parent chain operator address. 113 func (sbh *SubBridgeHandler) setParentOperatorNonce(newNonce uint64) { 114 sbh.subbridge.bridgeAccounts.pAccount.SetNonce(newNonce) 115 } 116 117 // addParentOperatorNonce increases nonce by number 118 func (sbh *SubBridgeHandler) addParentOperatorNonce(number uint64) { 119 sbh.subbridge.bridgeAccounts.pAccount.IncNonce() 120 } 121 122 // getParentOperatorNonceSynced returns whether the parent chain operator account nonce is synced or not. 123 func (sbh *SubBridgeHandler) getParentOperatorNonceSynced() bool { 124 return sbh.nonceSynced 125 } 126 127 // getParentOperatorBalance returns the parent chain operator balance. 128 func (sbh *SubBridgeHandler) getParentOperatorBalance() (*big.Int, error) { 129 ctx, cancel := context.WithTimeout(context.Background(), timeout) 130 defer cancel() 131 return sbh.subbridge.remoteBackend.BalanceAt(ctx, sbh.subbridge.bridgeAccounts.pAccount.address, nil) 132 } 133 134 // getParentBridgeContractBalance returns the parent bridge contract's balance. 135 func (sbh *SubBridgeHandler) getParentBridgeContractBalance(addr common.Address) (*big.Int, error) { 136 ctx, cancel := context.WithTimeout(context.Background(), timeout) 137 defer cancel() 138 139 if !sbh.subbridge.bridgeManager.IsInParentAddrs(addr) { 140 logger.Error(ErrUnknownBridgeContractAddr.Error(), "addr", addr) 141 return common.Big0, ErrUnknownBridgeContractAddr 142 } 143 return sbh.subbridge.remoteBackend.BalanceAt(ctx, addr, nil) 144 } 145 146 // setParentOperatorNonceSynced sets whether the parent chain operator account nonce is synced or not. 147 func (sbh *SubBridgeHandler) setParentOperatorNonceSynced(synced bool) { 148 sbh.nonceSynced = synced 149 } 150 151 func (sbh *SubBridgeHandler) getChildOperatorNonce() uint64 { 152 return sbh.subbridge.txPool.GetPendingNonce(sbh.subbridge.bridgeAccounts.cAccount.address) 153 } 154 155 // getChildOperatorBalance returns the child chain operator balance. 156 func (sbh *SubBridgeHandler) getChildOperatorBalance() (*big.Int, error) { 157 ctx, cancel := context.WithTimeout(context.Background(), timeout) 158 defer cancel() 159 return sbh.subbridge.localBackend.BalanceAt(ctx, sbh.subbridge.bridgeAccounts.cAccount.address, nil) 160 } 161 162 // getChildBridgeContractBalance returns the child bridge contract's balance. 163 func (sbh *SubBridgeHandler) getChildBridgeContractBalance(addr common.Address) (*big.Int, error) { 164 ctx, cancel := context.WithTimeout(context.Background(), timeout) 165 defer cancel() 166 167 if !sbh.subbridge.bridgeManager.IsInChildAddrs(addr) { 168 logger.Error(ErrUnknownBridgeContractAddr.Error(), "addr", addr) 169 return common.Big0, ErrUnknownBridgeContractAddr 170 } 171 return sbh.subbridge.localBackend.BalanceAt(ctx, addr, nil) 172 } 173 174 func (sbh *SubBridgeHandler) getRemoteGasPrice() uint64 { 175 return sbh.remoteGasPrice 176 } 177 178 // setRemoteGasPrice sets parent chain's gasprice 179 func (sbh *SubBridgeHandler) setRemoteGasPrice(gasPrice uint64) { 180 sbh.subbridge.bridgeAccounts.pAccount.SetGasPrice(big.NewInt(int64(gasPrice))) 181 sbh.remoteGasPrice = gasPrice 182 } 183 184 // setRemoteChainValues sets parent chain's configuration values 185 func (sbh *SubBridgeHandler) setRemoteChainValues(pcInfo parentChainInfo) { 186 sbh.setRemoteGasPrice(pcInfo.GasPrice) 187 if pcInfo.IsMagmaEnabled { 188 // Set parent chain's gasprice with upperboundbasefee 189 sbh.remoteGasPrice = pcInfo.KIP71Config.UpperBoundBaseFee 190 sbh.subbridge.bridgeAccounts.SetParentKIP71Config(pcInfo.KIP71Config) 191 kip71Config := sbh.subbridge.bridgeAccounts.GetParentKIP71Config() 192 193 logger.Info("[SC][Sync] Updated parent chain values", "gasPrice", sbh.subbridge.bridgeAccounts.GetParentGasPrice(), 194 "LowerBoundBaseFee", kip71Config.LowerBoundBaseFee, 195 "UpperBoundBaseFee", kip71Config.UpperBoundBaseFee, 196 "GasTarget", kip71Config.GasTarget, 197 "MaxBlockGasUsedForBaseFee", kip71Config.MaxBlockGasUsedForBaseFee, 198 "BaseFeeDenominator", kip71Config.BaseFeeDenominator) 199 } else { 200 logger.Info("Updated parent chain's gas price", "gasPrice", sbh.subbridge.bridgeAccounts.GetParentGasPrice()) 201 } 202 } 203 204 // GetParentOperatorAddr returns a pointer of a hex address of an account used for parent chain. 205 // If given as a parameter, it will use it. If not given, it will use the address of the public key 206 // derived from chainKey. 207 func (sbh *SubBridgeHandler) GetParentOperatorAddr() *common.Address { 208 return &sbh.subbridge.bridgeAccounts.pAccount.address 209 } 210 211 // GetChildOperatorAddr returns a pointer of a hex address of an account used for child chain. 212 // If given as a parameter, it will use it. If not given, it will use the address of the public key 213 // derived from chainKey. 214 func (sbh *SubBridgeHandler) GetChildOperatorAddr() *common.Address { 215 return &sbh.subbridge.bridgeAccounts.cAccount.address 216 } 217 218 // GetAnchoringPeriod returns the period to make and send a chain transaction to parent chain. 219 func (sbh *SubBridgeHandler) GetAnchoringPeriod() uint64 { 220 return sbh.chainTxPeriod 221 } 222 223 // GetSentChainTxsLimit returns the maximum number of stored chain transactions for resending. 224 func (sbh *SubBridgeHandler) GetSentChainTxsLimit() uint64 { 225 return sbh.sentServiceChainTxsLimit 226 } 227 228 func (sbh *SubBridgeHandler) HandleMainMsg(p BridgePeer, msg p2p.Msg) error { 229 // Handle the message depending on its contents 230 switch msg.Code { 231 case ServiceChainResponse: 232 logger.Trace("received rpc ServiceChainResponse") 233 data := make([]byte, msg.Size) 234 err := msg.Decode(&data) 235 if err != nil { 236 logger.Error("failed to decode the p2p ServiceChainResponse message", "err", err) 237 return nil 238 } 239 logger.Trace("send rpc response to the rpc client") 240 _, err = sbh.subbridge.rpcConn.Write(data) 241 if err != nil { 242 return err 243 } 244 return nil 245 case StatusMsg: 246 return nil 247 case ServiceChainParentChainInfoResponseMsg: 248 logger.Debug("received ServiceChainParentChainInfoResponseMsg") 249 if err := sbh.handleParentChainInfoResponseMsg(p, msg); err != nil { 250 return err 251 } 252 253 case ServiceChainReceiptResponseMsg: 254 logger.Debug("received ServiceChainReceiptResponseMsg") 255 if err := sbh.handleParentChainReceiptResponseMsg(p, msg); err != nil { 256 return err 257 } 258 case ServiceChainInvalidTxResponseMsg: 259 logger.Debug("received ServiceChainInvalidTxResponseMsg") 260 if err := sbh.handleParentChainInvalidTxResponseMsg(msg); err != nil { 261 return err 262 } 263 default: 264 return errResp(ErrInvalidMsgCode, "%v", msg.Code) 265 } 266 return nil 267 } 268 269 // handleParentChainInfoResponseMsg handles parent chain info response message from parent chain. 270 // It will update the ParentOperatorNonce and remoteGasPrice of ServiceChainProtocolManager. 271 func (sbh *SubBridgeHandler) handleParentChainInfoResponseMsg(p BridgePeer, msg p2p.Msg) error { 272 var pcInfo parentChainInfo 273 if err := msg.Decode(&pcInfo); err != nil { 274 logger.Error("failed to decode", "err", err) 275 return errResp(ErrDecode, "msg %v: %v", msg, err) 276 } 277 sbh.LockParentOperator() 278 defer sbh.UnLockParentOperator() 279 280 poolNonce := sbh.subbridge.bridgeTxPool.GetMaxTxNonce(sbh.GetParentOperatorAddr()) 281 if poolNonce > 0 { 282 poolNonce += 1 283 // just check 284 if sbh.getParentOperatorNonce() > poolNonce { 285 logger.Error("parent chain operator nonce is bigger than the chain pool nonce.", "BridgeTxPoolNonce", poolNonce, "mainChainAccountNonce", sbh.getParentOperatorNonce()) 286 } 287 if poolNonce < pcInfo.Nonce { 288 // BridgeTxPool journal miss txs which already sent to parent-chain 289 logger.Error("chain pool nonce is less than the parent chain nonce.", "chainPoolNonce", poolNonce, "receivedNonce", pcInfo.Nonce) 290 sbh.setParentOperatorNonce(pcInfo.Nonce) 291 } else { 292 // BridgeTxPool journal has txs which don't receive receipt from parent-chain 293 sbh.setParentOperatorNonce(poolNonce) 294 } 295 } else if sbh.getParentOperatorNonce() > pcInfo.Nonce { 296 logger.Error("parent chain operator nonce is bigger than the received nonce.", "mainChainAccountNonce", sbh.getParentOperatorNonce(), "receivedNonce", pcInfo.Nonce) 297 sbh.setParentOperatorNonce(pcInfo.Nonce) 298 } else { 299 // there is no tx in bridgetTxPool, so parent-chain's nonce is used 300 sbh.setParentOperatorNonce(pcInfo.Nonce) 301 } 302 sbh.setParentOperatorNonceSynced(true) 303 sbh.setRemoteChainValues(pcInfo) 304 logger.Info("ParentChainNonceResponse", "receivedNonce", pcInfo.Nonce, "gasPrice", pcInfo.GasPrice, "mainChainAccountNonce", sbh.getParentOperatorNonce()) 305 return nil 306 } 307 308 // handleParentChainReceiptResponseMsg handles receipt response message from parent chain. 309 // It will store the received receipts and remove corresponding transaction in the resending list. 310 func (sbh *SubBridgeHandler) handleParentChainReceiptResponseMsg(p BridgePeer, msg p2p.Msg) error { 311 // TODO-Klaytn-ServiceChain Need to add an option, not to write receipts. 312 // Decode the retrieval message 313 var receipts []*types.ReceiptForStorage 314 if err := msg.Decode(&receipts); err != nil && err != rlp.EOL { 315 return errResp(ErrDecode, "msg %v: %v", msg, err) 316 } 317 // Stores receipt and remove tx from sentServiceChainTxs only if the tx is successfully executed. 318 sbh.writeServiceChainTxReceipts(sbh.subbridge.blockchain, receipts) 319 return nil 320 } 321 322 // genUnsignedChainDataAnchoringTx generates an unsigned transaction, which type is TxTypeChainDataAnchoring. 323 // Nonce of account used for service chain transaction will be increased after the signing. 324 func (sbh *SubBridgeHandler) genUnsignedChainDataAnchoringTx(block *types.Block) (*types.Transaction, error) { 325 anchoringData, err := types.NewAnchoringDataType0(block, block.NumberU64()-sbh.txCountStartingBlockNumber+1, sbh.txCount) 326 if err != nil { 327 return nil, err 328 } 329 encodedCCTxData, err := rlp.EncodeToBytes(anchoringData) 330 if err != nil { 331 return nil, err 332 } 333 334 values := map[types.TxValueKeyType]interface{}{ 335 types.TxValueKeyNonce: sbh.getParentOperatorNonce(), // parent chain operator nonce will be increased after signing a transaction. 336 types.TxValueKeyFrom: *sbh.GetParentOperatorAddr(), 337 types.TxValueKeyGasLimit: uint64(100000), // TODO-Klaytn-ServiceChain should define proper gas limit 338 types.TxValueKeyGasPrice: new(big.Int).SetUint64(sbh.remoteGasPrice), 339 types.TxValueKeyAnchoredData: encodedCCTxData, 340 } 341 342 txType := types.TxTypeChainDataAnchoring 343 344 if feePayer := sbh.subbridge.bridgeAccounts.GetParentOperatorFeePayer(); feePayer != (common.Address{}) { 345 values[types.TxValueKeyFeePayer] = feePayer 346 txType = types.TxTypeFeeDelegatedChainDataAnchoring 347 } 348 349 if tx, err := types.NewTransactionWithMap(txType, values); err != nil { 350 return nil, err 351 } else { 352 return tx, nil 353 } 354 } 355 356 // LocalChainHeadEvent deals with servicechain feature to generate/broadcast service chain transactions and request receipts. 357 func (sbh *SubBridgeHandler) LocalChainHeadEvent(block *types.Block) { 358 if sbh.getParentOperatorNonceSynced() { 359 // TODO-Klaytn if other feature use below chainTx, this condition should be refactored to use it for other feature. 360 if sbh.subbridge.GetAnchoringTx() { 361 sbh.blockAnchoringManager(block) 362 } 363 sbh.broadcastServiceChainTx() 364 sbh.broadcastServiceChainReceiptRequest() 365 366 sbh.skipSyncBlockCount = 0 367 } else { 368 sbh.txCountStartingBlockNumber = 0 369 if sbh.skipSyncBlockCount%SyncRequestInterval == 0 { 370 // TODO-Klaytn too many request while sync main-net 371 sbh.SyncNonceAndGasPrice() 372 // check tx's receipts which parent-chain already executed in BridgeTxPool 373 go sbh.broadcastServiceChainReceiptRequest() 374 } 375 sbh.skipSyncBlockCount++ 376 } 377 } 378 379 // handleParentChainInvalidTxResponseMsg receives unexecuted txs which were not executed by some of the reasons (e.g., lower gas price) 380 // and removes them from bridgeTxPool to prevent resending **as it is without necessary modification** 381 func (sbh *SubBridgeHandler) handleParentChainInvalidTxResponseMsg(msg p2p.Msg) error { 382 var invalidTxs []InvalidParentChainTx 383 if err := msg.Decode(&invalidTxs); err != nil && err != rlp.EOL { 384 return errResp(ErrDecode, "msg %v: %v", msg, err) 385 } 386 txPool := sbh.subbridge.GetBridgeTxPool() 387 for _, invalidTx := range invalidTxs { 388 if tx := txPool.Get(invalidTx.TxHash); tx != nil { 389 logger.Error("A bridge tx was not executed", "err", invalidTx.ErrStr, 390 "txHash", invalidTx.TxHash.String(), 391 "txGasPrice", tx.GasPrice().Uint64()) 392 if invalidTx.ErrStr == blockchain.ErrGasPriceBelowBaseFee.Error() { 393 logger.Info("[SC][HandleTxDropped] Request gasPrice and Magma values to parent chain") 394 sbh.SyncNonceAndGasPrice() 395 396 logger.Error("Bridge tx is removed which has lower gasPrice than UpperBoundBaseFee") 397 // Remove the tx and delegate re-execution of the tx by Value Transfer Recovery feature 398 if err := sbh.subbridge.GetBridgeTxPool().RemoveTx(tx); err != nil { 399 logger.Error("Failed to remove bridge tx", 400 "txType", tx.Type(), "txNonce", tx.Nonce(), "txHash", tx.Hash().String()) 401 } else { 402 logger.Info("Removed bridge tx", 403 "txType", tx.Type(), "txNonce", tx.Nonce(), "txHash", tx.Hash().String()) 404 } 405 } // TODO-ServiceChain: Consider other types of tx failures with else {} 406 } 407 } 408 return nil 409 } 410 411 // broadcastServiceChainTx broadcasts service chain transactions to parent chain peers. 412 // It signs the given unsigned transaction with parent chain ID and then send it to its 413 // parent chain peers. 414 func (sbh *SubBridgeHandler) broadcastServiceChainTx() { 415 parentChainID := sbh.parentChainID 416 if parentChainID == nil { 417 logger.Error("unexpected nil parentChainID while broadcastServiceChainTx") 418 } 419 txs := sbh.subbridge.GetBridgeTxPool().PendingTxsByAddress(&sbh.subbridge.bridgeAccounts.pAccount.address, int(sbh.GetSentChainTxsLimit())) // TODO-Klaytn-Servicechain change GetSentChainTxsLimit type to int from uint64 420 peers := sbh.subbridge.BridgePeerSet().peers 421 422 for _, peer := range peers { 423 if peer.GetChainID().Cmp(parentChainID) != 0 { 424 logger.Error("parent peer with different parent chainID", "peerID", peer.GetID(), "peer chainID", peer.GetChainID(), "parent chainID", parentChainID) 425 continue 426 } 427 peer.SendServiceChainTxs(txs) 428 logger.Trace("sent ServiceChainTxData", "peerID", peer.GetID()) 429 } 430 logger.Trace("broadcastServiceChainTx ServiceChainTxData", "len(txs)", len(txs), "len(peers)", len(peers)) 431 } 432 433 // writeServiceChainTxReceipts writes the received receipts of service chain transactions. 434 func (sbh *SubBridgeHandler) writeServiceChainTxReceipts(bc *blockchain.BlockChain, receipts []*types.ReceiptForStorage) { 435 for _, receipt := range receipts { 436 txHash := receipt.TxHash 437 if tx := sbh.subbridge.GetBridgeTxPool().Get(txHash); tx != nil { 438 if tx.Type().IsChainDataAnchoring() { 439 data, err := tx.AnchoredData() 440 if err != nil { 441 logger.Error("failed to get anchoring data", "txHash", txHash.String(), "err", err) 442 continue 443 } 444 decodedData, err := types.DecodeAnchoringData(data) 445 if err != nil { 446 logger.Warn("failed to decode anchoring tx", "txHash", txHash.String(), "err", err) 447 continue 448 } 449 sbh.WriteReceiptFromParentChain(decodedData.GetBlockHash(), (*types.Receipt)(receipt)) 450 sbh.WriteAnchoredBlockNumber(decodedData.GetBlockNumber().Uint64()) 451 } 452 // TODO-Klaytn-ServiceChain: support other tx types if needed. 453 sbh.subbridge.GetBridgeTxPool().RemoveTx(tx) 454 } else { 455 logger.Trace("received service chain transaction receipt does not exist in sentServiceChainTxs", "txHash", txHash.String()) 456 } 457 logger.Trace("received service chain transaction receipt", "anchoring txHash", txHash.String()) 458 } 459 } 460 461 func (sbh *SubBridgeHandler) RegisterNewPeer(p BridgePeer) error { 462 sbh.subbridge.addPeerCh <- struct{}{} 463 464 if sbh.getParentChainID().Cmp(p.GetChainID()) != 0 { 465 return fmt.Errorf("attempt to add a peer with different chainID failed! existing chainID: %v, new chainID: %v", sbh.getParentChainID(), p.GetChainID()) 466 } 467 // sync nonce and gasprice with peer 468 sbh.SyncNonceAndGasPrice() 469 470 return nil 471 } 472 473 // broadcastServiceChainReceiptRequest broadcasts receipt requests for service chain transactions. 474 func (sbh *SubBridgeHandler) broadcastServiceChainReceiptRequest() { 475 hashes := sbh.subbridge.GetBridgeTxPool().PendingTxHashesByAddress(sbh.GetParentOperatorAddr(), int(sbh.GetSentChainTxsLimit())) // TODO-Klaytn-Servicechain change GetSentChainTxsLimit type to int from uint64 476 for _, peer := range sbh.subbridge.BridgePeerSet().peers { 477 peer.SendServiceChainReceiptRequest(hashes) 478 logger.Debug("sent ServiceChainReceiptRequest", "peerID", peer.GetID(), "numReceiptsRequested", len(hashes)) 479 } 480 } 481 482 // updateTxCount update txCount to insert into anchoring tx. 483 func (sbh *SubBridgeHandler) updateTxCount(block *types.Block) error { 484 if block == nil { 485 return ErrInvalidBlock 486 } 487 488 if sbh.txCountStartingBlockNumber == 0 { 489 sbh.txCount = 0 // reset for the next anchoring period 490 sbh.txCountStartingBlockNumber = block.NumberU64() 491 } 492 493 var startBlkNum uint64 494 if sbh.latestTxCountAddedBlockNumber == 0 { 495 startBlkNum = block.NumberU64() 496 } else { 497 startBlkNum = sbh.latestTxCountAddedBlockNumber + 1 498 } 499 500 if startBlkNum < sbh.txCountStartingBlockNumber { 501 startBlkNum = sbh.txCountStartingBlockNumber 502 } 503 504 for i := startBlkNum; i <= block.NumberU64(); i++ { 505 b := sbh.subbridge.blockchain.GetBlockByNumber(i) 506 if b == nil { 507 logger.Error("blockAnchoringManager: break to generateAndAddAnchoringTxIntoTxPool by the missed block", "missedBlockNumber", i) 508 break 509 } 510 sbh.txCount += uint64(b.Transactions().Len()) 511 sbh.UpdateLatestTxCountAddedBlockNumber(i) 512 } 513 514 return nil 515 } 516 517 // blockAnchoringManager generates anchoring transactions and updates transaction count. 518 func (sbh *SubBridgeHandler) blockAnchoringManager(block *types.Block) error { 519 if err := sbh.updateTxCount(block); err != nil { 520 return err 521 } 522 return sbh.generateAndAddAnchoringTxIntoTxPool(block) 523 } 524 525 func (sbh *SubBridgeHandler) generateAndAddAnchoringTxIntoTxPool(block *types.Block) error { 526 if block == nil { 527 return ErrInvalidBlock 528 } 529 530 // Generating Anchoring Tx 531 if block.NumberU64()%sbh.chainTxPeriod != 0 { 532 return nil 533 } 534 sbh.LockParentOperator() 535 defer sbh.UnLockParentOperator() 536 537 unsignedTx, err := sbh.genUnsignedChainDataAnchoringTx(block) 538 if err != nil { 539 logger.Error("Failed to generate service chain transaction", "blockNum", block.NumberU64(), "err", err) 540 return err 541 } 542 txCount := sbh.txCount 543 // Reset for the next anchoring period. 544 sbh.txCount = 0 545 sbh.txCountStartingBlockNumber = block.NumberU64() + 1 546 547 signedTx, err := sbh.subbridge.bridgeAccounts.pAccount.SignTx(unsignedTx) 548 if err != nil { 549 logger.Error("failed signing tx", "err", err) 550 return err 551 } 552 if err := sbh.subbridge.GetBridgeTxPool().AddLocal(signedTx); err == nil { 553 sbh.addParentOperatorNonce(1) 554 } else { 555 logger.Debug("failed to add tx into bridge txpool", "err", err) 556 return err 557 } 558 559 logger.Info("Generate an anchoring tx", "blockNum", block.NumberU64(), "blockhash", block.Hash().String(), "txCount", txCount, "txHash", signedTx.Hash().String()) 560 561 return nil 562 } 563 564 // SyncNonceAndGasPrice requests the nonce of address used for service chain tx to parent chain peers. 565 func (scpm *SubBridgeHandler) SyncNonceAndGasPrice() { 566 addr := scpm.GetParentOperatorAddr() 567 for _, peer := range scpm.subbridge.BridgePeerSet().peers { 568 peer.SendServiceChainInfoRequest(addr) 569 } 570 } 571 572 // GetLatestAnchoredBlockNumber returns the latest block number whose data has been anchored to the parent chain. 573 func (sbh *SubBridgeHandler) GetLatestAnchoredBlockNumber() uint64 { 574 return sbh.subbridge.ChainDB().ReadAnchoredBlockNumber() 575 } 576 577 // UpdateLatestTxCountAddedBlockNumber sets the latestTxCountAddedBlockNumber to the block number of the last anchoring tx which was added into bridge txPool. 578 func (sbh *SubBridgeHandler) UpdateLatestTxCountAddedBlockNumber(newLatestAnchoredBN uint64) { 579 if sbh.latestTxCountAddedBlockNumber < newLatestAnchoredBN { 580 sbh.latestTxCountAddedBlockNumber = newLatestAnchoredBN 581 } 582 } 583 584 // WriteAnchoredBlockNumber writes the block number whose data has been anchored to the parent chain. 585 func (sbh *SubBridgeHandler) WriteAnchoredBlockNumber(blockNum uint64) { 586 if sbh.GetLatestAnchoredBlockNumber() < blockNum { 587 sbh.subbridge.chainDB.WriteAnchoredBlockNumber(blockNum) 588 lastAnchoredBlockNumGauge.Update(int64(blockNum)) 589 } 590 } 591 592 // WriteReceiptFromParentChain writes a receipt received from parent chain to child chain 593 // with corresponding block hash. It assumes that a child chain has only one parent chain. 594 func (sbh *SubBridgeHandler) WriteReceiptFromParentChain(blockHash common.Hash, receipt *types.Receipt) { 595 sbh.subbridge.chainDB.WriteReceiptFromParentChain(blockHash, receipt) 596 } 597 598 // GetReceiptFromParentChain returns a receipt received from parent chain to child chain 599 // with corresponding block hash. It assumes that a child chain has only one parent chain. 600 func (sbh *SubBridgeHandler) GetReceiptFromParentChain(blockHash common.Hash) *types.Receipt { 601 return sbh.subbridge.chainDB.ReadReceiptFromParentChain(blockHash) 602 }