github.com/Finschia/finschia-sdk@v0.48.1/server/rosetta/converter.go (about) 1 package rosetta 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "reflect" 8 9 "github.com/btcsuite/btcd/btcec" 10 rosettatypes "github.com/coinbase/rosetta-sdk-go/types" 11 12 abci "github.com/tendermint/tendermint/abci/types" 13 14 "github.com/Finschia/ostracon/crypto" 15 ostcoretypes "github.com/Finschia/ostracon/rpc/core/types" 16 octypes "github.com/Finschia/ostracon/types" 17 18 sdkclient "github.com/Finschia/finschia-sdk/client" 19 "github.com/Finschia/finschia-sdk/codec" 20 codectypes "github.com/Finschia/finschia-sdk/codec/types" 21 "github.com/Finschia/finschia-sdk/crypto/keys/secp256k1" 22 cryptotypes "github.com/Finschia/finschia-sdk/crypto/types" 23 crgerrs "github.com/Finschia/finschia-sdk/server/rosetta/lib/errors" 24 crgtypes "github.com/Finschia/finschia-sdk/server/rosetta/lib/types" 25 sdk "github.com/Finschia/finschia-sdk/types" 26 "github.com/Finschia/finschia-sdk/types/tx/signing" 27 authsigning "github.com/Finschia/finschia-sdk/x/auth/signing" 28 auth "github.com/Finschia/finschia-sdk/x/auth/types" 29 banktypes "github.com/Finschia/finschia-sdk/x/bank/types" 30 ) 31 32 // Converter is a utility that can be used to convert 33 // back and forth from rosetta to sdk and tendermint types 34 // IMPORTANT NOTES: 35 // - IT SHOULD BE USED ONLY TO DEAL WITH THINGS 36 // IN A STATELESS WAY! IT SHOULD NEVER INTERACT DIRECTLY 37 // WITH TENDERMINT RPC AND COSMOS GRPC 38 // 39 // - IT SHOULD RETURN cosmos rosetta gateway error types! 40 type Converter interface { 41 // ToSDK exposes the methods that convert 42 // rosetta types to cosmos sdk and tendermint types 43 ToSDK() ToSDKConverter 44 // ToRosetta exposes the methods that convert 45 // sdk and tendermint types to rosetta types 46 ToRosetta() ToRosettaConverter 47 } 48 49 // ToRosettaConverter is an interface that exposes 50 // all the functions used to convert sdk and 51 // tendermint types to rosetta known types 52 type ToRosettaConverter interface { 53 // BlockResponse returns a block response given a result block 54 BlockResponse(block *ostcoretypes.ResultBlock) crgtypes.BlockResponse 55 // BeginBlockToTx converts the given begin block hash to rosetta transaction hash 56 BeginBlockTxHash(blockHash []byte) string 57 // EndBlockTxHash converts the given endblock hash to rosetta transaction hash 58 EndBlockTxHash(blockHash []byte) string 59 // Amounts converts sdk.Coins to rosetta.Amounts 60 Amounts(ownedCoins []sdk.Coin, availableCoins sdk.Coins) []*rosettatypes.Amount 61 // Ops converts an sdk.Msg to rosetta operations 62 Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, error) 63 // OpsAndSigners takes raw transaction bytes and returns rosetta operations and the expected signers 64 OpsAndSigners(txBytes []byte) (ops []*rosettatypes.Operation, signers []*rosettatypes.AccountIdentifier, err error) 65 // Meta converts an sdk.Msg to rosetta metadata 66 Meta(msg sdk.Msg) (meta map[string]interface{}, err error) 67 // SignerData returns account signing data from a queried any account 68 SignerData(anyAccount *codectypes.Any) (*SignerData, error) 69 // SigningComponents returns rosetta's components required to build a signable transaction 70 SigningComponents(tx authsigning.Tx, metadata *ConstructionMetadata, rosPubKeys []*rosettatypes.PublicKey) (txBytes []byte, payloadsToSign []*rosettatypes.SigningPayload, err error) 71 // Tx converts a tendermint transaction and tx result if provided to a rosetta tx 72 Tx(rawTx octypes.Tx, txResult *abci.ResponseDeliverTx) (*rosettatypes.Transaction, error) 73 // TxIdentifiers converts a tendermint tx to transaction identifiers 74 TxIdentifiers(txs []octypes.Tx) []*rosettatypes.TransactionIdentifier 75 // BalanceOps converts events to balance operations 76 BalanceOps(status string, events []abci.Event) []*rosettatypes.Operation 77 // SyncStatus converts a tendermint status to sync status 78 SyncStatus(status *ostcoretypes.ResultStatus) *rosettatypes.SyncStatus 79 // Peers converts tendermint peers to rosetta 80 Peers(peers []ostcoretypes.Peer) []*rosettatypes.Peer 81 } 82 83 // ToSDKConverter is an interface that exposes 84 // all the functions used to convert rosetta types 85 // to tendermint and sdk types 86 type ToSDKConverter interface { 87 // UnsignedTx converts rosetta operations to an unsigned cosmos sdk transactions 88 UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx, err error) 89 // SignedTx adds the provided signatures after decoding the unsigned transaction raw bytes 90 // and returns the signed tx bytes 91 SignedTx(txBytes []byte, signatures []*rosettatypes.Signature) (signedTxBytes []byte, err error) 92 // Msg converts metadata to an sdk message 93 Msg(meta map[string]interface{}, msg sdk.Msg) (err error) 94 // HashToTxType returns the transaction type (end block, begin block or deliver tx) 95 // and the real hash to query in order to get information 96 HashToTxType(hashBytes []byte) (txType TransactionType, realHash []byte) 97 // PubKey attempts to convert a rosetta public key to cosmos sdk one 98 PubKey(pk *rosettatypes.PublicKey) (cryptotypes.PubKey, error) 99 } 100 101 type converter struct { 102 newTxBuilder func() sdkclient.TxBuilder 103 txBuilderFromTx func(tx sdk.Tx) (sdkclient.TxBuilder, error) 104 txDecode sdk.TxDecoder 105 txEncode sdk.TxEncoder 106 bytesToSign func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error) 107 ir codectypes.InterfaceRegistry 108 cdc *codec.ProtoCodec 109 } 110 111 func NewConverter(cdc *codec.ProtoCodec, ir codectypes.InterfaceRegistry, cfg sdkclient.TxConfig) Converter { 112 return converter{ 113 newTxBuilder: cfg.NewTxBuilder, 114 txBuilderFromTx: cfg.WrapTxBuilder, 115 txDecode: cfg.TxDecoder(), 116 txEncode: cfg.TxEncoder(), 117 bytesToSign: func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error) { 118 bytesToSign, err := cfg.SignModeHandler().GetSignBytes(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, signerData, tx) 119 if err != nil { 120 return nil, err 121 } 122 123 return crypto.Sha256(bytesToSign), nil 124 }, 125 ir: ir, 126 cdc: cdc, 127 } 128 } 129 130 func (c converter) ToSDK() ToSDKConverter { 131 return c 132 } 133 134 func (c converter) ToRosetta() ToRosettaConverter { 135 return c 136 } 137 138 // OpsToUnsignedTx returns all the sdk.Msgs given the operations 139 func (c converter) UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx, err error) { 140 builder := c.newTxBuilder() 141 142 var msgs []sdk.Msg 143 144 for i := 0; i < len(ops); i++ { 145 op := ops[i] 146 147 protoMessage, err := c.ir.Resolve(op.Type) 148 if err != nil { 149 return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation not found: "+op.Type) 150 } 151 152 msg, ok := protoMessage.(sdk.Msg) 153 if !ok { 154 return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation is not a valid supported sdk.Msg: "+op.Type) 155 } 156 157 err = c.Msg(op.Metadata, msg) 158 if err != nil { 159 return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 160 } 161 162 // verify message correctness 163 if err = msg.ValidateBasic(); err != nil { 164 return nil, crgerrs.WrapError( 165 crgerrs.ErrBadArgument, 166 fmt.Sprintf("validation of operation at index %d failed: %s", op.OperationIdentifier.Index, err), 167 ) 168 } 169 signers := msg.GetSigners() 170 // check if there are enough signers 171 if len(signers) == 0 { 172 return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("operation at index %d got no signers", op.OperationIdentifier.Index)) 173 } 174 // append the msg 175 msgs = append(msgs, msg) 176 // if there's only one signer then simply continue 177 if len(signers) == 1 { 178 continue 179 } 180 // after we have got the msg, we need to verify if the message has multiple signers 181 // if it has got multiple signers, then we need to fetch all the related operations 182 // which involve the other signers of the msg, we expect to find them in order 183 // so if the msg is named "v1.test.Send" and it expects 3 signers, the next 3 operations 184 // must be with the same name "v1.test.Send" and contain the other signers 185 // then we can just skip their processing 186 for j := 0; j < len(signers)-1; j++ { 187 skipOp := ops[i+j] // get the next index 188 // verify that the operation is equal to the new one 189 if skipOp.Type != op.Type { 190 return nil, crgerrs.WrapError( 191 crgerrs.ErrBadArgument, 192 fmt.Sprintf("operation at index %d should have had type %s got: %s", i+j, op.Type, skipOp.Type), 193 ) 194 } 195 196 if !reflect.DeepEqual(op.Metadata, skipOp.Metadata) { 197 return nil, crgerrs.WrapError( 198 crgerrs.ErrBadArgument, 199 fmt.Sprintf("operation at index %d should have had metadata equal to %#v, got: %#v", i+j, op.Metadata, skipOp.Metadata)) 200 } 201 202 i++ // increase so we skip it 203 } 204 } 205 206 if err := builder.SetMsgs(msgs...); err != nil { 207 return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) 208 } 209 210 return builder.GetTx(), nil 211 } 212 213 // Msg unmarshals the rosetta metadata to the given sdk.Msg 214 func (c converter) Msg(meta map[string]interface{}, msg sdk.Msg) error { 215 metaBytes, err := json.Marshal(meta) 216 if err != nil { 217 return err 218 } 219 return c.cdc.UnmarshalJSON(metaBytes, msg) 220 } 221 222 func (c converter) Meta(msg sdk.Msg) (meta map[string]interface{}, err error) { 223 b, err := c.cdc.MarshalJSON(msg) 224 if err != nil { 225 return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 226 } 227 228 err = json.Unmarshal(b, &meta) 229 if err != nil { 230 return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 231 } 232 233 return 234 } 235 236 // Ops will create an operation for each msg signer 237 // with the message proto name as type, and the raw fields 238 // as metadata 239 func (c converter) Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, error) { 240 opName := sdk.MsgTypeURL(msg) 241 242 meta, err := c.Meta(msg) 243 if err != nil { 244 return nil, err 245 } 246 247 ops := make([]*rosettatypes.Operation, len(msg.GetSigners())) 248 for i, signer := range msg.GetSigners() { 249 op := &rosettatypes.Operation{ 250 Type: opName, 251 Status: &status, 252 Account: &rosettatypes.AccountIdentifier{Address: signer.String()}, 253 Metadata: meta, 254 } 255 256 ops[i] = op 257 } 258 259 return ops, nil 260 } 261 262 // Tx converts a tendermint raw transaction and its result (if provided) to a rosetta transaction 263 func (c converter) Tx(rawTx octypes.Tx, txResult *abci.ResponseDeliverTx) (*rosettatypes.Transaction, error) { 264 // decode tx 265 tx, err := c.txDecode(rawTx) 266 if err != nil { 267 return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 268 } 269 // get initial status, as per sdk design, if one msg fails 270 // the whole TX will be considered failing, so we can't have 271 // 1 msg being success and 1 msg being reverted 272 status := StatusTxSuccess 273 switch txResult { 274 // if nil, we're probably checking an unconfirmed tx 275 // or trying to build a new transaction, so status 276 // is not put inside 277 case nil: 278 status = "" 279 // set the status 280 default: 281 if txResult.Code != abci.CodeTypeOK { 282 status = StatusTxReverted 283 } 284 } 285 // get operations from msgs 286 msgs := tx.GetMsgs() 287 var rawTxOps []*rosettatypes.Operation 288 289 for _, msg := range msgs { 290 ops, err := c.Ops(status, msg) 291 if err != nil { 292 return nil, err 293 } 294 rawTxOps = append(rawTxOps, ops...) 295 } 296 297 // now get balance events from response deliver tx 298 var balanceOps []*rosettatypes.Operation 299 // tx result might be nil, in case we're querying an unconfirmed tx from the mempool 300 if txResult != nil { 301 balanceOps = c.BalanceOps(status, txResult.Events) 302 } 303 304 // now normalize indexes 305 totalOps := AddOperationIndexes(rawTxOps, balanceOps) 306 307 return &rosettatypes.Transaction{ 308 TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: fmt.Sprintf("%X", rawTx.Hash())}, 309 Operations: totalOps, 310 }, nil 311 } 312 313 func (c converter) BalanceOps(status string, events []abci.Event) []*rosettatypes.Operation { 314 var ops []*rosettatypes.Operation 315 316 for _, e := range events { 317 balanceOps, ok := sdkEventToBalanceOperations(status, e) 318 if !ok { 319 continue 320 } 321 ops = append(ops, balanceOps...) 322 } 323 324 return ops 325 } 326 327 // sdkEventToBalanceOperations converts an event to a rosetta balance operation 328 // it will panic if the event is malformed because it might mean the sdk spec 329 // has changed and rosetta needs to reflect those changes too. 330 // The balance operations are multiple, one for each denom. 331 func sdkEventToBalanceOperations(status string, event abci.Event) (operations []*rosettatypes.Operation, isBalanceEvent bool) { 332 var ( 333 accountIdentifier string 334 coinChange sdk.Coins 335 isSub bool 336 ) 337 338 switch event.Type { 339 default: 340 return nil, false 341 case banktypes.EventTypeCoinSpent: 342 spender := sdk.MustAccAddressFromBech32((string)(event.Attributes[0].Value)) 343 coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) 344 if err != nil { 345 panic(err) 346 } 347 348 isSub = true 349 coinChange = coins 350 accountIdentifier = spender.String() 351 352 case banktypes.EventTypeCoinReceived: 353 receiver := sdk.MustAccAddressFromBech32((string)(event.Attributes[0].Value)) 354 coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) 355 if err != nil { 356 panic(err) 357 } 358 359 isSub = false 360 coinChange = coins 361 accountIdentifier = receiver.String() 362 363 // rosetta does not have the concept of burning coins, so we need to mock 364 // the burn as a send to an address that cannot be resolved to anything 365 case banktypes.EventTypeCoinBurn: 366 coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) 367 if err != nil { 368 panic(err) 369 } 370 371 coinChange = coins 372 accountIdentifier = BurnerAddressIdentifier 373 } 374 375 operations = make([]*rosettatypes.Operation, len(coinChange)) 376 377 for i, coin := range coinChange { 378 379 value := coin.Amount.String() 380 // in case the event is a subtract balance one the rewrite value with 381 // the negative coin identifier 382 if isSub { 383 value = "-" + value 384 } 385 386 op := &rosettatypes.Operation{ 387 Type: event.Type, 388 Status: &status, 389 Account: &rosettatypes.AccountIdentifier{Address: accountIdentifier}, 390 Amount: &rosettatypes.Amount{ 391 Value: value, 392 Currency: &rosettatypes.Currency{ 393 Symbol: coin.Denom, 394 Decimals: 0, 395 }, 396 }, 397 } 398 399 operations[i] = op 400 } 401 return operations, true 402 } 403 404 // Amounts converts []sdk.Coin to rosetta amounts 405 func (c converter) Amounts(ownedCoins []sdk.Coin, availableCoins sdk.Coins) []*rosettatypes.Amount { 406 amounts := make([]*rosettatypes.Amount, len(availableCoins)) 407 ownedCoinsMap := make(map[string]sdk.Int, len(availableCoins)) 408 409 for _, ownedCoin := range ownedCoins { 410 ownedCoinsMap[ownedCoin.Denom] = ownedCoin.Amount 411 } 412 413 for i, coin := range availableCoins { 414 value, owned := ownedCoinsMap[coin.Denom] 415 if !owned { 416 amounts[i] = &rosettatypes.Amount{ 417 Value: sdk.NewInt(0).String(), 418 Currency: &rosettatypes.Currency{ 419 Symbol: coin.Denom, 420 }, 421 } 422 continue 423 } 424 amounts[i] = &rosettatypes.Amount{ 425 Value: value.String(), 426 Currency: &rosettatypes.Currency{ 427 Symbol: coin.Denom, 428 }, 429 } 430 } 431 432 return amounts 433 } 434 435 // AddOperationIndexes adds the indexes to operations adhering to specific rules: 436 // operations related to messages will be always before than the balance ones 437 func AddOperationIndexes(msgOps []*rosettatypes.Operation, balanceOps []*rosettatypes.Operation) (finalOps []*rosettatypes.Operation) { 438 lenMsgOps := len(msgOps) 439 lenBalanceOps := len(balanceOps) 440 finalOps = make([]*rosettatypes.Operation, 0, lenMsgOps+lenBalanceOps) 441 442 var currentIndex int64 443 // add indexes to msg ops 444 for _, op := range msgOps { 445 op.OperationIdentifier = &rosettatypes.OperationIdentifier{ 446 Index: currentIndex, 447 } 448 449 finalOps = append(finalOps, op) 450 currentIndex++ 451 } 452 453 // add indexes to balance ops 454 for _, op := range balanceOps { 455 op.OperationIdentifier = &rosettatypes.OperationIdentifier{ 456 Index: currentIndex, 457 } 458 459 finalOps = append(finalOps, op) 460 currentIndex++ 461 } 462 463 return finalOps 464 } 465 466 // EndBlockTxHash produces a mock endblock hash that rosetta can query 467 // for endblock operations, it also serves the purpose of representing 468 // part of the state changes happening at endblock level (balance ones) 469 func (c converter) EndBlockTxHash(hash []byte) string { 470 final := append([]byte{EndBlockHashStart}, hash...) 471 return fmt.Sprintf("%X", final) 472 } 473 474 // BeginBlockTxHash produces a mock beginblock hash that rosetta can query 475 // for beginblock operations, it also serves the purpose of representing 476 // part of the state changes happening at beginblock level (balance ones) 477 func (c converter) BeginBlockTxHash(hash []byte) string { 478 final := append([]byte{BeginBlockHashStart}, hash...) 479 return fmt.Sprintf("%X", final) 480 } 481 482 // HashToTxType takes the provided hash bytes from rosetta and discerns if they are 483 // a deliver tx type or endblock/begin block hash, returning the real hash afterwards 484 func (c converter) HashToTxType(hashBytes []byte) (txType TransactionType, realHash []byte) { 485 switch len(hashBytes) { 486 case DeliverTxSize: 487 return DeliverTxTx, hashBytes 488 489 case BeginEndBlockTxSize: 490 switch hashBytes[0] { 491 case BeginBlockHashStart: 492 return BeginBlockTx, hashBytes[1:] 493 case EndBlockHashStart: 494 return EndBlockTx, hashBytes[1:] 495 default: 496 return UnrecognizedTx, nil 497 } 498 499 default: 500 return UnrecognizedTx, nil 501 } 502 } 503 504 // StatusToSyncStatus converts a tendermint status to rosetta sync status 505 func (c converter) SyncStatus(status *ostcoretypes.ResultStatus) *rosettatypes.SyncStatus { 506 // determine sync status 507 stage := StatusPeerSynced 508 if status.SyncInfo.CatchingUp { 509 stage = StatusPeerSyncing 510 } 511 512 return &rosettatypes.SyncStatus{ 513 CurrentIndex: &status.SyncInfo.LatestBlockHeight, 514 TargetIndex: nil, // sync info does not allow us to get target height 515 Stage: &stage, 516 } 517 } 518 519 // TxIdentifiers converts a tendermint raw transactions into an array of rosetta tx identifiers 520 func (c converter) TxIdentifiers(txs []octypes.Tx) []*rosettatypes.TransactionIdentifier { 521 converted := make([]*rosettatypes.TransactionIdentifier, len(txs)) 522 for i, tx := range txs { 523 converted[i] = &rosettatypes.TransactionIdentifier{Hash: fmt.Sprintf("%X", tx.Hash())} 524 } 525 526 return converted 527 } 528 529 // tmResultBlockToRosettaBlockResponse converts a tendermint result block to block response 530 func (c converter) BlockResponse(block *ostcoretypes.ResultBlock) crgtypes.BlockResponse { 531 var parentBlock *rosettatypes.BlockIdentifier 532 533 switch block.Block.Height { 534 case 1: 535 parentBlock = &rosettatypes.BlockIdentifier{ 536 Index: 1, 537 Hash: fmt.Sprintf("%X", block.BlockID.Hash.Bytes()), 538 } 539 default: 540 parentBlock = &rosettatypes.BlockIdentifier{ 541 Index: block.Block.Height - 1, 542 Hash: fmt.Sprintf("%X", block.Block.LastBlockID.Hash.Bytes()), 543 } 544 } 545 return crgtypes.BlockResponse{ 546 Block: &rosettatypes.BlockIdentifier{ 547 Index: block.Block.Height, 548 Hash: block.Block.Hash().String(), 549 }, 550 ParentBlock: parentBlock, 551 MillisecondTimestamp: timeToMilliseconds(block.Block.Time), 552 TxCount: int64(len(block.Block.Txs)), 553 } 554 } 555 556 // Peers converts tm peers to rosetta peers 557 func (c converter) Peers(peers []ostcoretypes.Peer) []*rosettatypes.Peer { 558 converted := make([]*rosettatypes.Peer, len(peers)) 559 560 for i, peer := range peers { 561 converted[i] = &rosettatypes.Peer{ 562 PeerID: peer.NodeInfo.Moniker, 563 Metadata: map[string]interface{}{ 564 "addr": peer.NodeInfo.ListenAddr, 565 }, 566 } 567 } 568 569 return converted 570 } 571 572 // OpsAndSigners takes transactions bytes and returns the operation, is signed is true it will return 573 // the account identifiers which have signed the transaction 574 func (c converter) OpsAndSigners(txBytes []byte) (ops []*rosettatypes.Operation, signers []*rosettatypes.AccountIdentifier, err error) { 575 rosTx, err := c.ToRosetta().Tx(txBytes, nil) 576 if err != nil { 577 return nil, nil, err 578 } 579 ops = rosTx.Operations 580 581 // get the signers 582 sdkTx, err := c.txDecode(txBytes) 583 if err != nil { 584 return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 585 } 586 587 txBuilder, err := c.txBuilderFromTx(sdkTx) 588 if err != nil { 589 return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 590 } 591 592 for _, signer := range txBuilder.GetTx().GetSigners() { 593 signers = append(signers, &rosettatypes.AccountIdentifier{ 594 Address: signer.String(), 595 }) 596 } 597 598 return 599 } 600 601 func (c converter) SignedTx(txBytes []byte, signatures []*rosettatypes.Signature) (signedTxBytes []byte, err error) { 602 rawTx, err := c.txDecode(txBytes) 603 if err != nil { 604 return nil, err 605 } 606 607 txBuilder, err := c.txBuilderFromTx(rawTx) 608 if err != nil { 609 return nil, err 610 } 611 612 notSignedSigs, err := txBuilder.GetTx().GetSignaturesV2() // 613 if err != nil { 614 return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 615 } 616 617 if len(notSignedSigs) != len(signatures) { 618 return nil, crgerrs.WrapError( 619 crgerrs.ErrInvalidTransaction, 620 fmt.Sprintf("expected transaction to have signers data matching the provided signatures: %d <-> %d", len(notSignedSigs), len(signatures))) 621 } 622 623 signedSigs := make([]signing.SignatureV2, len(notSignedSigs)) 624 for i, signature := range signatures { 625 // TODO(fdymylja): here we should check that the public key matches... 626 signedSigs[i] = signing.SignatureV2{ 627 PubKey: notSignedSigs[i].PubKey, 628 Data: &signing.SingleSignatureData{ 629 SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, 630 Signature: signature.Bytes, 631 }, 632 Sequence: notSignedSigs[i].Sequence, 633 } 634 } 635 636 if err = txBuilder.SetSignatures(signedSigs...); err != nil { 637 return nil, err 638 } 639 640 txBytes, err = c.txEncode(txBuilder.GetTx()) 641 if err != nil { 642 return nil, err 643 } 644 645 return txBytes, nil 646 } 647 648 func (c converter) PubKey(pubKey *rosettatypes.PublicKey) (cryptotypes.PubKey, error) { 649 if pubKey.CurveType != "secp256k1" { 650 return nil, crgerrs.WrapError(crgerrs.ErrUnsupportedCurve, "only secp256k1 supported") 651 } 652 653 cmp, err := btcec.ParsePubKey(pubKey.Bytes, btcec.S256()) 654 if err != nil { 655 return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) 656 } 657 658 compressedPublicKey := make([]byte, secp256k1.PubKeySize) 659 copy(compressedPublicKey, cmp.SerializeCompressed()) 660 661 pk := &secp256k1.PubKey{Key: compressedPublicKey} 662 663 return pk, nil 664 } 665 666 // SigningComponents takes a sdk tx and construction metadata and returns signable components 667 func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMetadata, rosPubKeys []*rosettatypes.PublicKey) (txBytes []byte, payloadsToSign []*rosettatypes.SigningPayload, err error) { 668 // verify metadata correctness 669 feeAmount, err := sdk.ParseCoinsNormalized(metadata.GasPrice) 670 if err != nil { 671 return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) 672 } 673 674 signers := tx.GetSigners() 675 // assert the signers data provided in options are the same as the expected signing accounts 676 // and that the number of rosetta provided public keys equals the one of the signers 677 if len(metadata.SignersData) != len(signers) || len(signers) != len(rosPubKeys) { 678 return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "signers data and account identifiers mismatch") 679 } 680 681 // add transaction metadata 682 builder, err := c.txBuilderFromTx(tx) 683 if err != nil { 684 return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 685 } 686 builder.SetFeeAmount(feeAmount) 687 builder.SetGasLimit(metadata.GasLimit) 688 builder.SetMemo(metadata.Memo) 689 690 // build signatures 691 partialSignatures := make([]signing.SignatureV2, len(signers)) 692 payloadsToSign = make([]*rosettatypes.SigningPayload, len(signers)) 693 694 // pub key ordering matters, in a future release this check might be relaxed 695 for i, signer := range signers { 696 // assert that the provided public keys are correctly ordered 697 // by checking if the signer at index i matches the pubkey at index 698 pubKey, err := c.ToSDK().PubKey(rosPubKeys[0]) 699 if err != nil { 700 return nil, nil, err 701 } 702 if !bytes.Equal(pubKey.Address().Bytes(), signer.Bytes()) { 703 return nil, nil, crgerrs.WrapError( 704 crgerrs.ErrBadArgument, 705 fmt.Sprintf("public key at index %d does not match the expected transaction signer: %X <-> %X", i, rosPubKeys[i].Bytes, signer.Bytes()), 706 ) 707 } 708 709 // set the signer data 710 signerData := authsigning.SignerData{ 711 ChainID: metadata.ChainID, 712 AccountNumber: metadata.SignersData[i].AccountNumber, 713 Sequence: metadata.SignersData[i].Sequence, 714 } 715 716 // get signature bytes 717 signBytes, err := c.bytesToSign(tx, signerData) 718 if err != nil { 719 return nil, nil, crgerrs.WrapError(crgerrs.ErrUnknown, fmt.Sprintf("unable to sign tx: %s", err.Error())) 720 } 721 722 // set payload 723 payloadsToSign[i] = &rosettatypes.SigningPayload{ 724 AccountIdentifier: &rosettatypes.AccountIdentifier{Address: signer.String()}, 725 Bytes: signBytes, 726 SignatureType: rosettatypes.Ecdsa, 727 } 728 729 // set partial signature 730 partialSignatures[i] = signing.SignatureV2{ 731 PubKey: pubKey, 732 Data: &signing.SingleSignatureData{}, // needs to be set to empty otherwise the codec will cry 733 Sequence: metadata.SignersData[i].Sequence, 734 } 735 736 } 737 738 // now we set the partial signatures in the tx 739 // because we will need to decode the sequence 740 // information of each account in a stateless way 741 err = builder.SetSignatures(partialSignatures...) 742 if err != nil { 743 return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 744 } 745 746 // finally encode the tx 747 txBytes, err = c.txEncode(builder.GetTx()) 748 if err != nil { 749 return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 750 } 751 752 return txBytes, payloadsToSign, nil 753 } 754 755 // SignerData converts the given any account to signer data 756 func (c converter) SignerData(anyAccount *codectypes.Any) (*SignerData, error) { 757 var acc auth.AccountI 758 err := c.ir.UnpackAny(anyAccount, &acc) 759 if err != nil { 760 return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) 761 } 762 763 return &SignerData{ 764 AccountNumber: acc.GetAccountNumber(), 765 Sequence: acc.GetSequence(), 766 }, nil 767 }