github.com/eris-ltd/erisdb@v0.25.0/deploy/def/client.go (about)

     1  package def
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"strconv"
     8  	"time"
     9  
    10  	"reflect"
    11  
    12  	hex "github.com/tmthrgd/go-hex"
    13  
    14  	"github.com/hyperledger/burrow/acm"
    15  	"github.com/hyperledger/burrow/binary"
    16  	"github.com/hyperledger/burrow/crypto"
    17  	"github.com/hyperledger/burrow/execution/evm/abi"
    18  	"github.com/hyperledger/burrow/execution/exec"
    19  	"github.com/hyperledger/burrow/execution/names"
    20  	"github.com/hyperledger/burrow/genesis/spec"
    21  	"github.com/hyperledger/burrow/keys"
    22  	"github.com/hyperledger/burrow/logging"
    23  	"github.com/hyperledger/burrow/permission"
    24  	"github.com/hyperledger/burrow/rpc"
    25  	"github.com/hyperledger/burrow/rpc/rpcevents"
    26  	"github.com/hyperledger/burrow/rpc/rpcquery"
    27  	"github.com/hyperledger/burrow/rpc/rpctransact"
    28  	"github.com/hyperledger/burrow/txs"
    29  	"github.com/hyperledger/burrow/txs/payload"
    30  	"google.golang.org/grpc"
    31  )
    32  
    33  type Client struct {
    34  	MempoolSigning    bool
    35  	ChainAddress      string
    36  	KeysClientAddress string
    37  	// Memoised clients and info
    38  	chainID               string
    39  	timeout               time.Duration
    40  	transactClient        rpctransact.TransactClient
    41  	queryClient           rpcquery.QueryClient
    42  	executionEventsClient rpcevents.ExecutionEventsClient
    43  	keyClient             keys.KeyClient
    44  	AllSpecs              *abi.AbiSpec
    45  }
    46  
    47  func NewClient(chain, keysClientAddress string, mempoolSigning bool, timeout time.Duration) *Client {
    48  	client := Client{
    49  		ChainAddress:      chain,
    50  		MempoolSigning:    mempoolSigning,
    51  		KeysClientAddress: keysClientAddress,
    52  		timeout:           timeout,
    53  	}
    54  	return &client
    55  }
    56  
    57  // Connect GRPC clients using ChainURL
    58  func (c *Client) dial(logger *logging.Logger) error {
    59  	if c.transactClient == nil {
    60  		conn, err := grpc.Dial(c.ChainAddress, grpc.WithInsecure())
    61  		if err != nil {
    62  			return err
    63  		}
    64  		c.transactClient = rpctransact.NewTransactClient(conn)
    65  		c.queryClient = rpcquery.NewQueryClient(conn)
    66  		c.executionEventsClient = rpcevents.NewExecutionEventsClient(conn)
    67  		if c.KeysClientAddress == "" {
    68  			logger.InfoMsg("Using mempool signing since no keyClient set, pass --keys to sign locally or elsewhere")
    69  			c.MempoolSigning = true
    70  			c.keyClient, err = keys.NewRemoteKeyClient(c.ChainAddress, logger)
    71  		} else {
    72  			logger.InfoMsg("Using keys server", "server", c.KeysClientAddress)
    73  			c.keyClient, err = keys.NewRemoteKeyClient(c.KeysClientAddress, logger)
    74  		}
    75  
    76  		if err != nil {
    77  			return err
    78  		}
    79  		ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
    80  		defer cancel()
    81  
    82  		stat, err := c.queryClient.Status(ctx, &rpcquery.StatusParam{})
    83  		if err != nil {
    84  			return err
    85  		}
    86  		c.chainID = stat.ChainID
    87  	}
    88  	return nil
    89  }
    90  
    91  func (c *Client) Transact(logger *logging.Logger) (rpctransact.TransactClient, error) {
    92  	err := c.dial(logger)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	return c.transactClient, err
    97  }
    98  
    99  func (c *Client) Query(logger *logging.Logger) (rpcquery.QueryClient, error) {
   100  	err := c.dial(logger)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	return c.queryClient, nil
   105  }
   106  
   107  func (c *Client) Events(logger *logging.Logger) (rpcevents.ExecutionEventsClient, error) {
   108  	err := c.dial(logger)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	return c.executionEventsClient, nil
   113  }
   114  
   115  func (c *Client) Status(logger *logging.Logger) (*rpc.ResultStatus, error) {
   116  	err := c.dial(logger)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   121  	defer cancel()
   122  	return c.queryClient.Status(ctx, &rpcquery.StatusParam{})
   123  }
   124  
   125  func (c *Client) GetKeyAddress(key string, logger *logging.Logger) (crypto.Address, error) {
   126  	address, err := crypto.AddressFromHexString(key)
   127  	if err == nil {
   128  		return address, nil
   129  	}
   130  	err = c.dial(logger)
   131  	if err != nil {
   132  		return crypto.Address{}, err
   133  	}
   134  	return c.keyClient.GetAddressForKeyName(key)
   135  }
   136  
   137  func (c *Client) GetAccount(address crypto.Address) (*acm.Account, error) {
   138  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   139  	defer cancel()
   140  	return c.queryClient.GetAccount(ctx, &rpcquery.GetAccountParam{Address: address})
   141  }
   142  
   143  func (c *Client) GetStorage(address crypto.Address, key binary.Word256) (binary.Word256, error) {
   144  	val, err := c.queryClient.GetStorage(context.Background(), &rpcquery.GetStorageParam{Address: address, Key: key})
   145  	if err != nil {
   146  		return binary.Word256{}, err
   147  	}
   148  	return val.Value, err
   149  }
   150  
   151  func (c *Client) GetName(name string, logger *logging.Logger) (*names.Entry, error) {
   152  	err := c.dial(logger)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   157  	defer cancel()
   158  	return c.queryClient.GetName(ctx, &rpcquery.GetNameParam{Name: name})
   159  }
   160  
   161  func (c *Client) GetValidatorSet(logger *logging.Logger) (*rpcquery.ValidatorSet, error) {
   162  	err := c.dial(logger)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   167  	defer cancel()
   168  	return c.queryClient.GetValidatorSet(ctx, &rpcquery.GetValidatorSetParam{})
   169  }
   170  
   171  func (c *Client) GetProposal(hash []byte, logger *logging.Logger) (*payload.Ballot, error) {
   172  	err := c.dial(logger)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	return c.queryClient.GetProposal(context.Background(), &rpcquery.GetProposalParam{Hash: hash})
   177  }
   178  
   179  func (c *Client) ListProposals(proposed bool, logger *logging.Logger) ([]*rpcquery.ProposalResult, error) {
   180  	err := c.dial(logger)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	stream, err := c.queryClient.ListProposals(context.Background(), &rpcquery.ListProposalsParam{Proposed: proposed})
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	var ballots []*rpcquery.ProposalResult
   189  	ballot, err := stream.Recv()
   190  	for err == nil {
   191  		ballots = append(ballots, ballot)
   192  		ballot, err = stream.Recv()
   193  	}
   194  	if err == io.EOF {
   195  		return ballots, nil
   196  	}
   197  	return nil, err
   198  }
   199  
   200  func (c *Client) SignAndBroadcast(tx payload.Payload, logger *logging.Logger) (*exec.TxExecution, error) {
   201  	err := c.dial(logger)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	txEnv, err := c.SignTx(tx, logger)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	return c.BroadcastEnvelope(txEnv, logger)
   210  }
   211  
   212  func (c *Client) SignTx(tx payload.Payload, logger *logging.Logger) (*txs.Envelope, error) {
   213  	err := c.dial(logger)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  	txEnv := txs.Enclose(c.chainID, tx)
   218  	if c.MempoolSigning {
   219  		logger.InfoMsg("Using mempool signing")
   220  		return txEnv, nil
   221  	}
   222  	inputs := tx.GetInputs()
   223  	signers := make([]acm.AddressableSigner, len(inputs))
   224  	for i, input := range inputs {
   225  		signers[i], err = keys.AddressableSigner(c.keyClient, input.Address)
   226  		if err != nil {
   227  			return nil, err
   228  		}
   229  	}
   230  	err = txEnv.Sign(signers...)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  	return txEnv, nil
   235  }
   236  
   237  // Creates a keypair using attached keys service
   238  func (c *Client) CreateKey(keyName, curveTypeString string, logger *logging.Logger) (crypto.PublicKey, error) {
   239  	err := c.dial(logger)
   240  	if err != nil {
   241  		return crypto.PublicKey{}, err
   242  	}
   243  	if c.keyClient == nil {
   244  		return crypto.PublicKey{}, fmt.Errorf("could not create key pair since no keys service is attached, " +
   245  			"pass --keys flag")
   246  	}
   247  	curveType := crypto.CurveTypeEd25519
   248  	if curveTypeString != "" {
   249  		curveType, err = crypto.CurveTypeFromString(curveTypeString)
   250  		if err != nil {
   251  			return crypto.PublicKey{}, err
   252  		}
   253  	}
   254  	address, err := c.keyClient.Generate(keyName, curveType)
   255  	if err != nil {
   256  		return crypto.PublicKey{}, err
   257  	}
   258  	return c.keyClient.PublicKey(address)
   259  }
   260  
   261  // Broadcast payload for remote signing
   262  func (c *Client) Broadcast(tx payload.Payload, logger *logging.Logger) (*exec.TxExecution, error) {
   263  	err := c.dial(logger)
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   268  	defer cancel()
   269  	return c.transactClient.BroadcastTxSync(ctx, &rpctransact.TxEnvelopeParam{Payload: tx.Any()})
   270  }
   271  
   272  // Broadcast envelope - can be locally signed or remote signing will be attempted
   273  func (c *Client) BroadcastEnvelope(txEnv *txs.Envelope, logger *logging.Logger) (*exec.TxExecution, error) {
   274  	err := c.dial(logger)
   275  	if err != nil {
   276  		return nil, err
   277  	}
   278  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   279  	defer cancel()
   280  
   281  	return c.transactClient.BroadcastTxSync(ctx, &rpctransact.TxEnvelopeParam{Envelope: txEnv})
   282  }
   283  
   284  func (c *Client) ParseUint64(amount string) (uint64, error) {
   285  	if amount == "" {
   286  		return 0, nil
   287  	}
   288  	return strconv.ParseUint(amount, 10, 64)
   289  }
   290  
   291  // Simulated call
   292  
   293  type QueryArg struct {
   294  	Input   string
   295  	Address string
   296  	Data    string
   297  }
   298  
   299  func (c *Client) QueryContract(arg *QueryArg, logger *logging.Logger) (*exec.TxExecution, error) {
   300  	logger.InfoMsg("Query contract", "query", arg)
   301  	tx, err := c.Call(&CallArg{
   302  		Input:   arg.Input,
   303  		Address: arg.Address,
   304  		Data:    arg.Data,
   305  	}, logger)
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   310  	defer cancel()
   311  	return c.transactClient.CallTxSim(ctx, tx)
   312  }
   313  
   314  // Transaction types
   315  
   316  type GovArg struct {
   317  	Input       string
   318  	Native      string
   319  	Power       string
   320  	Sequence    string
   321  	Permissions []string
   322  	Roles       []string
   323  	Address     string
   324  	PublicKey   string
   325  }
   326  
   327  func (c *Client) UpdateAccount(arg *GovArg, logger *logging.Logger) (*payload.GovTx, error) {
   328  	logger.InfoMsg("GovTx", "account", arg)
   329  	err := c.dial(logger)
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  	input, err := c.TxInput(arg.Input, arg.Native, arg.Sequence, true, logger)
   334  	if err != nil {
   335  		return nil, err
   336  	}
   337  	update := &spec.TemplateAccount{
   338  		Permissions: arg.Permissions,
   339  		Roles:       arg.Permissions,
   340  	}
   341  	if arg.Address != "" {
   342  		address, err := c.GetKeyAddress(arg.Address, logger)
   343  		if err != nil {
   344  			return nil, fmt.Errorf("could not parse UpdateAccoount Address: %v", err)
   345  		}
   346  		update.Address = &address
   347  	}
   348  	if arg.PublicKey != "" {
   349  		publicKey, err := publicKeyFromString(arg.PublicKey)
   350  		if err != nil {
   351  			return nil, fmt.Errorf("could not parse UpdateAccount PublicKey: %v", err)
   352  		}
   353  		update.PublicKey = &publicKey
   354  		// Update arg for variable usage
   355  		arg.Address = publicKey.GetAddress().String()
   356  	}
   357  	if update.PublicKey == nil {
   358  		// Attempt to get public key from connected key client
   359  		if update.Address != nil {
   360  			// Try key client
   361  			if c.keyClient != nil {
   362  				publicKey, err := c.keyClient.PublicKey(*update.Address)
   363  				if err != nil {
   364  					logger.InfoMsg("Could not retrieve public key from keys server", "address", *update.Address)
   365  				} else {
   366  					update.PublicKey = &publicKey
   367  				}
   368  			}
   369  			// We can still proceed with just address set
   370  		} else {
   371  			return nil, fmt.Errorf("neither target address or public key were provided to govern account")
   372  		}
   373  	}
   374  	_, err = permission.PermFlagFromStringList(arg.Permissions)
   375  	if err != nil {
   376  		return nil, fmt.Errorf("could not parse UpdateAccoutn permissions: %v", err)
   377  	}
   378  
   379  	if arg.Native != "" {
   380  		native, err := c.ParseUint64(arg.Native)
   381  		if err != nil {
   382  			return nil, fmt.Errorf("could not parse native token amount: %v", err)
   383  		}
   384  		update.Amounts = update.Balances().Native(native)
   385  	}
   386  	if arg.Power != "" {
   387  		power, err := c.ParseUint64(arg.Power)
   388  		if err != nil {
   389  			return nil, fmt.Errorf("could not parse native token amount: %v", err)
   390  		}
   391  		update.Amounts = update.Balances().Power(power)
   392  	}
   393  	tx := &payload.GovTx{
   394  		Inputs:         []*payload.TxInput{input},
   395  		AccountUpdates: []*spec.TemplateAccount{update},
   396  	}
   397  	return tx, nil
   398  }
   399  
   400  func publicKeyFromString(publicKey string) (crypto.PublicKey, error) {
   401  	bs, err := hex.DecodeString(publicKey)
   402  	if err != nil {
   403  		return crypto.PublicKey{}, fmt.Errorf("could not parse public key string %s as hex: %v", publicKey, err)
   404  	}
   405  	switch len(bs) {
   406  	case crypto.PublicKeyLength(crypto.CurveTypeEd25519):
   407  		return crypto.PublicKeyFromBytes(bs, crypto.CurveTypeEd25519)
   408  	case crypto.PublicKeyLength(crypto.CurveTypeSecp256k1):
   409  		return crypto.PublicKeyFromBytes(bs, crypto.CurveTypeSecp256k1)
   410  	default:
   411  		return crypto.PublicKey{}, fmt.Errorf("public key string %s has byte length %d which is not the size of either "+
   412  			"ed25519 or compressed secp256k1 keys so cannot construct public key", publicKey, len(bs))
   413  	}
   414  }
   415  
   416  type CallArg struct {
   417  	Input    string
   418  	Amount   string
   419  	Sequence string
   420  	Address  string
   421  	Fee      string
   422  	Gas      string
   423  	Data     string
   424  }
   425  
   426  func (c *Client) Call(arg *CallArg, logger *logging.Logger) (*payload.CallTx, error) {
   427  	logger.InfoMsg("CallTx", "call", arg)
   428  	input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger)
   429  	if err != nil {
   430  		return nil, err
   431  	}
   432  	var contractAddress *crypto.Address
   433  	if arg.Address != "" {
   434  		address, err := c.GetKeyAddress(arg.Address, logger)
   435  		if err != nil {
   436  			return nil, err
   437  		}
   438  		contractAddress = &address
   439  	}
   440  	fee, err := c.ParseUint64(arg.Fee)
   441  	if err != nil {
   442  		return nil, err
   443  	}
   444  	gas, err := c.ParseUint64(arg.Gas)
   445  	if err != nil {
   446  		return nil, err
   447  	}
   448  	code, err := hex.DecodeString(arg.Data)
   449  	if err != nil {
   450  		return nil, err
   451  	}
   452  	tx := &payload.CallTx{
   453  		Input:    input,
   454  		Address:  contractAddress,
   455  		Data:     code,
   456  		Fee:      fee,
   457  		GasLimit: gas,
   458  	}
   459  	return tx, nil
   460  }
   461  
   462  type SendArg struct {
   463  	Input    string
   464  	Amount   string
   465  	Sequence string
   466  	Output   string
   467  }
   468  
   469  func (c *Client) Send(arg *SendArg, logger *logging.Logger) (*payload.SendTx, error) {
   470  	logger.InfoMsg("SendTx", "send", arg)
   471  	input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger)
   472  	if err != nil {
   473  		return nil, err
   474  	}
   475  	outputAddress, err := c.GetKeyAddress(arg.Output, logger)
   476  	if err != nil {
   477  		return nil, err
   478  	}
   479  	tx := &payload.SendTx{
   480  		Inputs: []*payload.TxInput{input},
   481  		Outputs: []*payload.TxOutput{{
   482  			Address: outputAddress,
   483  			Amount:  input.Amount,
   484  		}},
   485  	}
   486  	return tx, nil
   487  }
   488  
   489  type NameArg struct {
   490  	Input    string
   491  	Amount   string
   492  	Sequence string
   493  	Name     string
   494  	Data     string
   495  	Fee      string
   496  }
   497  
   498  func (c *Client) Name(arg *NameArg, logger *logging.Logger) (*payload.NameTx, error) {
   499  	logger.InfoMsg("NameTx", "name", arg)
   500  	input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger)
   501  	if err != nil {
   502  		return nil, err
   503  	}
   504  	fee, err := c.ParseUint64(arg.Fee)
   505  	if err != nil {
   506  		return nil, err
   507  	}
   508  	tx := &payload.NameTx{
   509  		Input: input,
   510  		Name:  arg.Name,
   511  		Data:  arg.Data,
   512  		Fee:   fee,
   513  	}
   514  	return tx, nil
   515  }
   516  
   517  type PermArg struct {
   518  	Input      string
   519  	Sequence   string
   520  	Action     string
   521  	Target     string
   522  	Permission string
   523  	Value      string
   524  	Role       string
   525  }
   526  
   527  func (c *Client) Permissions(arg *PermArg, logger *logging.Logger) (*payload.PermsTx, error) {
   528  	logger.InfoMsg("PermsTx", "perm", arg)
   529  	input, err := c.TxInput(arg.Input, "", arg.Sequence, true, logger)
   530  	if err != nil {
   531  		return nil, err
   532  	}
   533  	action, err := permission.PermStringToFlag(arg.Action)
   534  	if err != nil {
   535  		return nil, err
   536  	}
   537  	permArgs := permission.PermArgs{
   538  		Action: action,
   539  	}
   540  	if arg.Target != "" {
   541  		target, err := c.GetKeyAddress(arg.Target, logger)
   542  		if err != nil {
   543  			return nil, err
   544  		}
   545  		permArgs.Target = &target
   546  	}
   547  	if arg.Value != "" {
   548  		var value bool
   549  		switch arg.Value {
   550  		case "true":
   551  			value = true
   552  		case "false":
   553  			value = false
   554  		default:
   555  			return nil, fmt.Errorf("did not recognise value %s as boolean, use 'true' or 'false'", arg.Value)
   556  		}
   557  		permArgs.Value = &value
   558  	}
   559  	if arg.Permission != "" {
   560  		perm, err := permission.PermStringToFlag(arg.Permission)
   561  		if err != nil {
   562  			return nil, err
   563  		}
   564  		permArgs.Permission = &perm
   565  	}
   566  
   567  	if arg.Role != "" {
   568  		permArgs.Role = &arg.Role
   569  	}
   570  
   571  	tx := &payload.PermsTx{
   572  		Input:    input,
   573  		PermArgs: permArgs,
   574  	}
   575  	return tx, nil
   576  }
   577  
   578  func (c *Client) TxInput(inputString, amountString, sequenceString string, allowMempoolSigning bool, logger *logging.Logger) (*payload.TxInput, error) {
   579  	var err error
   580  	var inputAddress crypto.Address
   581  	if inputString != "" {
   582  		inputAddress, err = c.GetKeyAddress(inputString, logger)
   583  		if err != nil {
   584  			return nil, fmt.Errorf("TxInput(): could not obtain input address from '%s': %v", inputString, err)
   585  		}
   586  	}
   587  	var amount uint64
   588  	if amountString != "" {
   589  		amount, err = c.ParseUint64(amountString)
   590  	}
   591  	var sequence uint64
   592  	sequence, err = c.getSequence(sequenceString, inputAddress, c.MempoolSigning && allowMempoolSigning, logger)
   593  	if err != nil {
   594  		return nil, err
   595  	}
   596  	return &payload.TxInput{
   597  		Address:  inputAddress,
   598  		Amount:   amount,
   599  		Sequence: sequence,
   600  	}, nil
   601  }
   602  
   603  func (c *Client) getSequence(sequence string, inputAddress crypto.Address, mempoolSigning bool, logger *logging.Logger) (uint64, error) {
   604  	err := c.dial(logger)
   605  	if err != nil {
   606  		return 0, err
   607  	}
   608  	if sequence == "" {
   609  		if mempoolSigning {
   610  			// Perform mempool signing
   611  			return 0, nil
   612  		}
   613  		// Get from chain
   614  		ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
   615  		defer cancel()
   616  		acc, err := c.queryClient.GetAccount(ctx, &rpcquery.GetAccountParam{Address: inputAddress})
   617  		if err != nil {
   618  			return 0, err
   619  		}
   620  		return acc.Sequence + 1, nil
   621  	}
   622  	return c.ParseUint64(sequence)
   623  }
   624  
   625  func argMap(value interface{}) map[string]interface{} {
   626  	rv := reflect.ValueOf(value)
   627  	if rv.Kind() == reflect.Ptr {
   628  		rv = rv.Elem()
   629  	}
   630  	rt := rv.Type()
   631  	fields := make(map[string]interface{})
   632  	for i := 0; i < rv.NumField(); i++ {
   633  		if rv.Field(i).Kind() == reflect.String {
   634  			fields[rt.Field(i).Name] = rv.Field(i).String()
   635  		}
   636  	}
   637  	return fields
   638  }