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  }