github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/intclient/intclient1.go (about) 1 package intclient 2 3 import ( 4 "context" 5 "crypto/ecdsa" 6 "github.com/intfoundation/intchain/common" 7 "github.com/intfoundation/intchain/common/hexutil" 8 "github.com/intfoundation/intchain/core/types" 9 "github.com/intfoundation/intchain/crypto" 10 intAbi "github.com/intfoundation/intchain/intabi/abi" 11 "github.com/intfoundation/intchain/log" 12 "github.com/intfoundation/intchain/params" 13 "github.com/pkg/errors" 14 "math/big" 15 "math/rand" 16 "time" 17 ) 18 19 func (ec *Client) BlockNumber(ctx context.Context) (*big.Int, error) { 20 21 var hex hexutil.Big 22 23 err := ec.c.CallContext(ctx, &hex, "eth_blockNumber") 24 if err != nil { 25 return nil, err 26 } 27 return (*big.Int)(&hex), nil 28 } 29 30 // SendDataToMainChain send epoch data to main chain through eth_sendRawTransaction 31 func (ec *Client) SendDataToMainChain(ctx context.Context, data []byte, prv *ecdsa.PrivateKey, mainChainId string) (common.Hash, error) { 32 33 // data 34 bs, err := intAbi.ChainABI.Pack(intAbi.SaveDataToMainChain.String(), data) 35 if err != nil { 36 return common.Hash{}, err 37 } 38 39 account := crypto.PubkeyToAddress(prv.PublicKey) 40 41 // nonce, fetch the nonce first, if we get nonce too low error, we will manually add the value until the error gone 42 nonce, err := ec.NonceAt(ctx, account, nil) 43 if err != nil { 44 return common.Hash{}, err 45 } 46 47 // tx signer for the main chain 48 digest := crypto.Keccak256([]byte(mainChainId)) 49 signer := types.NewEIP155Signer(new(big.Int).SetBytes(digest[:])) 50 51 var hash = common.Hash{} 52 //should send successfully, let's wait longer time 53 err = retry(30, time.Second*3, func() error { 54 // gasPrice 55 gasPrice, err := ec.SuggestGasPrice(ctx) 56 if err != nil { 57 return err 58 } 59 60 SendTX: 61 // tx 62 tx := types.NewTransaction(nonce, intAbi.ChainContractMagicAddr, nil, 0, gasPrice, bs) 63 64 // sign the tx 65 signedTx, err := types.SignTx(tx, signer, prv) 66 if err != nil { 67 return err 68 } 69 70 // eth_sendRawTransaction 71 err = ec.SendTransaction(ctx, signedTx) 72 if err != nil { 73 if err.Error() == "nonce too low" { 74 log.Warnf("SendDataToMainChain: failed, nonce too low, %v current nonce is %v. Will try to increase the nonce then send again.", account, nonce) 75 nonce += 1 76 goto SendTX 77 } else { 78 return err 79 } 80 } 81 82 hash = signedTx.Hash() 83 return nil 84 }) 85 86 return hash, err 87 } 88 89 // BroadcastDataToMainChain send tx3 proof data to MainChain via rpc call, then broadcast it via p2p network 90 func (ec *Client) BroadcastDataToMainChain(ctx context.Context, chainId string, data []byte) error { 91 if chainId == "" || chainId == params.MainnetChainConfig.IntChainId || chainId == params.TestnetChainConfig.IntChainId { 92 return errors.New("invalid child chainId") 93 } 94 95 err := retry(1, time.Millisecond*200, func() error { 96 return ec.c.CallContext(ctx, nil, "chain_broadcastTX3ProofData", common.ToHex(data)) 97 }) 98 99 return err 100 } 101 102 func retry(attemps int, sleep time.Duration, fn func() error) error { 103 104 if err := fn(); err != nil { 105 if attemps--; attemps >= 0 { 106 // Add some randomness to prevent creating a Thundering Herd 107 jitter := time.Duration(rand.Int63n(int64(sleep))) 108 sleep = sleep + jitter/2 109 110 time.Sleep(sleep) 111 return retry(attemps, sleep*2, fn) 112 } 113 114 return err 115 } 116 117 return nil 118 }