github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/neatcli/neatio.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/neatlab/neatio/chain/core/types" 11 "github.com/neatlab/neatio/chain/log" 12 neatAbi "github.com/neatlab/neatio/neatabi/abi" 13 "github.com/neatlab/neatio/params" 14 "github.com/neatlab/neatio/utilities/common" 15 "github.com/neatlab/neatio/utilities/common/hexutil" 16 "github.com/neatlab/neatio/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 func (ec *Client) SendDataToMainChain(ctx context.Context, data []byte, prv *ecdsa.PrivateKey, mainChainId string) (common.Hash, error) { 32 33 bs, err := neatAbi.ChainABI.Pack(neatAbi.SaveDataToMainChain.String(), data) 34 if err != nil { 35 return common.Hash{}, err 36 } 37 38 account := crypto.PubkeyToAddress(prv.PublicKey) 39 40 nonce, err := ec.NonceAt(ctx, account, nil) 41 if err != nil { 42 return common.Hash{}, err 43 } 44 45 digest := crypto.Keccak256([]byte(mainChainId)) 46 signer := types.NewEIP155Signer(new(big.Int).SetBytes(digest[:])) 47 48 var hash = common.Hash{} 49 50 err = retry(30, time.Second*3, func() error { 51 52 gasPrice, err := ec.SuggestGasPrice(ctx) 53 if err != nil { 54 return err 55 } 56 57 SendTX: 58 59 tx := types.NewTransaction(nonce, neatAbi.NeatioSmartContractAddress, nil, 0, gasPrice, bs) 60 61 signedTx, err := types.SignTx(tx, signer, prv) 62 if err != nil { 63 return err 64 } 65 66 err = ec.SendTransaction(ctx, signedTx) 67 if err != nil { 68 if err.Error() == "nonce too low" { 69 log.Warnf("SendDataToMainChain: failed, nonce too low, %v current nonce is %v. Will try to increase the nonce then send again.", account, nonce) 70 nonce += 1 71 goto SendTX 72 } else { 73 return err 74 } 75 } 76 77 hash = signedTx.Hash() 78 return nil 79 }) 80 81 return hash, err 82 } 83 84 func (ec *Client) BroadcastDataToMainChain(ctx context.Context, chainId string, data []byte) error { 85 if chainId == "" || chainId == params.MainnetChainConfig.NeatChainId || chainId == params.TestnetChainConfig.NeatChainId { 86 return errors.New("invalid side chainId") 87 } 88 89 err := retry(1, time.Millisecond*200, func() error { 90 return ec.c.CallContext(ctx, nil, "chain_broadcastTX3ProofData", common.ToHex(data)) 91 }) 92 93 return err 94 } 95 96 func retry(attemps int, sleep time.Duration, fn func() error) error { 97 98 if err := fn(); err != nil { 99 if attemps--; attemps >= 0 { 100 101 jitter := time.Duration(rand.Int63n(int64(sleep))) 102 sleep = sleep + jitter/2 103 104 time.Sleep(sleep) 105 return retry(attemps, sleep*2, fn) 106 } 107 108 return err 109 } 110 111 return nil 112 }