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 }