github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/neatio/cross_chain.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"regexp"
     9  	"strings"
    10  	"sync"
    11  	"time"
    12  	"unicode/utf8"
    13  
    14  	"github.com/neatlab/neatio/chain/consensus"
    15  	"github.com/neatlab/neatio/chain/consensus/neatcon/epoch"
    16  	ntcTypes "github.com/neatlab/neatio/chain/consensus/neatcon/types"
    17  	"github.com/neatlab/neatio/chain/core"
    18  	"github.com/neatlab/neatio/chain/core/rawdb"
    19  	"github.com/neatlab/neatio/chain/core/state"
    20  	"github.com/neatlab/neatio/chain/core/types"
    21  	"github.com/neatlab/neatio/chain/log"
    22  	"github.com/neatlab/neatio/chain/trie"
    23  	neatAbi "github.com/neatlab/neatio/neatabi/abi"
    24  	"github.com/neatlab/neatio/neatcli"
    25  	"github.com/neatlab/neatio/neatdb"
    26  	"github.com/neatlab/neatio/neatptc"
    27  	"github.com/neatlab/neatio/network/node"
    28  	"github.com/neatlab/neatio/params"
    29  	"github.com/neatlab/neatio/utilities/common"
    30  	"github.com/neatlab/neatio/utilities/common/math"
    31  	"github.com/neatlab/neatio/utilities/rlp"
    32  	"github.com/neatlib/crypto-go"
    33  	dbm "github.com/neatlib/db-go"
    34  )
    35  
    36  type CrossChainHelper struct {
    37  	mtx             sync.Mutex
    38  	chainInfoDB     dbm.DB
    39  	localTX3CacheDB neatdb.Database
    40  
    41  	client      *neatcli.Client
    42  	mainChainId string
    43  }
    44  
    45  func (cch *CrossChainHelper) GetMutex() *sync.Mutex {
    46  	return &cch.mtx
    47  }
    48  
    49  func (cch *CrossChainHelper) GetChainInfoDB() dbm.DB {
    50  	return cch.chainInfoDB
    51  }
    52  
    53  func (cch *CrossChainHelper) GetClient() *neatcli.Client {
    54  	return cch.client
    55  }
    56  
    57  func (cch *CrossChainHelper) GetMainChainId() string {
    58  	return cch.mainChainId
    59  }
    60  
    61  func (cch *CrossChainHelper) CanCreateSideChain(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 NeatIO as a side chain, try use other name instead")
    78  	}
    79  
    80  	ci := core.GetChainInfo(cch.chainInfoDB, chainId)
    81  	if ci != nil {
    82  		return fmt.Errorf("Chain %s has already exist, try use other name instead", chainId)
    83  	}
    84  
    85  	cci := core.GetPendingSideChainData(cch.chainInfoDB, chainId)
    86  	if cci != nil {
    87  		return fmt.Errorf("Chain %s has already applied, try use other name instead", chainId)
    88  	}
    89  
    90  	if minValidators < core.OFFICIAL_MINIMUM_VALIDATORS {
    91  		return fmt.Errorf("Validators count is not meet the minimum official validator count (%v)", core.OFFICIAL_MINIMUM_VALIDATORS)
    92  	}
    93  
    94  	officialMinimumDeposit := math.MustParseBig256(core.OFFICIAL_MINIMUM_DEPOSIT)
    95  	if minDepositAmount.Cmp(officialMinimumDeposit) == -1 {
    96  		return fmt.Errorf("Deposit amount is not meet the minimum official deposit amount (%v NEAT)", new(big.Int).Div(officialMinimumDeposit, big.NewInt(params.NEAT)))
    97  	}
    98  
    99  	if startupCost.Cmp(officialMinimumDeposit) != 0 {
   100  		return fmt.Errorf("Startup cost is not meet the required amount (%v NEAT)", new(big.Int).Div(officialMinimumDeposit, big.NewInt(params.NEAT)))
   101  	}
   102  
   103  	if startBlock.Cmp(endBlock) >= 0 {
   104  		return errors.New("start block number must be less than end block number")
   105  	}
   106  
   107  	neatio := MustGetNeatChainFromNode(chainMgr.mainChain.NeatNode)
   108  	currentBlock := neatio.BlockChain().CurrentBlock()
   109  	if endBlock.Cmp(currentBlock.Number()) <= 0 {
   110  		return errors.New("end block number has already passed")
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  func (cch *CrossChainHelper) CreateSideChain(from common.Address, chainId string, minValidators uint16, minDepositAmount *big.Int, startBlock, endBlock *big.Int) error {
   117  	log.Debug("CreateSideChain - start")
   118  
   119  	cci := &core.CoreChainInfo{
   120  		Owner:            from,
   121  		ChainId:          chainId,
   122  		MinValidators:    minValidators,
   123  		MinDepositAmount: minDepositAmount,
   124  		StartBlock:       startBlock,
   125  		EndBlock:         endBlock,
   126  		JoinedValidators: make([]core.JoinedValidator, 0),
   127  	}
   128  	core.CreatePendingSideChainData(cch.chainInfoDB, cci)
   129  
   130  	log.Debug("CreateSideChain - end")
   131  	return nil
   132  }
   133  
   134  func (cch *CrossChainHelper) ValidateJoinSideChain(from common.Address, consensusPubkey []byte, chainId string, depositAmount *big.Int, signature []byte) error {
   135  	log.Debug("ValidateJoinSideChain - start")
   136  
   137  	if chainId == MainChain || chainId == TestnetChain {
   138  		return errors.New("you can't join NeatIO as a side chain, try use other name instead")
   139  	}
   140  
   141  	if err := crypto.CheckConsensusPubKey(from, consensusPubkey, signature); err != nil {
   142  		return err
   143  	}
   144  
   145  	ci := core.GetPendingSideChainData(cch.chainInfoDB, chainId)
   146  	if ci == nil {
   147  		if core.GetChainInfo(cch.chainInfoDB, chainId) != nil {
   148  			return fmt.Errorf("chain %s has already created/started, try use other name instead", chainId)
   149  		} else {
   150  			return fmt.Errorf("side chain %s not exist, try use other name instead", chainId)
   151  		}
   152  	}
   153  
   154  	find := false
   155  	for _, joined := range ci.JoinedValidators {
   156  		if from == joined.Address {
   157  			find = true
   158  			break
   159  		}
   160  	}
   161  
   162  	if find {
   163  		return errors.New(fmt.Sprintf("You have already joined the Side Chain %s", chainId))
   164  	}
   165  
   166  	if !(depositAmount != nil && depositAmount.Sign() == 1) {
   167  		return errors.New("deposit amount must be greater than 0")
   168  	}
   169  
   170  	log.Debug("ValidateJoinSideChain - end")
   171  	return nil
   172  }
   173  
   174  func (cch *CrossChainHelper) JoinSideChain(from common.Address, pubkey crypto.PubKey, chainId string, depositAmount *big.Int) error {
   175  	log.Debug("JoinSideChain - start")
   176  
   177  	ci := core.GetPendingSideChainData(cch.chainInfoDB, chainId)
   178  	if ci == nil {
   179  		log.Errorf("JoinSideChain - Side Chain %s not exist, you can't join the chain", chainId)
   180  		return fmt.Errorf("Side Chain %s not exist, you can't join the chain", chainId)
   181  	}
   182  
   183  	for _, joined := range ci.JoinedValidators {
   184  		if from == joined.Address {
   185  			return nil
   186  		}
   187  	}
   188  
   189  	jv := core.JoinedValidator{
   190  		PubKey:        pubkey,
   191  		Address:       from,
   192  		DepositAmount: depositAmount,
   193  	}
   194  
   195  	ci.JoinedValidators = append(ci.JoinedValidators, jv)
   196  
   197  	core.UpdatePendingSideChainData(cch.chainInfoDB, ci)
   198  
   199  	log.Debug("JoinSideChain - end")
   200  	return nil
   201  }
   202  
   203  func (cch *CrossChainHelper) ReadyForLaunchSideChain(height *big.Int, stateDB *state.StateDB) ([]string, []byte, []string) {
   204  
   205  	readyId, updateBytes, removedId := core.GetSideChainForLaunch(cch.chainInfoDB, height, stateDB)
   206  	if len(readyId) == 0 {
   207  
   208  	} else {
   209  
   210  	}
   211  
   212  	return readyId, updateBytes, removedId
   213  }
   214  
   215  func (cch *CrossChainHelper) ProcessPostPendingData(newPendingIdxBytes []byte, deleteSideChainIds []string) {
   216  	core.ProcessPostPendingData(cch.chainInfoDB, newPendingIdxBytes, deleteSideChainIds)
   217  }
   218  
   219  func (cch *CrossChainHelper) VoteNextEpoch(ep *epoch.Epoch, from common.Address, voteHash common.Hash, txHash common.Hash) error {
   220  
   221  	voteSet := ep.GetNextEpoch().GetEpochValidatorVoteSet()
   222  	if voteSet == nil {
   223  		voteSet = epoch.NewEpochValidatorVoteSet()
   224  	}
   225  
   226  	vote, exist := voteSet.GetVoteByAddress(from)
   227  
   228  	if exist {
   229  
   230  		vote.VoteHash = voteHash
   231  		vote.TxHash = txHash
   232  	} else {
   233  
   234  		vote = &epoch.EpochValidatorVote{
   235  			Address:  from,
   236  			VoteHash: voteHash,
   237  			TxHash:   txHash,
   238  		}
   239  		voteSet.StoreVote(vote)
   240  	}
   241  
   242  	epoch.SaveEpochVoteSet(ep.GetDB(), ep.GetNextEpoch().Number, voteSet)
   243  	return nil
   244  }
   245  
   246  func (cch *CrossChainHelper) RevealVote(ep *epoch.Epoch, from common.Address, pubkey crypto.PubKey, depositAmount *big.Int, salt string, txHash common.Hash) error {
   247  
   248  	voteSet := ep.GetNextEpoch().GetEpochValidatorVoteSet()
   249  	vote, exist := voteSet.GetVoteByAddress(from)
   250  
   251  	if exist {
   252  
   253  		vote.PubKey = pubkey
   254  		vote.Amount = depositAmount
   255  		vote.Salt = salt
   256  		vote.TxHash = txHash
   257  	}
   258  
   259  	epoch.SaveEpochVoteSet(ep.GetDB(), ep.GetNextEpoch().Number, voteSet)
   260  	return nil
   261  }
   262  
   263  func (cch *CrossChainHelper) UpdateNextEpoch(ep *epoch.Epoch, from common.Address, pubkey crypto.PubKey, depositAmount *big.Int, salt string, txHash common.Hash) error {
   264  	voteSet := ep.GetNextEpoch().GetEpochValidatorVoteSet()
   265  	if voteSet == nil {
   266  		voteSet = epoch.NewEpochValidatorVoteSet()
   267  	}
   268  
   269  	vote, exist := voteSet.GetVoteByAddress(from)
   270  
   271  	if exist {
   272  		vote.Amount = depositAmount
   273  		vote.TxHash = txHash
   274  	} else {
   275  		vote = &epoch.EpochValidatorVote{
   276  			Address: from,
   277  			PubKey:  pubkey,
   278  			Amount:  depositAmount,
   279  			Salt:    "neatio",
   280  			TxHash:  txHash,
   281  		}
   282  
   283  		voteSet.StoreVote(vote)
   284  	}
   285  
   286  	epoch.SaveEpochVoteSet(ep.GetDB(), ep.GetNextEpoch().Number, voteSet)
   287  	return nil
   288  }
   289  
   290  func (cch *CrossChainHelper) GetHeightFromMainChain() *big.Int {
   291  	neatio := MustGetNeatChainFromNode(chainMgr.mainChain.NeatNode)
   292  	return neatio.BlockChain().CurrentBlock().Number()
   293  }
   294  
   295  func (cch *CrossChainHelper) GetTxFromMainChain(txHash common.Hash) *types.Transaction {
   296  	neatio := MustGetNeatChainFromNode(chainMgr.mainChain.NeatNode)
   297  	chainDb := neatio.ChainDb()
   298  
   299  	tx, _, _, _ := rawdb.ReadTransaction(chainDb, txHash)
   300  	return tx
   301  }
   302  
   303  func (cch *CrossChainHelper) GetEpochFromMainChain() (string, *epoch.Epoch) {
   304  	neatio := MustGetNeatChainFromNode(chainMgr.mainChain.NeatNode)
   305  	var ep *epoch.Epoch
   306  	if neatcon, ok := neatio.Engine().(consensus.NeatCon); ok {
   307  		ep = neatcon.GetEpoch()
   308  	}
   309  	return neatio.ChainConfig().NeatChainId, ep
   310  }
   311  
   312  func (cch *CrossChainHelper) ChangeValidators(chainId string) {
   313  
   314  	if chainMgr == nil {
   315  		return
   316  	}
   317  
   318  	var chain *Chain = nil
   319  	if chainId == MainChain || chainId == TestnetChain {
   320  		chain = chainMgr.mainChain
   321  	} else if chn, ok := chainMgr.sideChains[chainId]; ok {
   322  		chain = chn
   323  	}
   324  
   325  	if chain == nil || chain.NeatNode == nil {
   326  		return
   327  	}
   328  
   329  	if address, ok := chainMgr.getNodeValidator(chain.NeatNode); ok {
   330  		chainMgr.server.AddLocalValidator(chainId, address)
   331  	}
   332  }
   333  
   334  func (cch *CrossChainHelper) VerifySideChainProofData(bs []byte) error {
   335  
   336  	log.Debug("VerifySideChainProofData - start")
   337  
   338  	var proofData types.SideChainProofData
   339  	err := rlp.DecodeBytes(bs, &proofData)
   340  	if err != nil {
   341  		return err
   342  	}
   343  
   344  	header := proofData.Header
   345  
   346  	if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
   347  
   348  	}
   349  
   350  	ncExtra, err := ntcTypes.ExtractNeatConExtra(header)
   351  	if err != nil {
   352  		return err
   353  	}
   354  
   355  	chainId := ncExtra.ChainID
   356  	if chainId == "" || chainId == MainChain || chainId == TestnetChain {
   357  		return fmt.Errorf("invalid side chain id: %s", chainId)
   358  	}
   359  
   360  	if header.Nonce != (types.NeatConEmptyNonce) && !bytes.Equal(header.Nonce[:], types.NeatConNonce) {
   361  		return errors.New("invalid nonce")
   362  	}
   363  
   364  	if header.MixDigest != types.NeatConDigest {
   365  		return errors.New("invalid mix digest")
   366  	}
   367  
   368  	if header.UncleHash != types.NeatConNilUncleHash {
   369  		return errors.New("invalid uncle Hash")
   370  	}
   371  
   372  	if header.Difficulty == nil || header.Difficulty.Cmp(types.NeatConDefaultDifficulty) != 0 {
   373  		return errors.New("invalid difficulty")
   374  	}
   375  
   376  	if ncExtra.EpochBytes != nil && len(ncExtra.EpochBytes) != 0 {
   377  		ep := epoch.FromBytes(ncExtra.EpochBytes)
   378  		if ep != nil && ep.Number == 0 {
   379  			return nil
   380  		}
   381  	}
   382  
   383  	if chainId != "side_0" {
   384  		ci := core.GetChainInfo(cch.chainInfoDB, chainId)
   385  		if ci == nil {
   386  			return fmt.Errorf("chain info %s not found", chainId)
   387  		}
   388  		epoch := ci.GetEpochByBlockNumber(ncExtra.Height)
   389  		if epoch == nil {
   390  			return fmt.Errorf("could not get epoch for block height %v", ncExtra.Height)
   391  		}
   392  
   393  		if epoch.Number > ci.EpochNumber {
   394  			ci.EpochNumber = epoch.Number
   395  			ci.Epoch = epoch
   396  			core.SaveChainInfo(cch.chainInfoDB, ci)
   397  		}
   398  
   399  		valSet := epoch.Validators
   400  		if !bytes.Equal(valSet.Hash(), ncExtra.ValidatorsHash) {
   401  			return errors.New("inconsistent validator set")
   402  		}
   403  
   404  		seenCommit := ncExtra.SeenCommit
   405  		if !bytes.Equal(ncExtra.SeenCommitHash, seenCommit.Hash()) {
   406  			return errors.New("invalid committed seals")
   407  		}
   408  
   409  		if err = valSet.VerifyCommit(ncExtra.ChainID, ncExtra.Height, seenCommit); err != nil {
   410  			return err
   411  		}
   412  	}
   413  
   414  	log.Debug("VerifySideChainProofData - end")
   415  	return nil
   416  }
   417  
   418  func (cch *CrossChainHelper) SaveSideChainProofDataToMainChain(bs []byte) error {
   419  	log.Debug("SaveSideChainProofDataToMainChain - start")
   420  
   421  	var proofData types.SideChainProofData
   422  	err := rlp.DecodeBytes(bs, &proofData)
   423  	if err != nil {
   424  		return err
   425  	}
   426  
   427  	header := proofData.Header
   428  	ncExtra, err := ntcTypes.ExtractNeatConExtra(header)
   429  	if err != nil {
   430  		return err
   431  	}
   432  
   433  	chainId := ncExtra.ChainID
   434  	if chainId == "" || chainId == MainChain || chainId == TestnetChain {
   435  		return fmt.Errorf("invalid side chain id: %s", chainId)
   436  	}
   437  
   438  	if len(ncExtra.EpochBytes) != 0 {
   439  		ep := epoch.FromBytes(ncExtra.EpochBytes)
   440  		if ep != nil {
   441  			ci := core.GetChainInfo(cch.chainInfoDB, ncExtra.ChainID)
   442  
   443  			if ci == nil {
   444  				for {
   445  
   446  					time.Sleep(3 * time.Second)
   447  					ci = core.GetChainInfo(cch.chainInfoDB, ncExtra.ChainID)
   448  					if ci != nil {
   449  						break
   450  					}
   451  				}
   452  			}
   453  
   454  			futureEpoch := ep.Number > ci.EpochNumber && ncExtra.Height < ep.StartBlock
   455  			if futureEpoch {
   456  
   457  				core.SaveFutureEpoch(cch.chainInfoDB, ep, chainId)
   458  				log.Infof("Future epoch saved from chain: %s, epoch: %v", chainId, ep)
   459  			} else if ep.Number == 0 || ep.Number >= ci.EpochNumber {
   460  
   461  				ci.EpochNumber = ep.Number
   462  				ci.Epoch = ep
   463  				core.SaveChainInfo(cch.chainInfoDB, ci)
   464  				log.Infof("Epoch saved from chain: %s, epoch: %v", chainId, ep)
   465  			}
   466  		}
   467  	}
   468  
   469  	log.Debug("SaveSideChainProofDataToMainChain - end")
   470  	return nil
   471  }
   472  
   473  func (cch *CrossChainHelper) ValidateTX3ProofData(proofData *types.TX3ProofData) error {
   474  	log.Debug("ValidateTX3ProofData - start")
   475  
   476  	header := proofData.Header
   477  
   478  	if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
   479  
   480  	}
   481  
   482  	ncExtra, err := ntcTypes.ExtractNeatConExtra(header)
   483  	if err != nil {
   484  		return err
   485  	}
   486  
   487  	chainId := ncExtra.ChainID
   488  	if chainId == "" || chainId == MainChain || chainId == TestnetChain {
   489  		return fmt.Errorf("invalid side chain id: %s", chainId)
   490  	}
   491  
   492  	if header.Nonce != (types.NeatConEmptyNonce) && !bytes.Equal(header.Nonce[:], types.NeatConNonce) {
   493  		return errors.New("invalid nonce")
   494  	}
   495  
   496  	if header.MixDigest != types.NeatConDigest {
   497  		return errors.New("invalid mix digest")
   498  	}
   499  
   500  	if header.UncleHash != types.NeatConNilUncleHash {
   501  		return errors.New("invalid uncle Hash")
   502  	}
   503  
   504  	if header.Difficulty == nil || header.Difficulty.Cmp(types.NeatConDefaultDifficulty) != 0 {
   505  		return errors.New("invalid difficulty")
   506  	}
   507  
   508  	if ncExtra.EpochBytes != nil && len(ncExtra.EpochBytes) != 0 {
   509  		ep := epoch.FromBytes(ncExtra.EpochBytes)
   510  		if ep != nil && ep.Number == 0 {
   511  			return nil
   512  		}
   513  	}
   514  
   515  	ci := core.GetChainInfo(cch.chainInfoDB, chainId)
   516  	if ci == nil {
   517  		return fmt.Errorf("chain info %s not found", chainId)
   518  	}
   519  	epoch := ci.GetEpochByBlockNumber(ncExtra.Height)
   520  	if epoch == nil {
   521  		return fmt.Errorf("could not get epoch for block height %v", ncExtra.Height)
   522  	}
   523  
   524  	if epoch.Number > ci.EpochNumber {
   525  		ci.EpochNumber = epoch.Number
   526  		ci.Epoch = epoch
   527  		core.SaveChainInfo(cch.chainInfoDB, ci)
   528  	}
   529  
   530  	valSet := epoch.Validators
   531  	if !bytes.Equal(valSet.Hash(), ncExtra.ValidatorsHash) {
   532  		return errors.New("inconsistent validator set")
   533  	}
   534  
   535  	seenCommit := ncExtra.SeenCommit
   536  	if !bytes.Equal(ncExtra.SeenCommitHash, seenCommit.Hash()) {
   537  		return errors.New("invalid committed seals")
   538  	}
   539  
   540  	if err = valSet.VerifyCommit(ncExtra.ChainID, ncExtra.Height, seenCommit); err != nil {
   541  		return err
   542  	}
   543  
   544  	keybuf := new(bytes.Buffer)
   545  	for i, txIndex := range proofData.TxIndexs {
   546  		keybuf.Reset()
   547  		rlp.Encode(keybuf, uint(txIndex))
   548  		_, _, err := trie.VerifyProof(header.TxHash, keybuf.Bytes(), proofData.TxProofs[i])
   549  		if err != nil {
   550  			return err
   551  		}
   552  	}
   553  
   554  	log.Debug("ValidateTX3ProofData - end")
   555  	return nil
   556  }
   557  
   558  func (cch *CrossChainHelper) ValidateTX4WithInMemTX3ProofData(tx4 *types.Transaction, tx3ProofData *types.TX3ProofData) error {
   559  
   560  	signer := types.NewEIP155Signer(tx4.ChainId())
   561  	from, err := types.Sender(signer, tx4)
   562  	if err != nil {
   563  		return core.ErrInvalidSender
   564  	}
   565  
   566  	var args neatAbi.WithdrawFromMainChainArgs
   567  
   568  	if !neatAbi.IsNeatChainContractAddr(tx4.To()) {
   569  		return errors.New("invalid TX4: wrong To()")
   570  	}
   571  
   572  	data := tx4.Data()
   573  	function, err := neatAbi.FunctionTypeFromId(data[:4])
   574  	if err != nil {
   575  		return err
   576  	}
   577  
   578  	if function != neatAbi.WithdrawFromMainChain {
   579  		return errors.New("invalid TX4: wrong function")
   580  	}
   581  
   582  	if err := neatAbi.ChainABI.UnpackMethodInputs(&args, neatAbi.WithdrawFromMainChain.String(), data[4:]); err != nil {
   583  		return err
   584  	}
   585  
   586  	header := tx3ProofData.Header
   587  	if err != nil {
   588  		return err
   589  	}
   590  	keybuf := new(bytes.Buffer)
   591  	rlp.Encode(keybuf, tx3ProofData.TxIndexs[0])
   592  	val, _, err := trie.VerifyProof(header.TxHash, keybuf.Bytes(), tx3ProofData.TxProofs[0])
   593  	if err != nil {
   594  		return err
   595  	}
   596  
   597  	var tx3 types.Transaction
   598  	err = rlp.DecodeBytes(val, &tx3)
   599  	if err != nil {
   600  		return err
   601  	}
   602  
   603  	signer2 := types.NewEIP155Signer(tx3.ChainId())
   604  	tx3From, err := types.Sender(signer2, &tx3)
   605  	if err != nil {
   606  		return core.ErrInvalidSender
   607  	}
   608  
   609  	var tx3Args neatAbi.WithdrawFromSideChainArgs
   610  	tx3Data := tx3.Data()
   611  	if err := neatAbi.ChainABI.UnpackMethodInputs(&tx3Args, neatAbi.WithdrawFromSideChain.String(), tx3Data[4:]); err != nil {
   612  		return err
   613  	}
   614  
   615  	if from != tx3From || args.ChainId != tx3Args.ChainId || args.Amount.Cmp(tx3.Value()) != 0 {
   616  		return errors.New("params are not consistent with tx in side chain")
   617  	}
   618  
   619  	return nil
   620  }
   621  
   622  func (cch *CrossChainHelper) GetTX3(chainId string, txHash common.Hash) *types.Transaction {
   623  	return rawdb.GetTX3(cch.localTX3CacheDB, chainId, txHash)
   624  }
   625  
   626  func (cch *CrossChainHelper) DeleteTX3(chainId string, txHash common.Hash) {
   627  	rawdb.DeleteTX3(cch.localTX3CacheDB, chainId, txHash)
   628  }
   629  
   630  func (cch *CrossChainHelper) WriteTX3ProofData(proofData *types.TX3ProofData) error {
   631  	return rawdb.WriteTX3ProofData(cch.localTX3CacheDB, proofData)
   632  }
   633  
   634  func (cch *CrossChainHelper) GetTX3ProofData(chainId string, txHash common.Hash) *types.TX3ProofData {
   635  	return rawdb.GetTX3ProofData(cch.localTX3CacheDB, chainId, txHash)
   636  }
   637  
   638  func (cch *CrossChainHelper) GetAllTX3ProofData() []*types.TX3ProofData {
   639  	return rawdb.GetAllTX3ProofData(cch.localTX3CacheDB)
   640  }
   641  
   642  func MustGetNeatChainFromNode(node *node.Node) *neatptc.NeatIO {
   643  	neatChain, err := getNeatChainFromNode(node)
   644  	if err != nil {
   645  		panic("getNeatChainFromNode error: " + err.Error())
   646  	}
   647  	return neatChain
   648  }
   649  
   650  func getNeatChainFromNode(node *node.Node) (*neatptc.NeatIO, error) {
   651  	var neatChain *neatptc.NeatIO
   652  	if err := node.Service(&neatChain); err != nil {
   653  		return nil, err
   654  	}
   655  
   656  	return neatChain, nil
   657  }