github.com/klaytn/klaytn@v1.12.1/node/sc/main_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  	"math/big"
    21  
    22  	"github.com/klaytn/klaytn/blockchain/types"
    23  	"github.com/klaytn/klaytn/common"
    24  	"github.com/klaytn/klaytn/datasync/downloader"
    25  	"github.com/klaytn/klaytn/networks/p2p"
    26  	"github.com/klaytn/klaytn/params"
    27  	"github.com/klaytn/klaytn/rlp"
    28  	"github.com/pkg/errors"
    29  )
    30  
    31  var ErrRPCDecode = errors.New("failed to decode mainbridge rpc call message")
    32  
    33  type MainBridgeHandler struct {
    34  	mainbridge *MainBridge
    35  	// childChainID is the first received chainID from child chain peer.
    36  	childChainIDs map[common.Address]*big.Int
    37  }
    38  
    39  func NewMainBridgeHandler(scc *SCConfig, main *MainBridge) (*MainBridgeHandler, error) {
    40  	return &MainBridgeHandler{
    41  		mainbridge:    main,
    42  		childChainIDs: make(map[common.Address]*big.Int),
    43  	}, nil
    44  }
    45  
    46  func (mbh *MainBridgeHandler) HandleSubMsg(p BridgePeer, msg p2p.Msg) error {
    47  	logger.Trace("mainbridge handle sub message", "msg.Code", msg.Code)
    48  
    49  	// Handle the message depending on its contents
    50  	switch msg.Code {
    51  	case ServiceChainCall:
    52  		if err := mbh.handleCallMsg(p, msg); err != nil {
    53  			return err
    54  		}
    55  		return nil
    56  	case StatusMsg:
    57  		return nil
    58  	case ServiceChainTxsMsg:
    59  		logger.Trace("received ServiceChainTxsMsg")
    60  		// TODO-Klaytn how to check acceptTxs
    61  		// Transactions arrived, make sure we have a valid and fresh chain to handle them
    62  		//if atomic.LoadUint32(&pm.acceptTxs) == 0 {
    63  		//	break
    64  		//}
    65  		if err := mbh.handleServiceChainTxDataMsg(p, msg); err != nil {
    66  			return err
    67  		}
    68  	case ServiceChainParentChainInfoRequestMsg:
    69  		logger.Debug("received ServiceChainParentChainInfoRequestMsg")
    70  		if err := mbh.handleServiceChainParentChainInfoRequestMsg(p, msg); err != nil {
    71  			return err
    72  		}
    73  	case ServiceChainReceiptRequestMsg:
    74  		logger.Debug("received ServiceChainReceiptRequestMsg")
    75  		if err := mbh.handleServiceChainReceiptRequestMsg(p, msg); err != nil {
    76  			return err
    77  		}
    78  	default:
    79  		return errResp(ErrInvalidMsgCode, "%v", msg.Code)
    80  	}
    81  	return nil
    82  }
    83  
    84  func (mbh *MainBridgeHandler) handleCallMsg(p BridgePeer, msg p2p.Msg) error {
    85  	logger.Trace("mainbridge writes the rpc call message to rpc server", "msg.Size", msg.Size, "msg", msg)
    86  	data := make([]byte, msg.Size)
    87  	err := msg.Decode(&data)
    88  	if err != nil {
    89  		logger.Error("error in mainbridge message handler", "err", err)
    90  		return err
    91  	}
    92  
    93  	// Write to RPC server pipe
    94  	_, err = mbh.mainbridge.rpcConn.Write(data)
    95  	if err != nil {
    96  		logger.Error("failed to write to the rpc server pipe", "err", err)
    97  		return err
    98  	}
    99  	return nil
   100  }
   101  
   102  // handleServiceChainTxDataMsg handles service chain transactions from child chain.
   103  // It will return an error if given tx is not TxTypeChainDataAnchoring type.
   104  func (mbh *MainBridgeHandler) handleServiceChainTxDataMsg(p BridgePeer, msg p2p.Msg) error {
   105  	// pm.txMsgLock.Lock()
   106  	// Transactions can be processed, parse all of them and deliver to the pool
   107  	var txs []*types.Transaction
   108  	if err := msg.Decode(&txs); err != nil {
   109  		return errResp(ErrDecode, "msg %v: %v", msg, err)
   110  	}
   111  
   112  	// Only valid txs should be pushed into the pool.
   113  	// Invalid txs found are sent to child chain for further action.
   114  	invalidTxs := make([]InvalidParentChainTx, 0)
   115  	for _, tx := range txs {
   116  		if tx == nil {
   117  			invalidTxs = append(invalidTxs, InvalidParentChainTx{tx.Hash(), errResp(ErrDecode, "tx is nil").Error()})
   118  			continue
   119  		}
   120  		if err := mbh.mainbridge.txPool.AddRemote(tx); err != nil {
   121  			txHash := tx.Hash()
   122  			logger.Trace("Invalid tx found",
   123  				"txType", tx.Type(), "txNonce", tx.Nonce(), "txHash", txHash.String(), "err", err)
   124  			invalidTxs = append(invalidTxs, InvalidParentChainTx{txHash, err.Error()})
   125  		}
   126  	}
   127  	if len(invalidTxs) > 0 {
   128  		return p.SendServiceChainInvalidTxResponse(invalidTxs)
   129  	}
   130  	return nil
   131  }
   132  
   133  // handleServiceChainParentChainInfoRequestMsg handles parent chain info request message from child chain.
   134  // It will send the nonce of the account and its gas price to the child chain peer who requested.
   135  func (mbh *MainBridgeHandler) handleServiceChainParentChainInfoRequestMsg(p BridgePeer, msg p2p.Msg) error {
   136  	var addr common.Address
   137  	if err := msg.Decode(&addr); err != nil {
   138  		return errResp(ErrDecode, "msg %v: %v", msg, err)
   139  	}
   140  	nonce := mbh.mainbridge.txPool.GetPendingNonce(addr)
   141  	chainCfg := mbh.mainbridge.blockchain.Config()
   142  	pcInfo := parentChainInfo{
   143  		nonce,
   144  		mbh.mainbridge.txPool.GasPrice().Uint64(),
   145  		params.KIP71Config{
   146  			LowerBoundBaseFee:         chainCfg.Governance.KIP71.LowerBoundBaseFee,
   147  			UpperBoundBaseFee:         chainCfg.Governance.KIP71.UpperBoundBaseFee,
   148  			GasTarget:                 chainCfg.Governance.KIP71.GasTarget,
   149  			MaxBlockGasUsedForBaseFee: chainCfg.Governance.KIP71.MaxBlockGasUsedForBaseFee,
   150  			BaseFeeDenominator:        chainCfg.Governance.KIP71.BaseFeeDenominator,
   151  		},
   152  		chainCfg.IsMagmaForkEnabled(mbh.mainbridge.blockchain.CurrentBlock().Number()),
   153  	}
   154  	p.SendServiceChainInfoResponse(&pcInfo)
   155  	logger.Info("SendServiceChainInfoResponse", "pBridgeAccoount", addr,
   156  		"nonce", pcInfo.Nonce, "gasPrice", pcInfo.GasPrice,
   157  		"LowerBoundBaseFee", pcInfo.KIP71Config.LowerBoundBaseFee,
   158  		"UpperBoundBaseFee", pcInfo.KIP71Config.UpperBoundBaseFee,
   159  		"GasTarget", pcInfo.KIP71Config.GasTarget,
   160  		"MaxBlockGasUsedForBaseFee", pcInfo.KIP71Config.MaxBlockGasUsedForBaseFee,
   161  		"BaseFeeDenominator", pcInfo.KIP71Config.BaseFeeDenominator,
   162  	)
   163  	return nil
   164  }
   165  
   166  // handleServiceChainReceiptRequestMsg handles receipt request message from child chain.
   167  // It will find and send corresponding receipts with given transaction hashes.
   168  func (mbh *MainBridgeHandler) handleServiceChainReceiptRequestMsg(p BridgePeer, msg p2p.Msg) error {
   169  	// Decode the retrieval message
   170  	msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))
   171  	if _, err := msgStream.List(); err != nil {
   172  		return err
   173  	}
   174  	// Gather state data until the fetch or network limits is reached
   175  	var (
   176  		hash               common.Hash
   177  		receiptsForStorage []*types.ReceiptForStorage
   178  	)
   179  	for len(receiptsForStorage) < downloader.MaxReceiptFetch {
   180  		// Retrieve the hash of the next block
   181  		if err := msgStream.Decode(&hash); err == rlp.EOL {
   182  			break
   183  		} else if err != nil {
   184  			return errResp(ErrDecode, "msg %v: %v", msg, err)
   185  		}
   186  		// Retrieve the receipt of requested service chain tx, skip if unknown.
   187  		receipt := mbh.mainbridge.blockchain.GetReceiptByTxHash(hash)
   188  		if receipt == nil {
   189  			continue
   190  		}
   191  
   192  		receiptsForStorage = append(receiptsForStorage, (*types.ReceiptForStorage)(receipt))
   193  	}
   194  	if len(receiptsForStorage) == 0 {
   195  		return nil
   196  	}
   197  	return p.SendServiceChainReceiptResponse(receiptsForStorage)
   198  }