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