github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/deploy/def/client.go (about)

     1  package def
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"reflect"
     8  	"strconv"
     9  	"time"
    10  
    11  	"github.com/hyperledger/burrow/encoding"
    12  	"github.com/tendermint/tendermint/p2p"
    13  
    14  	"github.com/hyperledger/burrow/acm"
    15  	"github.com/hyperledger/burrow/acm/acmstate"
    16  	"github.com/hyperledger/burrow/binary"
    17  	"github.com/hyperledger/burrow/crypto"
    18  	"github.com/hyperledger/burrow/execution/evm/abi"
    19  	"github.com/hyperledger/burrow/execution/exec"
    20  	"github.com/hyperledger/burrow/execution/names"
    21  	"github.com/hyperledger/burrow/execution/registry"
    22  	"github.com/hyperledger/burrow/genesis/spec"
    23  	"github.com/hyperledger/burrow/keys"
    24  	"github.com/hyperledger/burrow/logging"
    25  	"github.com/hyperledger/burrow/permission"
    26  	"github.com/hyperledger/burrow/rpc"
    27  	"github.com/hyperledger/burrow/rpc/rpcevents"
    28  	"github.com/hyperledger/burrow/rpc/rpcquery"
    29  	"github.com/hyperledger/burrow/rpc/rpctransact"
    30  	"github.com/hyperledger/burrow/txs"
    31  	"github.com/hyperledger/burrow/txs/payload"
    32  	hex "github.com/tmthrgd/go-hex"
    33  )
    34  
    35  type Client struct {
    36  	MempoolSigning    bool
    37  	ChainAddress      string
    38  	KeysClientAddress string
    39  	// Memoised clients and info
    40  	chainID               string
    41  	timeout               time.Duration
    42  	transactClient        rpctransact.TransactClient
    43  	queryClient           rpcquery.QueryClient
    44  	executionEventsClient rpcevents.ExecutionEventsClient
    45  	keyClient             keys.KeyClient
    46  	AllSpecs              *abi.Spec
    47  }
    48  
    49  func NewClient(chain, keysClientAddress string, mempoolSigning bool, timeout time.Duration) *Client {
    50  	client := Client{
    51  		ChainAddress:      chain,
    52  		MempoolSigning:    mempoolSigning,
    53  		KeysClientAddress: keysClientAddress,
    54  		timeout:           timeout,
    55  	}
    56  	return &client
    57  }
    58  
    59  // Connect GRPC clients using ChainURL
    60  func (c *Client) dial(logger *logging.Logger) error {
    61  	if c.transactClient == nil {
    62  		conn, err := encoding.GRPCDial(c.ChainAddress)
    63  		if err != nil {
    64  			return err
    65  		}
    66  		c.transactClient = rpctransact.NewTransactClient(conn)
    67  		c.queryClient = rpcquery.NewQueryClient(conn)
    68  		c.executionEventsClient = rpcevents.NewExecutionEventsClient(conn)
    69  		if c.KeysClientAddress == "" {
    70  			logger.InfoMsg("Using mempool signing since no keyClient set, pass --keys to sign locally or elsewhere")
    71  			c.MempoolSigning = true
    72  			c.keyClient, err = keys.NewRemoteKeyClient(c.ChainAddress, logger)
    73  		} else {
    74  			logger.InfoMsg("Using keys server", "server", c.KeysClientAddress)
    75  			c.keyClient, err = keys.NewRemoteKeyClient(c.KeysClientAddress, logger)
    76  		}
    77  
    78  		if err != nil {
    79  			return err
    80  		}
    81  		ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
    82  		defer cancel()
    83  
    84  		stat, err := c.queryClient.Status(ctx, &rpcquery.StatusParam{})
    85  		if err != nil {
    86  			return err
    87  		}
    88  		c.chainID = stat.ChainID
    89  	}
    90  	return nil
    91  }
    92  
    93  func (c *Client) Transact(logger *logging.Logger) (rpctransact.TransactClient, error) {
    94  	err := c.dial(logger)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	return c.transactClient, err
    99  }
   100  
   101  func (c *Client) Query(logger *logging.Logger) (rpcquery.QueryClient, error) {
   102  	err := c.dial(logger)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	return c.queryClient, nil
   107  }
   108  
   109  func (c *Client) Events(logger *logging.Logger) (rpcevents.ExecutionEventsClient, error) {
   110  	err := c.dial(logger)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	return c.executionEventsClient, nil
   115  }
   116  
   117  func (c *Client) Status(logger *logging.Logger) (*rpc.ResultStatus, error) {
   118  	err := c.dial(logger)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   123  	defer cancel()
   124  	return c.queryClient.Status(ctx, &rpcquery.StatusParam{})
   125  }
   126  
   127  func (c *Client) ParseAddress(key string, logger *logging.Logger) (crypto.Address, error) {
   128  	address, err := crypto.AddressFromHexString(key)
   129  	if err == nil {
   130  		return address, nil
   131  	}
   132  	err = c.dial(logger)
   133  	if err != nil {
   134  		return crypto.Address{}, err
   135  	}
   136  	return c.keyClient.GetAddressForKeyName(key)
   137  }
   138  
   139  func (c *Client) GetAccount(address crypto.Address) (*acm.Account, error) {
   140  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   141  	defer cancel()
   142  	return c.queryClient.GetAccount(ctx, &rpcquery.GetAccountParam{Address: address})
   143  }
   144  
   145  func (c *Client) GetMetadataForAccount(address crypto.Address) (string, error) {
   146  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   147  	defer cancel()
   148  	metadata, err := c.queryClient.GetMetadata(ctx, &rpcquery.GetMetadataParam{Address: &address})
   149  	if err != nil {
   150  		return "", err
   151  	}
   152  
   153  	return metadata.Metadata, nil
   154  }
   155  
   156  func (c *Client) GetMetadata(metahash acmstate.MetadataHash) (string, error) {
   157  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   158  	defer cancel()
   159  	var bs binary.HexBytes = metahash.Bytes()
   160  	metadata, err := c.queryClient.GetMetadata(ctx, &rpcquery.GetMetadataParam{MetadataHash: &bs})
   161  	if err != nil {
   162  		return "", err
   163  	}
   164  
   165  	return metadata.Metadata, nil
   166  }
   167  
   168  func (c *Client) GetStorage(address crypto.Address, key binary.Word256) ([]byte, error) {
   169  	val, err := c.queryClient.GetStorage(context.Background(), &rpcquery.GetStorageParam{Address: address, Key: key})
   170  	if err != nil {
   171  		return []byte{}, err
   172  	}
   173  	return val.Value, err
   174  }
   175  
   176  func (c *Client) GetName(name string, logger *logging.Logger) (*names.Entry, error) {
   177  	err := c.dial(logger)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   182  	defer cancel()
   183  	return c.queryClient.GetName(ctx, &rpcquery.GetNameParam{Name: name})
   184  }
   185  
   186  func (c *Client) GetValidatorSet(logger *logging.Logger) (*rpcquery.ValidatorSet, error) {
   187  	err := c.dial(logger)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   192  	defer cancel()
   193  	return c.queryClient.GetValidatorSet(ctx, &rpcquery.GetValidatorSetParam{})
   194  }
   195  
   196  func (c *Client) GetProposal(hash []byte, logger *logging.Logger) (*payload.Ballot, error) {
   197  	err := c.dial(logger)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	return c.queryClient.GetProposal(context.Background(), &rpcquery.GetProposalParam{Hash: hash})
   202  }
   203  
   204  func (c *Client) ListProposals(proposed bool, logger *logging.Logger) ([]*rpcquery.ProposalResult, error) {
   205  	err := c.dial(logger)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	stream, err := c.queryClient.ListProposals(context.Background(), &rpcquery.ListProposalsParam{Proposed: proposed})
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	var ballots []*rpcquery.ProposalResult
   214  	ballot, err := stream.Recv()
   215  	for err == nil {
   216  		ballots = append(ballots, ballot)
   217  		ballot, err = stream.Recv()
   218  	}
   219  	if err == io.EOF {
   220  		return ballots, nil
   221  	}
   222  	return nil, err
   223  }
   224  
   225  func (c *Client) SignAndBroadcast(tx payload.Payload, logger *logging.Logger) (*exec.TxExecution, error) {
   226  	err := c.dial(logger)
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  	txEnv, err := c.SignTx(tx, logger)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  	return unifyErrors(c.BroadcastEnvelope(txEnv, logger))
   235  }
   236  
   237  func (c *Client) SignTx(tx payload.Payload, logger *logging.Logger) (*txs.Envelope, error) {
   238  	err := c.dial(logger)
   239  	if err != nil {
   240  		return nil, err
   241  	}
   242  	txEnv := txs.Enclose(c.chainID, tx)
   243  	if c.MempoolSigning {
   244  		logger.InfoMsg("Using mempool signing")
   245  		return txEnv, nil
   246  	}
   247  	inputs := tx.GetInputs()
   248  	signers := make([]acm.AddressableSigner, len(inputs))
   249  	for i, input := range inputs {
   250  		signers[i], err = keys.AddressableSigner(c.keyClient, input.Address)
   251  		if err != nil {
   252  			return nil, err
   253  		}
   254  	}
   255  	err = txEnv.Sign(signers...)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  	return txEnv, nil
   260  }
   261  
   262  // Creates a keypair using attached keys service
   263  func (c *Client) CreateKey(keyName, curveTypeString string, logger *logging.Logger) (*crypto.PublicKey, error) {
   264  	err := c.dial(logger)
   265  	if err != nil {
   266  		return nil, err
   267  	}
   268  	if c.keyClient == nil {
   269  		return nil, fmt.Errorf("could not create key pair since no keys service is attached, " +
   270  			"pass --keys flag")
   271  	}
   272  	curveType := crypto.CurveTypeEd25519
   273  	if curveTypeString != "" {
   274  		curveType, err = crypto.CurveTypeFromString(curveTypeString)
   275  		if err != nil {
   276  			return nil, err
   277  		}
   278  	}
   279  	address, err := c.keyClient.Generate(keyName, curveType)
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  	return c.keyClient.PublicKey(address)
   284  }
   285  
   286  // Broadcast payload for remote signing
   287  func (c *Client) Broadcast(tx payload.Payload, logger *logging.Logger) (*exec.TxExecution, error) {
   288  	err := c.dial(logger)
   289  	if err != nil {
   290  		return nil, err
   291  	}
   292  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   293  	defer cancel()
   294  	return unifyErrors(c.transactClient.BroadcastTxSync(ctx, &rpctransact.TxEnvelopeParam{Payload: tx.Any()}))
   295  }
   296  
   297  // Broadcast envelope - can be locally signed or remote signing will be attempted
   298  func (c *Client) BroadcastEnvelope(txEnv *txs.Envelope, logger *logging.Logger) (*exec.TxExecution, error) {
   299  	err := c.dial(logger)
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   304  	defer cancel()
   305  
   306  	return unifyErrors(c.transactClient.BroadcastTxSync(ctx, &rpctransact.TxEnvelopeParam{Envelope: txEnv}))
   307  }
   308  
   309  func (c *Client) ParseUint64(amount string) (uint64, error) {
   310  	if amount == "" {
   311  		return 0, nil
   312  	}
   313  	return strconv.ParseUint(amount, 10, 64)
   314  }
   315  
   316  // Simulated call
   317  
   318  type QueryArg struct {
   319  	Input   string
   320  	Address string
   321  	Data    string
   322  }
   323  
   324  func (c *Client) QueryContract(arg *QueryArg, logger *logging.Logger) (*exec.TxExecution, error) {
   325  	tx, err := c.Call(&CallArg{
   326  		Input:   arg.Input,
   327  		Address: arg.Address,
   328  		Data:    arg.Data,
   329  	}, logger)
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   334  	defer cancel()
   335  	return unifyErrors(c.transactClient.CallTxSim(ctx, tx))
   336  }
   337  
   338  // Transaction types
   339  
   340  type GovArg struct {
   341  	Input       string
   342  	Native      string
   343  	Power       string
   344  	Sequence    string
   345  	Permissions []string
   346  	Roles       []string
   347  	Address     string
   348  	PublicKey   string
   349  }
   350  
   351  func (c *Client) UpdateAccount(arg *GovArg, logger *logging.Logger) (*payload.GovTx, error) {
   352  	logger.InfoMsg("GovTx", "account", arg)
   353  	err := c.dial(logger)
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  	input, err := c.TxInput(arg.Input, arg.Native, arg.Sequence, true, logger)
   358  	if err != nil {
   359  		return nil, err
   360  	}
   361  	update := &spec.TemplateAccount{
   362  		Permissions: arg.Permissions,
   363  		Roles:       arg.Roles,
   364  	}
   365  	if arg.Address != "" {
   366  		addr, err := c.ParseAddress(arg.Address, logger)
   367  		if err != nil {
   368  			return nil, fmt.Errorf("could not parse address: %v", err)
   369  		}
   370  		update.Address = &addr
   371  	}
   372  	if arg.PublicKey != "" {
   373  		pubKey, err := PublicKeyFromString(arg.PublicKey)
   374  		if err != nil {
   375  			return nil, fmt.Errorf("could not parse publicKey: %v", err)
   376  		}
   377  		update.PublicKey = pubKey
   378  	} else {
   379  		// Attempt to get public key from connected key client
   380  		if arg.Address != "" {
   381  			// Try key client
   382  			pubKey, err := c.PublicKeyFromAddress(update.Address)
   383  			if err != nil {
   384  				logger.InfoMsg("did not get public key", "address", *update.Address)
   385  			} else {
   386  				update.PublicKey = pubKey
   387  			}
   388  			// We can still proceed with just address set
   389  		} else {
   390  			return nil, fmt.Errorf("neither target address or public key were provided")
   391  		}
   392  	}
   393  
   394  	_, err = permission.PermFlagFromStringList(arg.Permissions)
   395  	if err != nil {
   396  		return nil, fmt.Errorf("could not parse UpdateAccount permissions: %v", err)
   397  	}
   398  
   399  	if arg.Native != "" {
   400  		native, err := c.ParseUint64(arg.Native)
   401  		if err != nil {
   402  			return nil, fmt.Errorf("could not parse native token amount: %v", err)
   403  		}
   404  		update.Amounts = update.Balances().Native(native)
   405  	}
   406  	if arg.Power != "" {
   407  		power, err := c.ParseUint64(arg.Power)
   408  		if err != nil {
   409  			return nil, fmt.Errorf("could not parse native token amount: %v", err)
   410  		}
   411  		update.Amounts = update.Balances().Power(power)
   412  	}
   413  	tx := &payload.GovTx{
   414  		Inputs:         []*payload.TxInput{input},
   415  		AccountUpdates: []*spec.TemplateAccount{update},
   416  	}
   417  	return tx, nil
   418  }
   419  
   420  func (c *Client) PublicKeyFromAddress(address *crypto.Address) (*crypto.PublicKey, error) {
   421  	if c.keyClient != nil {
   422  		return nil, fmt.Errorf("key client is not set")
   423  	}
   424  	pubKey, err := c.keyClient.PublicKey(*address)
   425  	if err != nil {
   426  		return nil, fmt.Errorf("could not retrieve public key from keys server: %v", err)
   427  	}
   428  	return pubKey, nil
   429  }
   430  
   431  func PublicKeyFromString(publicKey string) (*crypto.PublicKey, error) {
   432  	bs, err := hex.DecodeString(publicKey)
   433  	if err != nil {
   434  		return nil, fmt.Errorf("could not parse public key string %s as hex: %v", publicKey, err)
   435  	}
   436  	switch len(bs) {
   437  	case crypto.PublicKeyLength(crypto.CurveTypeEd25519):
   438  		return crypto.PublicKeyFromBytes(bs, crypto.CurveTypeEd25519)
   439  	case crypto.PublicKeyLength(crypto.CurveTypeSecp256k1):
   440  		return crypto.PublicKeyFromBytes(bs, crypto.CurveTypeSecp256k1)
   441  	default:
   442  		return nil, fmt.Errorf("public key string %s has byte length %d which is not the size of either "+
   443  			"ed25519 or uncompressed secp256k1 keys so cannot construct public key", publicKey, len(bs))
   444  	}
   445  }
   446  
   447  type CallArg struct {
   448  	Input    string
   449  	Amount   string
   450  	Sequence string
   451  	Address  string
   452  	Fee      string
   453  	Gas      string
   454  	Data     string
   455  	WASM     string
   456  	Metadata map[acmstate.CodeHash]string
   457  }
   458  
   459  func (c *Client) Call(arg *CallArg, logger *logging.Logger) (*payload.CallTx, error) {
   460  	logger.TraceMsg("CallTx",
   461  		"input", arg.Input,
   462  		"amount", arg.Amount,
   463  		"sequence", arg.Sequence,
   464  		"address", arg.Address,
   465  		"data", arg.Data,
   466  		"wasm", arg.WASM)
   467  	input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger)
   468  	if err != nil {
   469  		return nil, err
   470  	}
   471  	var contractAddress *crypto.Address
   472  	if arg.Address != "" {
   473  		address, err := crypto.AddressFromHexString(arg.Address)
   474  		if err != nil {
   475  			return nil, err
   476  		}
   477  		contractAddress = &address
   478  	}
   479  
   480  	fee, err := c.ParseUint64(arg.Fee)
   481  	if err != nil {
   482  		return nil, err
   483  	}
   484  	gas, err := c.ParseUint64(arg.Gas)
   485  	if err != nil {
   486  		return nil, err
   487  	}
   488  	code, err := hex.DecodeString(arg.Data)
   489  	if err != nil {
   490  		return nil, err
   491  	}
   492  
   493  	wasm, err := hex.DecodeString(arg.WASM)
   494  	if err != nil {
   495  		return nil, err
   496  	}
   497  
   498  	metas := make([]*payload.ContractMeta, 0)
   499  	for codehash, metadata := range arg.Metadata {
   500  		metas = append(metas, &payload.ContractMeta{
   501  			CodeHash: codehash.Bytes(),
   502  			Meta:     metadata,
   503  		})
   504  	}
   505  
   506  	tx := &payload.CallTx{
   507  		Input:        input,
   508  		Address:      contractAddress,
   509  		Data:         code,
   510  		WASM:         wasm,
   511  		Fee:          fee,
   512  		GasLimit:     gas,
   513  		ContractMeta: metas,
   514  	}
   515  
   516  	return tx, nil
   517  }
   518  
   519  type SendArg struct {
   520  	Input    string
   521  	Amount   string
   522  	Sequence string
   523  	Output   string
   524  }
   525  
   526  func (c *Client) Send(arg *SendArg, logger *logging.Logger) (*payload.SendTx, error) {
   527  	logger.InfoMsg("SendTx", "send", arg)
   528  	input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger)
   529  	if err != nil {
   530  		return nil, err
   531  	}
   532  	outputAddress, err := c.ParseAddress(arg.Output, logger)
   533  	if err != nil {
   534  		return nil, err
   535  	}
   536  	tx := &payload.SendTx{
   537  		Inputs: []*payload.TxInput{input},
   538  		Outputs: []*payload.TxOutput{{
   539  			Address: outputAddress,
   540  			Amount:  input.Amount,
   541  		}},
   542  	}
   543  	return tx, nil
   544  }
   545  
   546  type BondArg struct {
   547  	Input    string
   548  	Amount   string
   549  	Sequence string
   550  }
   551  
   552  func (c *Client) Bond(arg *BondArg, logger *logging.Logger) (*payload.BondTx, error) {
   553  	logger.InfoMsg("BondTx", "account", arg)
   554  	err := c.dial(logger)
   555  	if err != nil {
   556  		return nil, err
   557  	}
   558  	input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger)
   559  	if err != nil {
   560  		return nil, err
   561  	}
   562  	return &payload.BondTx{
   563  		Input: input,
   564  	}, nil
   565  }
   566  
   567  type UnbondArg struct {
   568  	Output   string
   569  	Amount   string
   570  	Sequence string
   571  }
   572  
   573  func (c *Client) Unbond(arg *UnbondArg, logger *logging.Logger) (*payload.UnbondTx, error) {
   574  	logger.InfoMsg("UnbondTx", "account", arg)
   575  	if err := c.dial(logger); err != nil {
   576  		return nil, err
   577  	}
   578  	input, err := c.TxInput(arg.Output, arg.Amount, arg.Sequence, true, logger)
   579  	if err != nil {
   580  		return nil, err
   581  	}
   582  
   583  	tx := payload.NewUnbondTx(input.Address, input.Amount)
   584  	tx.Input = input
   585  
   586  	return tx, nil
   587  }
   588  
   589  type NameArg struct {
   590  	Input    string
   591  	Amount   string
   592  	Sequence string
   593  	Name     string
   594  	Data     string
   595  	Fee      string
   596  }
   597  
   598  func (c *Client) Name(arg *NameArg, logger *logging.Logger) (*payload.NameTx, error) {
   599  	logger.InfoMsg("NameTx", "name", arg)
   600  	input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger)
   601  	if err != nil {
   602  		return nil, err
   603  	}
   604  	fee, err := c.ParseUint64(arg.Fee)
   605  	if err != nil {
   606  		return nil, err
   607  	}
   608  	tx := &payload.NameTx{
   609  		Input: input,
   610  		Name:  arg.Name,
   611  		Data:  arg.Data,
   612  		Fee:   fee,
   613  	}
   614  	return tx, nil
   615  }
   616  
   617  type PermArg struct {
   618  	Input      string
   619  	Sequence   string
   620  	Action     string
   621  	Target     string
   622  	Permission string
   623  	Value      string
   624  	Role       string
   625  }
   626  
   627  func (c *Client) Permissions(arg *PermArg, logger *logging.Logger) (*payload.PermsTx, error) {
   628  	logger.InfoMsg("PermsTx", "perm", arg)
   629  	input, err := c.TxInput(arg.Input, "", arg.Sequence, true, logger)
   630  	if err != nil {
   631  		return nil, err
   632  	}
   633  	action, err := permission.PermStringToFlag(arg.Action)
   634  	if err != nil {
   635  		return nil, err
   636  	}
   637  	permArgs := permission.PermArgs{
   638  		Action: action,
   639  	}
   640  	if arg.Target != "" {
   641  		target, err := c.ParseAddress(arg.Target, logger)
   642  		if err != nil {
   643  			return nil, err
   644  		}
   645  		permArgs.Target = &target
   646  	}
   647  	if arg.Value != "" {
   648  		var value bool
   649  		switch arg.Value {
   650  		case "true":
   651  			value = true
   652  		case "false":
   653  			value = false
   654  		default:
   655  			return nil, fmt.Errorf("did not recognise value %s as boolean, use 'true' or 'false'", arg.Value)
   656  		}
   657  		permArgs.Value = &value
   658  	}
   659  	if arg.Permission != "" {
   660  		perm, err := permission.PermStringToFlag(arg.Permission)
   661  		if err != nil {
   662  			return nil, err
   663  		}
   664  		permArgs.Permission = &perm
   665  	}
   666  
   667  	if arg.Role != "" {
   668  		permArgs.Role = &arg.Role
   669  	}
   670  
   671  	tx := &payload.PermsTx{
   672  		Input:    input,
   673  		PermArgs: permArgs,
   674  	}
   675  	return tx, nil
   676  }
   677  
   678  type IdentifyArg struct {
   679  	Input      string
   680  	NodeKey    string
   681  	Moniker    string
   682  	NetAddress string
   683  	Amount     string
   684  	Sequence   string
   685  }
   686  
   687  func (c *Client) Identify(arg *IdentifyArg, logger *logging.Logger) (*payload.IdentifyTx, error) {
   688  	logger.InfoMsg("IdentifyTx", "name", arg)
   689  	input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger)
   690  	if err != nil {
   691  		return nil, err
   692  	}
   693  
   694  	address, err := crypto.AddressFromHexString(arg.Input)
   695  	if err != nil {
   696  		return nil, err
   697  	}
   698  
   699  	signer, err := keys.AddressableSigner(c.keyClient, address)
   700  	if err != nil {
   701  		return nil, err
   702  	}
   703  
   704  	nodeKey, err := p2p.LoadNodeKey(arg.NodeKey)
   705  	if err != nil {
   706  		return nil, err
   707  	}
   708  
   709  	id, err := crypto.AddressFromHexString(string(nodeKey.ID()))
   710  	if err != nil {
   711  		return nil, err
   712  	}
   713  
   714  	node := &registry.NodeIdentity{
   715  		Moniker:            arg.Moniker,
   716  		NetworkAddress:     arg.NetAddress,
   717  		TendermintNodeID:   id,
   718  		ValidatorPublicKey: signer.GetPublicKey(),
   719  	}
   720  
   721  	return &payload.IdentifyTx{
   722  		Inputs: []*payload.TxInput{input},
   723  		Node:   node,
   724  	}, nil
   725  }
   726  
   727  func (c *Client) TxInput(inputString, amountString, sequenceString string, allowMempoolSigning bool, logger *logging.Logger) (*payload.TxInput, error) {
   728  	var err error
   729  	var inputAddress crypto.Address
   730  	if inputString != "" {
   731  		inputAddress, err = c.ParseAddress(inputString, logger)
   732  		if err != nil {
   733  			return nil, fmt.Errorf("TxInput(): could not obtain input address from '%s': %v", inputString, err)
   734  		}
   735  	}
   736  	var amount uint64
   737  	if amountString != "" {
   738  		amount, err = c.ParseUint64(amountString)
   739  		if err != nil {
   740  			return nil, err
   741  		}
   742  	}
   743  	var sequence uint64
   744  	sequence, err = c.getSequence(sequenceString, inputAddress, c.MempoolSigning && allowMempoolSigning, logger)
   745  	if err != nil {
   746  		return nil, err
   747  	}
   748  	return &payload.TxInput{
   749  		Address:  inputAddress,
   750  		Amount:   amount,
   751  		Sequence: sequence,
   752  	}, nil
   753  }
   754  
   755  func (c *Client) getSequence(sequence string, inputAddress crypto.Address, mempoolSigning bool, logger *logging.Logger) (uint64, error) {
   756  	err := c.dial(logger)
   757  	if err != nil {
   758  		return 0, err
   759  	}
   760  	if sequence == "" {
   761  		if mempoolSigning {
   762  			// Perform mempool signing
   763  			return 0, nil
   764  		}
   765  		// Get from chain
   766  		ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   767  		defer cancel()
   768  		acc, err := c.queryClient.GetAccount(ctx, &rpcquery.GetAccountParam{Address: inputAddress})
   769  		if err != nil {
   770  			return 0, err
   771  		}
   772  		return acc.Sequence + 1, nil
   773  	}
   774  	return c.ParseUint64(sequence)
   775  }
   776  
   777  func argMap(value interface{}) map[string]interface{} {
   778  	rv := reflect.ValueOf(value)
   779  	if rv.Kind() == reflect.Ptr {
   780  		rv = rv.Elem()
   781  	}
   782  	rt := rv.Type()
   783  	fields := make(map[string]interface{})
   784  	for i := 0; i < rv.NumField(); i++ {
   785  		if rv.Field(i).Kind() == reflect.String {
   786  			fields[rt.Field(i).Name] = rv.Field(i).String()
   787  		}
   788  	}
   789  	return fields
   790  }
   791  
   792  // In order to safely handle a TxExecution one must check the Exception field to account for committed transaction
   793  // (therefore having no error) that may have exceptional executions (therefore not having the normal return values)
   794  func unifyErrors(txe *exec.TxExecution, err error) (*exec.TxExecution, error) {
   795  	if err != nil {
   796  		return nil, err
   797  	}
   798  	return txe, txe.Exception.AsError()
   799  }