github.com/Gessiux/neatchain@v1.3.1/neatcli/neatcli1.go (about)

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