github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/cmd/intchain/cross_chain.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/intfoundation/go-crypto"
     8  	dbm "github.com/intfoundation/go-db"
     9  	"github.com/intfoundation/intchain/common"
    10  	"github.com/intfoundation/intchain/common/math"
    11  	"github.com/intfoundation/intchain/consensus"
    12  	"github.com/intfoundation/intchain/consensus/ipbft/epoch"
    13  	tdmTypes "github.com/intfoundation/intchain/consensus/ipbft/types"
    14  	"github.com/intfoundation/intchain/core"
    15  	"github.com/intfoundation/intchain/core/rawdb"
    16  	"github.com/intfoundation/intchain/core/state"
    17  	"github.com/intfoundation/intchain/core/types"
    18  	intAbi "github.com/intfoundation/intchain/intabi/abi"
    19  	"github.com/intfoundation/intchain/intclient"
    20  	"github.com/intfoundation/intchain/intdb"
    21  	"github.com/intfoundation/intchain/intprotocol"
    22  	"github.com/intfoundation/intchain/log"
    23  	"github.com/intfoundation/intchain/node"
    24  	"github.com/intfoundation/intchain/params"
    25  	"github.com/intfoundation/intchain/rlp"
    26  	"github.com/intfoundation/intchain/trie"
    27  	"math/big"
    28  	"regexp"
    29  	"strings"
    30  	"sync"
    31  	"time"
    32  	"unicode/utf8"
    33  )
    34  
    35  type CrossChainHelper struct {
    36  	mtx             sync.Mutex
    37  	chainInfoDB     dbm.DB
    38  	localTX3CacheDB intdb.Database
    39  	//the client does only connect to main chain
    40  	client      *intclient.Client
    41  	mainChainId string
    42  }
    43  
    44  func (cch *CrossChainHelper) GetMutex() *sync.Mutex {
    45  	return &cch.mtx
    46  }
    47  
    48  func (cch *CrossChainHelper) GetChainInfoDB() dbm.DB {
    49  	return cch.chainInfoDB
    50  }
    51  
    52  func (cch *CrossChainHelper) GetClient() *intclient.Client {
    53  	return cch.client
    54  }
    55  
    56  func (cch *CrossChainHelper) GetMainChainId() string {
    57  	return cch.mainChainId
    58  }
    59  
    60  // CanCreateChildChain check the condition before send the create child chain into the tx pool
    61  func (cch *CrossChainHelper) CanCreateChildChain(from common.Address, chainId string, minValidators uint16, minDepositAmount, startupCost *big.Int, startBlock, endBlock *big.Int) error {
    62  
    63  	if chainId == "" || strings.Contains(chainId, ";") {
    64  		return errors.New("chainId is nil or empty, or contains ';', should be meaningful")
    65  	}
    66  
    67  	pass, _ := regexp.MatchString("^[a-z]+[a-z0-9_]*$", chainId)
    68  	if !pass {
    69  		return errors.New("chainId must be start with letter (a-z) and contains alphanumeric(lower case) or underscore, try use other name instead")
    70  	}
    71  
    72  	if utf8.RuneCountInString(chainId) > 30 {
    73  		return errors.New("max characters of chain id is 30, try use other name instead")
    74  	}
    75  
    76  	if chainId == MainChain || chainId == TestnetChain {
    77  		return errors.New("you can't create IntChain as a child chain, try use other name instead")
    78  	}
    79  
    80  	// Check if "chainId" has been created
    81  	ci := core.GetChainInfo(cch.chainInfoDB, chainId)
    82  	if ci != nil {
    83  		return fmt.Errorf("Chain %s has already exist, try use other name instead", chainId)
    84  	}
    85  
    86  	// Check if "chainId" has been registered
    87  	cci := core.GetPendingChildChainData(cch.chainInfoDB, chainId)
    88  	if cci != nil {
    89  		return fmt.Errorf("Chain %s has already applied, try use other name instead", chainId)
    90  	}
    91  
    92  	// Check the minimum validators
    93  	if minValidators < core.OFFICIAL_MINIMUM_VALIDATORS {
    94  		return fmt.Errorf("Validators count is not meet the minimum official validator count (%v)", core.OFFICIAL_MINIMUM_VALIDATORS)
    95  	}
    96  
    97  	// Check the minimum deposit amount
    98  	officialMinimumDeposit := math.MustParseBig256(core.OFFICIAL_MINIMUM_DEPOSIT)
    99  	if minDepositAmount.Cmp(officialMinimumDeposit) == -1 {
   100  		return fmt.Errorf("Deposit amount is not meet the minimum official deposit amount (%v INT)", new(big.Int).Div(officialMinimumDeposit, big.NewInt(params.INT)))
   101  	}
   102  
   103  	// Check the startup cost
   104  	if startupCost.Cmp(officialMinimumDeposit) != 0 {
   105  		return fmt.Errorf("Startup cost is not meet the required amount (%v INT)", new(big.Int).Div(officialMinimumDeposit, big.NewInt(params.INT)))
   106  	}
   107  
   108  	// Check start/end block
   109  	if startBlock.Cmp(endBlock) >= 0 {
   110  		return errors.New("start block number must be less than end block number")
   111  	}
   112  
   113  	// Check End Block already passed
   114  	intnode := MustGetIntChainFromNode(chainMgr.mainChain.IntNode)
   115  	currentBlock := intnode.BlockChain().CurrentBlock()
   116  	if endBlock.Cmp(currentBlock.Number()) <= 0 {
   117  		return errors.New("end block number has already passed")
   118  	}
   119  
   120  	return nil
   121  }
   122  
   123  // CreateChildChain Save the Child Chain Data into the DB, the data will be used later during Block Commit Callback
   124  func (cch *CrossChainHelper) CreateChildChain(from common.Address, chainId string, minValidators uint16, minDepositAmount *big.Int, startBlock, endBlock *big.Int) error {
   125  	log.Debug("CreateChildChain - start")
   126  
   127  	cci := &core.CoreChainInfo{
   128  		Owner:            from,
   129  		ChainId:          chainId,
   130  		MinValidators:    minValidators,
   131  		MinDepositAmount: minDepositAmount,
   132  		StartBlock:       startBlock,
   133  		EndBlock:         endBlock,
   134  		JoinedValidators: make([]core.JoinedValidator, 0),
   135  	}
   136  	core.CreatePendingChildChainData(cch.chainInfoDB, cci)
   137  
   138  	log.Debug("CreateChildChain - end")
   139  	return nil
   140  }
   141  
   142  // ValidateJoinChildChain check the criteria whether it meets the join child chain requirement
   143  func (cch *CrossChainHelper) ValidateJoinChildChain(from common.Address, consensusPubkey []byte, chainId string, depositAmount *big.Int, signature []byte) error {
   144  	log.Debug("ValidateJoinChildChain - start")
   145  
   146  	if chainId == MainChain || chainId == TestnetChain {
   147  		return errors.New("you can't join IntChain as a child chain, try use other name instead")
   148  	}
   149  
   150  	// Check Signature of the PubKey matched against the Address
   151  	if err := crypto.CheckConsensusPubKey(from, consensusPubkey, signature); err != nil {
   152  		return err
   153  	}
   154  
   155  	// Check if "chainId" has been created/registered
   156  	ci := core.GetPendingChildChainData(cch.chainInfoDB, chainId)
   157  	if ci == nil {
   158  		if core.GetChainInfo(cch.chainInfoDB, chainId) != nil {
   159  			return fmt.Errorf("chain %s has already created/started, try use other name instead", chainId)
   160  		} else {
   161  			return fmt.Errorf("child chain %s not exist, try use other name instead", chainId)
   162  		}
   163  	}
   164  
   165  	// Check if already joined the chain
   166  	find := false
   167  	for _, joined := range ci.JoinedValidators {
   168  		if from == joined.Address {
   169  			find = true
   170  			break
   171  		}
   172  	}
   173  
   174  	if find {
   175  		return errors.New(fmt.Sprintf("You have already joined the Child Chain %s", chainId))
   176  	}
   177  
   178  	// Check the deposit amount
   179  	if !(depositAmount != nil && depositAmount.Sign() == 1) {
   180  		return errors.New("deposit amount must be greater than 0")
   181  	}
   182  
   183  	log.Debug("ValidateJoinChildChain - end")
   184  	return nil
   185  }
   186  
   187  // JoinChildChain Join the Child Chain
   188  func (cch *CrossChainHelper) JoinChildChain(from common.Address, pubkey crypto.PubKey, chainId string, depositAmount *big.Int) error {
   189  	log.Debug("JoinChildChain - start")
   190  
   191  	// Load the Child Chain first
   192  	ci := core.GetPendingChildChainData(cch.chainInfoDB, chainId)
   193  	if ci == nil {
   194  		log.Errorf("JoinChildChain - Child Chain %s not exist, you can't join the chain", chainId)
   195  		return fmt.Errorf("Child Chain %s not exist, you can't join the chain", chainId)
   196  	}
   197  
   198  	for _, joined := range ci.JoinedValidators {
   199  		if from == joined.Address {
   200  			return nil
   201  		}
   202  	}
   203  
   204  	jv := core.JoinedValidator{
   205  		PubKey:        pubkey,
   206  		Address:       from,
   207  		DepositAmount: depositAmount,
   208  	}
   209  
   210  	ci.JoinedValidators = append(ci.JoinedValidators, jv)
   211  
   212  	core.UpdatePendingChildChainData(cch.chainInfoDB, ci)
   213  
   214  	log.Debug("JoinChildChain - end")
   215  	return nil
   216  }
   217  
   218  func (cch *CrossChainHelper) ReadyForLaunchChildChain(height *big.Int, stateDB *state.StateDB) ([]string, []byte, []string) {
   219  	//log.Debug("ReadyForLaunchChildChain - start")
   220  
   221  	readyId, updateBytes, removedId := core.GetChildChainForLaunch(cch.chainInfoDB, height, stateDB)
   222  	if len(readyId) == 0 {
   223  		//log.Debugf("ReadyForLaunchChildChain - No child chain to be launch in Block %v", height)
   224  	} else {
   225  		//log.Infof("ReadyForLaunchChildChain - %v child chain(s) to be launch in Block %v. %v", len(readyId), height, readyId)
   226  	}
   227  
   228  	//log.Debug("ReadyForLaunchChildChain - end")
   229  	return readyId, updateBytes, removedId
   230  }
   231  
   232  func (cch *CrossChainHelper) ProcessPostPendingData(newPendingIdxBytes []byte, deleteChildChainIds []string) {
   233  	core.ProcessPostPendingData(cch.chainInfoDB, newPendingIdxBytes, deleteChildChainIds)
   234  }
   235  
   236  func (cch *CrossChainHelper) VoteNextEpoch(ep *epoch.Epoch, from common.Address, voteHash common.Hash, txHash common.Hash) error {
   237  
   238  	voteSet := ep.GetNextEpoch().GetEpochValidatorVoteSet()
   239  	if voteSet == nil {
   240  		voteSet = epoch.NewEpochValidatorVoteSet()
   241  	}
   242  
   243  	vote, exist := voteSet.GetVoteByAddress(from)
   244  
   245  	if exist {
   246  		// Overwrite the Previous Hash Vote
   247  		vote.VoteHash = voteHash
   248  		vote.TxHash = txHash
   249  	} else {
   250  		// Create a new Hash Vote
   251  		vote = &epoch.EpochValidatorVote{
   252  			Address:  from,
   253  			VoteHash: voteHash,
   254  			TxHash:   txHash,
   255  		}
   256  		voteSet.StoreVote(vote)
   257  	}
   258  	// Save the VoteSet
   259  	epoch.SaveEpochVoteSet(ep.GetDB(), ep.GetNextEpoch().Number, voteSet)
   260  	return nil
   261  }
   262  
   263  func (cch *CrossChainHelper) RevealVote(ep *epoch.Epoch, from common.Address, pubkey crypto.PubKey, depositAmount *big.Int, salt string, txHash common.Hash) error {
   264  
   265  	voteSet := ep.GetNextEpoch().GetEpochValidatorVoteSet()
   266  	vote, exist := voteSet.GetVoteByAddress(from)
   267  
   268  	if exist {
   269  		// Update the Hash Vote with Real Data
   270  		vote.PubKey = pubkey
   271  		vote.Amount = depositAmount
   272  		vote.Salt = salt
   273  		vote.TxHash = txHash
   274  	}
   275  	// Save the VoteSet
   276  	epoch.SaveEpochVoteSet(ep.GetDB(), ep.GetNextEpoch().Number, voteSet)
   277  	return nil
   278  }
   279  
   280  func (cch *CrossChainHelper) UpdateNextEpoch(ep *epoch.Epoch, from common.Address, pubkey crypto.PubKey, depositAmount *big.Int, salt string, txHash common.Hash) error {
   281  	voteSet := ep.GetNextEpoch().GetEpochValidatorVoteSet()
   282  	if voteSet == nil {
   283  		voteSet = epoch.NewEpochValidatorVoteSet()
   284  	}
   285  
   286  	vote, exist := voteSet.GetVoteByAddress(from)
   287  
   288  	if exist {
   289  		vote.Amount = depositAmount
   290  		vote.TxHash = txHash
   291  	} else {
   292  		vote = &epoch.EpochValidatorVote{
   293  			Address: from,
   294  			PubKey:  pubkey,
   295  			Amount:  depositAmount,
   296  			Salt:    "intchain",
   297  			TxHash:  txHash,
   298  		}
   299  
   300  		voteSet.StoreVote(vote)
   301  	}
   302  
   303  	// Save the VoteSet
   304  	epoch.SaveEpochVoteSet(ep.GetDB(), ep.GetNextEpoch().Number, voteSet)
   305  	return nil
   306  }
   307  
   308  func (cch *CrossChainHelper) GetHeightFromMainChain() *big.Int {
   309  	intnode := MustGetIntChainFromNode(chainMgr.mainChain.IntNode)
   310  	return intnode.BlockChain().CurrentBlock().Number()
   311  }
   312  
   313  func (cch *CrossChainHelper) GetTxFromMainChain(txHash common.Hash) *types.Transaction {
   314  	intnode := MustGetIntChainFromNode(chainMgr.mainChain.IntNode)
   315  	chainDb := intnode.ChainDb()
   316  
   317  	tx, _, _, _ := rawdb.ReadTransaction(chainDb, txHash)
   318  	return tx
   319  }
   320  
   321  func (cch *CrossChainHelper) GetEpochFromMainChain() (string, *epoch.Epoch) {
   322  	intnode := MustGetIntChainFromNode(chainMgr.mainChain.IntNode)
   323  	var ep *epoch.Epoch
   324  	if ipbft, ok := intnode.Engine().(consensus.IPBFT); ok {
   325  		ep = ipbft.GetEpoch()
   326  	}
   327  	return intnode.ChainConfig().IntChainId, ep
   328  }
   329  
   330  func (cch *CrossChainHelper) ChangeValidators(chainId string) {
   331  
   332  	if chainMgr == nil {
   333  		return
   334  	}
   335  
   336  	var chain *Chain = nil
   337  	if chainId == MainChain || chainId == TestnetChain {
   338  		chain = chainMgr.mainChain
   339  	} else if chn, ok := chainMgr.childChains[chainId]; ok {
   340  		chain = chn
   341  	}
   342  
   343  	if chain == nil || chain.IntNode == nil {
   344  		return
   345  	}
   346  
   347  	if address, ok := chainMgr.getNodeValidator(chain.IntNode); ok {
   348  		chainMgr.server.AddLocalValidator(chainId, address)
   349  	}
   350  }
   351  
   352  // verify the signature of validators who voted for the block
   353  // most of the logic here is from 'VerifyHeader'
   354  func (cch *CrossChainHelper) VerifyChildChainProofData(bs []byte) error {
   355  
   356  	log.Debug("VerifyChildChainProofData - start")
   357  
   358  	var proofData types.ChildChainProofData
   359  	err := rlp.DecodeBytes(bs, &proofData)
   360  	if err != nil {
   361  		return err
   362  	}
   363  
   364  	header := proofData.Header
   365  	// Don't waste time checking blocks from the future
   366  	if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
   367  		//return errors.New("block in the future")
   368  	}
   369  
   370  	tdmExtra, err := tdmTypes.ExtractTendermintExtra(header)
   371  	if err != nil {
   372  		return err
   373  	}
   374  
   375  	chainId := tdmExtra.ChainID
   376  	if chainId == "" || chainId == MainChain || chainId == TestnetChain {
   377  		return fmt.Errorf("invalid child chain id: %s", chainId)
   378  	}
   379  
   380  	if header.Nonce != (types.TendermintEmptyNonce) && !bytes.Equal(header.Nonce[:], types.TendermintNonce) {
   381  		return errors.New("invalid nonce")
   382  	}
   383  
   384  	if header.MixDigest != types.TendermintDigest {
   385  		return errors.New("invalid mix digest")
   386  	}
   387  
   388  	if header.UncleHash != types.TendermintNilUncleHash {
   389  		return errors.New("invalid uncle Hash")
   390  	}
   391  
   392  	if header.Difficulty == nil || header.Difficulty.Cmp(types.TendermintDefaultDifficulty) != 0 {
   393  		return errors.New("invalid difficulty")
   394  	}
   395  
   396  	// special case: epoch 0 update
   397  	// TODO: how to verify this block which includes epoch 0?
   398  	if tdmExtra.EpochBytes != nil && len(tdmExtra.EpochBytes) != 0 {
   399  		ep := epoch.FromBytes(tdmExtra.EpochBytes)
   400  		if ep != nil && ep.Number == 0 {
   401  			return nil
   402  		}
   403  	}
   404  
   405  	// Bypass the validator check for official child chain 0
   406  	// TODO where need
   407  	if chainId != "child_0" {
   408  		ci := core.GetChainInfo(cch.chainInfoDB, chainId)
   409  		if ci == nil {
   410  			return fmt.Errorf("chain info %s not found", chainId)
   411  		}
   412  		epoch := ci.GetEpochByBlockNumber(tdmExtra.Height)
   413  		if epoch == nil {
   414  			return fmt.Errorf("could not get epoch for block height %v", tdmExtra.Height)
   415  		}
   416  
   417  		if epoch.Number > ci.EpochNumber {
   418  			ci.EpochNumber = epoch.Number
   419  			ci.Epoch = epoch
   420  			core.SaveChainInfo(cch.chainInfoDB, ci)
   421  		}
   422  
   423  		valSet := epoch.Validators
   424  		if !bytes.Equal(valSet.Hash(), tdmExtra.ValidatorsHash) {
   425  			return errors.New("inconsistent validator set")
   426  		}
   427  
   428  		seenCommit := tdmExtra.SeenCommit
   429  		if !bytes.Equal(tdmExtra.SeenCommitHash, seenCommit.Hash()) {
   430  			return errors.New("invalid committed seals")
   431  		}
   432  
   433  		if err = valSet.VerifyCommit(tdmExtra.ChainID, tdmExtra.Height, seenCommit); err != nil {
   434  			return err
   435  		}
   436  	}
   437  
   438  	log.Debug("VerifyChildChainProofData - end")
   439  	return nil
   440  }
   441  
   442  func (cch *CrossChainHelper) SaveChildChainProofDataToMainChain(bs []byte) error {
   443  	log.Debug("SaveChildChainProofDataToMainChain - start")
   444  
   445  	var proofData types.ChildChainProofData
   446  	err := rlp.DecodeBytes(bs, &proofData)
   447  	if err != nil {
   448  		return err
   449  	}
   450  
   451  	header := proofData.Header
   452  	tdmExtra, err := tdmTypes.ExtractTendermintExtra(header)
   453  	if err != nil {
   454  		return err
   455  	}
   456  
   457  	chainId := tdmExtra.ChainID
   458  	if chainId == "" || chainId == MainChain || chainId == TestnetChain {
   459  		return fmt.Errorf("invalid child chain id: %s", chainId)
   460  	}
   461  
   462  	// here is epoch update; should be a more general mechanism
   463  	if len(tdmExtra.EpochBytes) != 0 {
   464  		ep := epoch.FromBytes(tdmExtra.EpochBytes)
   465  		if ep != nil {
   466  			ci := core.GetChainInfo(cch.chainInfoDB, tdmExtra.ChainID)
   467  			// ChainInfo is nil means we need to wait for Child Chain to be launched, this could happened during catch-up scenario
   468  			if ci == nil {
   469  				for {
   470  					// wait for 3 sec and try again
   471  					time.Sleep(3 * time.Second)
   472  					ci = core.GetChainInfo(cch.chainInfoDB, tdmExtra.ChainID)
   473  					if ci != nil {
   474  						break
   475  					}
   476  				}
   477  			}
   478  
   479  			futureEpoch := ep.Number > ci.EpochNumber && tdmExtra.Height < ep.StartBlock
   480  			if futureEpoch {
   481  				// Future Epoch, just save the Epoch into Chain Info DB
   482  				core.SaveFutureEpoch(cch.chainInfoDB, ep, chainId)
   483  				log.Infof("Future epoch saved from chain: %s, epoch: %v", chainId, ep)
   484  			} else if ep.Number == 0 || ep.Number >= ci.EpochNumber {
   485  				// New Epoch, save or update the Epoch into Chain Info DB
   486  				ci.EpochNumber = ep.Number
   487  				ci.Epoch = ep
   488  				core.SaveChainInfo(cch.chainInfoDB, ci)
   489  				log.Infof("Epoch saved from chain: %s, epoch: %v", chainId, ep)
   490  			}
   491  		}
   492  	}
   493  
   494  	log.Debug("SaveChildChainProofDataToMainChain - end")
   495  	return nil
   496  }
   497  
   498  func (cch *CrossChainHelper) ValidateTX3ProofData(proofData *types.TX3ProofData) error {
   499  	log.Debug("ValidateTX3ProofData - start")
   500  
   501  	header := proofData.Header
   502  	// Don't waste time checking blocks from the future
   503  	if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
   504  		//return errors.New("block in the future")
   505  	}
   506  
   507  	tdmExtra, err := tdmTypes.ExtractTendermintExtra(header)
   508  	if err != nil {
   509  		return err
   510  	}
   511  
   512  	chainId := tdmExtra.ChainID
   513  	if chainId == "" || chainId == MainChain || chainId == TestnetChain {
   514  		return fmt.Errorf("invalid child chain id: %s", chainId)
   515  	}
   516  
   517  	if header.Nonce != (types.TendermintEmptyNonce) && !bytes.Equal(header.Nonce[:], types.TendermintNonce) {
   518  		return errors.New("invalid nonce")
   519  	}
   520  
   521  	if header.MixDigest != types.TendermintDigest {
   522  		return errors.New("invalid mix digest")
   523  	}
   524  
   525  	if header.UncleHash != types.TendermintNilUncleHash {
   526  		return errors.New("invalid uncle Hash")
   527  	}
   528  
   529  	if header.Difficulty == nil || header.Difficulty.Cmp(types.TendermintDefaultDifficulty) != 0 {
   530  		return errors.New("invalid difficulty")
   531  	}
   532  
   533  	// special case: epoch 0 update
   534  	// TODO: how to verify this block which includes epoch 0?
   535  	if tdmExtra.EpochBytes != nil && len(tdmExtra.EpochBytes) != 0 {
   536  		ep := epoch.FromBytes(tdmExtra.EpochBytes)
   537  		if ep != nil && ep.Number == 0 {
   538  			return nil
   539  		}
   540  	}
   541  
   542  	ci := core.GetChainInfo(cch.chainInfoDB, chainId)
   543  	if ci == nil {
   544  		return fmt.Errorf("chain info %s not found", chainId)
   545  	}
   546  	epoch := ci.GetEpochByBlockNumber(tdmExtra.Height)
   547  	if epoch == nil {
   548  		return fmt.Errorf("could not get epoch for block height %v", tdmExtra.Height)
   549  	}
   550  
   551  	if epoch.Number > ci.EpochNumber {
   552  		ci.EpochNumber = epoch.Number
   553  		ci.Epoch = epoch
   554  		core.SaveChainInfo(cch.chainInfoDB, ci)
   555  	}
   556  
   557  	valSet := epoch.Validators
   558  	if !bytes.Equal(valSet.Hash(), tdmExtra.ValidatorsHash) {
   559  		return errors.New("inconsistent validator set")
   560  	}
   561  
   562  	seenCommit := tdmExtra.SeenCommit
   563  	if !bytes.Equal(tdmExtra.SeenCommitHash, seenCommit.Hash()) {
   564  		return errors.New("invalid committed seals")
   565  	}
   566  
   567  	if err = valSet.VerifyCommit(tdmExtra.ChainID, tdmExtra.Height, seenCommit); err != nil {
   568  		return err
   569  	}
   570  
   571  	// tx merkle proof verify
   572  	keybuf := new(bytes.Buffer)
   573  	for i, txIndex := range proofData.TxIndexs {
   574  		keybuf.Reset()
   575  		rlp.Encode(keybuf, uint(txIndex))
   576  		_, _, err := trie.VerifyProof(header.TxHash, keybuf.Bytes(), proofData.TxProofs[i])
   577  		if err != nil {
   578  			return err
   579  		}
   580  	}
   581  
   582  	log.Debug("ValidateTX3ProofData - end")
   583  	return nil
   584  }
   585  
   586  func (cch *CrossChainHelper) ValidateTX4WithInMemTX3ProofData(tx4 *types.Transaction, tx3ProofData *types.TX3ProofData) error {
   587  	// TX4
   588  	signer := types.NewEIP155Signer(tx4.ChainId())
   589  	from, err := types.Sender(signer, tx4)
   590  	if err != nil {
   591  		return core.ErrInvalidSender
   592  	}
   593  
   594  	var args intAbi.WithdrawFromMainChainArgs
   595  
   596  	if !intAbi.IsIntChainContractAddr(tx4.To()) {
   597  		return errors.New("invalid TX4: wrong To()")
   598  	}
   599  
   600  	data := tx4.Data()
   601  	function, err := intAbi.FunctionTypeFromId(data[:4])
   602  	if err != nil {
   603  		return err
   604  	}
   605  
   606  	if function != intAbi.WithdrawFromMainChain {
   607  		return errors.New("invalid TX4: wrong function")
   608  	}
   609  
   610  	if err := intAbi.ChainABI.UnpackMethodInputs(&args, intAbi.WithdrawFromMainChain.String(), data[4:]); err != nil {
   611  		return err
   612  	}
   613  
   614  	// TX3
   615  	header := tx3ProofData.Header
   616  	if err != nil {
   617  		return err
   618  	}
   619  	keybuf := new(bytes.Buffer)
   620  	rlp.Encode(keybuf, tx3ProofData.TxIndexs[0])
   621  	val, _, err := trie.VerifyProof(header.TxHash, keybuf.Bytes(), tx3ProofData.TxProofs[0])
   622  	if err != nil {
   623  		return err
   624  	}
   625  
   626  	var tx3 types.Transaction
   627  	err = rlp.DecodeBytes(val, &tx3)
   628  	if err != nil {
   629  		return err
   630  	}
   631  
   632  	signer2 := types.NewEIP155Signer(tx3.ChainId())
   633  	tx3From, err := types.Sender(signer2, &tx3)
   634  	if err != nil {
   635  		return core.ErrInvalidSender
   636  	}
   637  
   638  	var tx3Args intAbi.WithdrawFromChildChainArgs
   639  	tx3Data := tx3.Data()
   640  	if err := intAbi.ChainABI.UnpackMethodInputs(&tx3Args, intAbi.WithdrawFromChildChain.String(), tx3Data[4:]); err != nil {
   641  		return err
   642  	}
   643  
   644  	// Does TX3 & TX4 Match
   645  	if from != tx3From || args.ChainId != tx3Args.ChainId || args.Amount.Cmp(tx3.Value()) != 0 {
   646  		return errors.New("params are not consistent with tx in child chain")
   647  	}
   648  
   649  	return nil
   650  }
   651  
   652  //SaveDataToMainV1 acceps both epoch and tx3
   653  //func (cch *CrossChainHelper) VerifyChildChainProofDataV1(proofData *types.ChildChainProofDataV1) error {
   654  //
   655  //	log.Debug("VerifyChildChainProofDataV1 - start")
   656  //
   657  //	header := proofData.Header
   658  //	// Don't waste time checking blocks from the future
   659  //	if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
   660  //		//return errors.New("block in the future")
   661  //	}
   662  //
   663  //	tdmExtra, err := tdmTypes.ExtractTendermintExtra(header)
   664  //	if err != nil {
   665  //		return err
   666  //	}
   667  //
   668  //	chainId := tdmExtra.ChainID
   669  //	if chainId == "" || chainId == MainChain || chainId == TestnetChain {
   670  //		return fmt.Errorf("invalid child chain id: %s", chainId)
   671  //	}
   672  //
   673  //	if header.Nonce != (types.TendermintEmptyNonce) && !bytes.Equal(header.Nonce[:], types.TendermintNonce) {
   674  //		return errors.New("invalid nonce")
   675  //	}
   676  //
   677  //	if header.MixDigest != types.TendermintDigest {
   678  //		return errors.New("invalid mix digest")
   679  //	}
   680  //
   681  //	if header.UncleHash != types.TendermintNilUncleHash {
   682  //		return errors.New("invalid uncle Hash")
   683  //	}
   684  //
   685  //	if header.Difficulty == nil || header.Difficulty.Cmp(types.TendermintDefaultDifficulty) != 0 {
   686  //		return errors.New("invalid difficulty")
   687  //	}
   688  //
   689  //	ci := core.GetChainInfo(cch.chainInfoDB, chainId)
   690  //	if ci == nil {
   691  //		return fmt.Errorf("chain info %s not found", chainId)
   692  //	}
   693  //
   694  //	isSd2mc := params.IsSd2mc(cch.GetMainChainId(), cch.GetHeightFromMainChain())
   695  //	// Bypass the validator check for official child chain 0
   696  //	if chainId != "child_0" || isSd2mc {
   697  //
   698  //		getValidatorsFromChainInfo := false
   699  //		if tdmExtra.EpochBytes != nil && len(tdmExtra.EpochBytes) != 0 {
   700  //			ep := epoch.FromBytes(tdmExtra.EpochBytes)
   701  //			if ep != nil && ep.Number == 0 {
   702  //				//Child chain just created and save the epoch info, get validators from chain info
   703  //				getValidatorsFromChainInfo = true
   704  //			}
   705  //		}
   706  //
   707  //		var valSet *tdmTypes.ValidatorSet = nil
   708  //		if !getValidatorsFromChainInfo {
   709  //			ep := ci.GetEpochByBlockNumber(tdmExtra.Height)
   710  //			if ep == nil {
   711  //				return fmt.Errorf("could not get epoch for block height %v", tdmExtra.Height)
   712  //			}
   713  //			valSet = ep.Validators
   714  //		} else {
   715  //			_, tdmGenesis := core.LoadChainGenesis(cch.chainInfoDB, chainId)
   716  //			if tdmGenesis == nil {
   717  //				return errors.New(fmt.Sprintf("unable to retrieve the genesis file for child chain %s", chainId))
   718  //			}
   719  //			coreGenesis, err := tdmTypes.GenesisDocFromJSON(tdmGenesis)
   720  //			if err != nil {
   721  //				return err
   722  //			}
   723  //
   724  //			ep := epoch.MakeOneEpoch(nil, &coreGenesis.CurrentEpoch, nil)
   725  //			if ep == nil {
   726  //				return fmt.Errorf("could not get epoch for genesis information")
   727  //			}
   728  //			valSet = ep.Validators
   729  //		}
   730  //
   731  //		if !bytes.Equal(valSet.Hash(), tdmExtra.ValidatorsHash) {
   732  //			return errors.New("inconsistent validator set")
   733  //		}
   734  //
   735  //		seenCommit := tdmExtra.SeenCommit
   736  //		if !bytes.Equal(tdmExtra.SeenCommitHash, seenCommit.Hash()) {
   737  //			return errors.New("invalid committed seals")
   738  //		}
   739  //
   740  //		if err = valSet.VerifyCommit(tdmExtra.ChainID, tdmExtra.Height, seenCommit); err != nil {
   741  //			return err
   742  //		}
   743  //	}
   744  //
   745  //	//Verify Tx3
   746  //	// tx merkle proof verify
   747  //	keybuf := new(bytes.Buffer)
   748  //	for i, txIndex := range proofData.TxIndexs {
   749  //		keybuf.Reset()
   750  //		rlp.Encode(keybuf, uint(txIndex))
   751  //		_, _, err := trie.VerifyProof(header.TxHash, keybuf.Bytes(), proofData.TxProofs[i])
   752  //		if err != nil {
   753  //			return err
   754  //		}
   755  //	}
   756  //
   757  //	log.Debug("VerifyChildChainProofDataV1 - end")
   758  //	return nil
   759  //}
   760  //
   761  //func (cch *CrossChainHelper) SaveChildChainProofDataToMainChainV1(proofData *types.ChildChainProofDataV1) error {
   762  //	log.Info("SaveChildChainProofDataToMainChainV1 - start")
   763  //
   764  //	header := proofData.Header
   765  //	tdmExtra, err := tdmTypes.ExtractTendermintExtra(header)
   766  //	if err != nil {
   767  //		return err
   768  //	}
   769  //
   770  //	chainId := tdmExtra.ChainID
   771  //	if chainId == "" || chainId == MainChain || chainId == TestnetChain {
   772  //		return fmt.Errorf("invalid child chain id: %s", chainId)
   773  //	}
   774  //
   775  //	// here is epoch update; should be a more general mechanism
   776  //	if len(tdmExtra.EpochBytes) != 0 {
   777  //		log.Info("SaveChildChainProofDataToMainChainV1 - Save Epoch")
   778  //		ep := epoch.FromBytes(tdmExtra.EpochBytes)
   779  //		if ep != nil {
   780  //			ci := core.GetChainInfo(cch.chainInfoDB, tdmExtra.ChainID)
   781  //			// ChainInfo is nil means we need to wait for Child Chain to be launched, this could happened during catch-up scenario
   782  //			if ci == nil {
   783  //				return fmt.Errorf("not possible to pass verification")
   784  //			}
   785  //
   786  //			futureEpoch := ep.Number > ci.EpochNumber && tdmExtra.Height < ep.StartBlock
   787  //			if futureEpoch {
   788  //				// Future Epoch, just save the Epoch into Chain Info DB
   789  //				core.SaveFutureEpoch(cch.chainInfoDB, ep, chainId)
   790  //			} else if ep.Number == 0 || ep.Number >= ci.EpochNumber {
   791  //				// New Epoch, save or update the Epoch into Chain Info DB
   792  //				ci.EpochNumber = ep.Number
   793  //				ci.Epoch = ep
   794  //				core.SaveChainInfo(cch.chainInfoDB, ci)
   795  //				log.Infof("Epoch saved from chain: %s, epoch: %v", chainId, ep)
   796  //			}
   797  //		}
   798  //	}
   799  //
   800  //	// Write the TX3ProofData
   801  //	if len(proofData.TxIndexs) != 0 {
   802  //
   803  //		log.Infof("SaveChildChainProofDataToMainChainV1 - Save Tx3, count is %v", len(proofData.TxIndexs))
   804  //		tx3ProofData := &types.TX3ProofData{
   805  //			Header:   proofData.Header,
   806  //			TxIndexs: proofData.TxIndexs,
   807  //			TxProofs: proofData.TxProofs,
   808  //		}
   809  //		if err := cch.WriteTX3ProofData(tx3ProofData); err != nil {
   810  //			log.Error("TX3ProofDataMsg write error", "error", err)
   811  //		}
   812  //	}
   813  //
   814  //	log.Info("SaveChildChainProofDataToMainChainV1 - end")
   815  //	return nil
   816  //}
   817  
   818  // TX3LocalCache start
   819  func (cch *CrossChainHelper) GetTX3(chainId string, txHash common.Hash) *types.Transaction {
   820  	return rawdb.GetTX3(cch.localTX3CacheDB, chainId, txHash)
   821  }
   822  
   823  func (cch *CrossChainHelper) DeleteTX3(chainId string, txHash common.Hash) {
   824  	rawdb.DeleteTX3(cch.localTX3CacheDB, chainId, txHash)
   825  }
   826  
   827  func (cch *CrossChainHelper) WriteTX3ProofData(proofData *types.TX3ProofData) error {
   828  	return rawdb.WriteTX3ProofData(cch.localTX3CacheDB, proofData)
   829  }
   830  
   831  func (cch *CrossChainHelper) GetTX3ProofData(chainId string, txHash common.Hash) *types.TX3ProofData {
   832  	return rawdb.GetTX3ProofData(cch.localTX3CacheDB, chainId, txHash)
   833  }
   834  
   835  func (cch *CrossChainHelper) GetAllTX3ProofData() []*types.TX3ProofData {
   836  	return rawdb.GetAllTX3ProofData(cch.localTX3CacheDB)
   837  }
   838  
   839  // TX3LocalCache end
   840  
   841  func MustGetIntChainFromNode(node *node.Node) *intprotocol.IntChain {
   842  	intChain, err := getIntChainFromNode(node)
   843  	if err != nil {
   844  		panic("getIntChainFromNode error: " + err.Error())
   845  	}
   846  	return intChain
   847  }
   848  
   849  func getIntChainFromNode(node *node.Node) (*intprotocol.IntChain, error) {
   850  	var intChain *intprotocol.IntChain
   851  	if err := node.Service(&intChain); err != nil {
   852  		return nil, err
   853  	}
   854  
   855  	return intChain, nil
   856  }