github.com/lino-network/lino@v0.6.11/client/core/core.go (about)

     1  package core
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"strings"
     7  
     8  	sdk "github.com/cosmos/cosmos-sdk/types"
     9  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    10  	"github.com/pkg/errors"
    11  	"github.com/tendermint/tendermint/crypto"
    12  	cmn "github.com/tendermint/tendermint/libs/common"
    13  	rpcclient "github.com/tendermint/tendermint/rpc/client"
    14  	ttypes "github.com/tendermint/tendermint/types"
    15  )
    16  
    17  // BroadcastTx - broadcast the transaction bytes to Tendermint
    18  func (ctx CoreContext) BroadcastTx(txBytes []byte) (sdk.TxResponse, error) {
    19  	node, err := ctx.GetNode()
    20  	if err != nil {
    21  		return sdk.TxResponse{}, err
    22  	}
    23  
    24  	res, err := node.BroadcastTxCommit(txBytes)
    25  	if err != nil {
    26  		return sdk.NewResponseFormatBroadcastTxCommit(res), err
    27  	}
    28  
    29  	if !res.CheckTx.IsOK() {
    30  		return sdk.NewResponseFormatBroadcastTxCommit(res), fmt.Errorf(res.CheckTx.Log)
    31  	}
    32  
    33  	if !res.DeliverTx.IsOK() {
    34  		return sdk.NewResponseFormatBroadcastTxCommit(res), fmt.Errorf(res.DeliverTx.Log)
    35  	}
    36  
    37  	return sdk.NewResponseFormatBroadcastTxCommit(res), nil
    38  }
    39  
    40  // Query - query from Tendermint with the provided key and storename
    41  func (ctx CoreContext) Query(key cmn.HexBytes, storeName string) (res []byte, err error) {
    42  	return ctx.query(key, storeName, "key")
    43  }
    44  
    45  // Query from Tendermint with the provided storename and path
    46  func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) {
    47  	path := fmt.Sprintf("/store/%s/%s", storeName, endPath)
    48  	node, err := ctx.GetNode()
    49  	if err != nil {
    50  		return res, err
    51  	}
    52  
    53  	opts := rpcclient.ABCIQueryOptions{
    54  		Height: ctx.Height,
    55  		Prove:  !ctx.TrustNode,
    56  	}
    57  	result, err := node.ABCIQueryWithOptions(path, key, opts)
    58  	if err != nil {
    59  		return res, err
    60  	}
    61  	resp := result.Response
    62  	if resp.Code != uint32(0) {
    63  		return res, errors.Errorf("Query failed: (%d) %s", resp.Code, resp.Log)
    64  	}
    65  	return resp.Value, nil
    66  }
    67  
    68  type OptionalSigner struct {
    69  	PrivKey crypto.PrivKey
    70  	Seq     uint64
    71  }
    72  
    73  func (ctx CoreContext) DoTxPrintResponse(msg sdk.Msg, optionalSigners ...OptionalSigner) error {
    74  	if err := msg.ValidateBasic(); err != nil {
    75  		return err
    76  	}
    77  
    78  	if ctx.Offline {
    79  		tx, err := ctx.BuildAndSign([]sdk.Msg{msg}, optionalSigners...)
    80  		if err != nil {
    81  			return err
    82  		}
    83  		txhex := hex.EncodeToString(tx)
    84  		txhex = strings.ToUpper(txhex)
    85  		fmt.Println(string(tx))
    86  		fmt.Println(txhex)
    87  		return nil
    88  	}
    89  
    90  	// build and sign the transaction, then broadcast to Tendermint
    91  	res, signErr := ctx.SignBuildBroadcast([]sdk.Msg{msg}, optionalSigners...)
    92  	if signErr != nil {
    93  		return signErr
    94  	}
    95  
    96  	fmt.Println(res.String())
    97  	return nil
    98  }
    99  
   100  // sign and build the transaction from the msg
   101  func (ctx CoreContext) SignBuildBroadcast(msgs []sdk.Msg, optionalSigners ...OptionalSigner) (sdk.TxResponse, error) {
   102  	txBytes, err := ctx.BuildAndSign(msgs, optionalSigners...)
   103  	if err != nil {
   104  		return sdk.TxResponse{}, err
   105  	}
   106  	fmt.Printf("broadcasting tx: %s\n",
   107  		strings.ToUpper(hex.EncodeToString(ttypes.Tx(txBytes).Hash())))
   108  	return ctx.BroadcastTx(txBytes)
   109  }
   110  
   111  func MakeSignature(msg authtypes.StdSignMsg, pk crypto.PrivKey) (sig authtypes.StdSignature, err error) {
   112  	// sign and build
   113  	bz := msg.Bytes()
   114  	if pk == nil {
   115  		return sig, errors.New("Must provide private key")
   116  	}
   117  	sigBytes, err := pk.Sign(bz)
   118  	if err != nil {
   119  		return sig, err
   120  	}
   121  	sig = authtypes.StdSignature{
   122  		PubKey:    pk.PubKey(),
   123  		Signature: sigBytes,
   124  	}
   125  	return sig, err
   126  }
   127  
   128  func (ctx CoreContext) Sign(msg []authtypes.StdSignMsg, keys []crypto.PrivKey) ([]byte, error) {
   129  	sigs := make([]authtypes.StdSignature, 0)
   130  	for i, pk := range keys {
   131  		sig, err := MakeSignature(msg[i], pk)
   132  		if err != nil {
   133  			return nil, err
   134  		}
   135  		sigs = append(sigs, sig)
   136  	}
   137  
   138  	return ctx.TxEncoder(
   139  		authtypes.NewStdTx(msg[0].Msgs, msg[0].Fee, sigs, msg[0].Memo))
   140  }
   141  
   142  func (ctx CoreContext) BuildSignMsg(msgs []sdk.Msg, seq uint64) (authtypes.StdSignMsg, error) {
   143  	if ctx.ChainID == "" {
   144  		return authtypes.StdSignMsg{}, fmt.Errorf("chain ID required but not specified")
   145  	}
   146  	fees := ctx.Fees
   147  	return authtypes.StdSignMsg{
   148  		ChainID:       ctx.ChainID,
   149  		AccountNumber: 0,
   150  		Sequence:      seq,
   151  		Memo:          ctx.Memo,
   152  		Msgs:          msgs,
   153  		Fee:           authtypes.NewStdFee(1, fees),
   154  	}, nil
   155  }
   156  
   157  func (ctx CoreContext) BuildAndSign(msgs []sdk.Msg, optionalSigners ...OptionalSigner) ([]byte, error) {
   158  	primary, err := ctx.BuildSignMsg(msgs, ctx.Sequence)
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	stdMsgs := []authtypes.StdSignMsg{primary}
   164  	privKeys := []crypto.PrivKey{ctx.PrivKey}
   165  	for _, signer := range optionalSigners {
   166  		msg, err := ctx.BuildSignMsg(msgs, signer.Seq)
   167  		if err != nil {
   168  			return nil, err
   169  		}
   170  		stdMsgs = append(stdMsgs, msg)
   171  		privKeys = append(privKeys, signer.PrivKey)
   172  	}
   173  
   174  	return ctx.Sign(stdMsgs, privKeys)
   175  }
   176  
   177  // GetNode prepares a simple rpc.Client
   178  func (ctx CoreContext) GetNode() (rpcclient.Client, error) {
   179  	if ctx.Client == nil {
   180  		return nil, errors.New("Must define node URI")
   181  	}
   182  	return ctx.Client, nil
   183  }