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  }