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 }