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 }