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 }