github.com/Finschia/finschia-sdk@v0.48.1/server/rosetta/converter_test.go (about) 1 package rosetta_test 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 "testing" 7 8 "github.com/Finschia/finschia-sdk/testutil/testdata" 9 "github.com/Finschia/finschia-sdk/types/tx/signing" 10 authtx "github.com/Finschia/finschia-sdk/x/auth/tx" 11 12 rosettatypes "github.com/coinbase/rosetta-sdk-go/types" 13 "github.com/stretchr/testify/suite" 14 15 abci "github.com/tendermint/tendermint/abci/types" 16 17 "github.com/Finschia/finschia-sdk/client" 18 "github.com/Finschia/finschia-sdk/codec" 19 codectypes "github.com/Finschia/finschia-sdk/codec/types" 20 "github.com/Finschia/finschia-sdk/server/rosetta" 21 crgerrs "github.com/Finschia/finschia-sdk/server/rosetta/lib/errors" 22 sdk "github.com/Finschia/finschia-sdk/types" 23 authsigning "github.com/Finschia/finschia-sdk/x/auth/signing" 24 bank "github.com/Finschia/finschia-sdk/x/bank/types" 25 ) 26 27 type ConverterTestSuite struct { 28 suite.Suite 29 30 c rosetta.Converter 31 unsignedTxBytes []byte 32 unsignedTx authsigning.Tx 33 34 ir codectypes.InterfaceRegistry 35 cdc *codec.ProtoCodec 36 txConf client.TxConfig 37 } 38 39 // generateMsgSend generate sample unsignedTxHex and pubKeyHex 40 func generateMsgSend() (unsignedTxHex []byte, pubKeyHex []byte) { 41 cdc, _ := rosetta.MakeCodec() 42 txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes) 43 44 _, fromPk, fromAddr := testdata.KeyTestPubAddr() 45 _, _, toAddr := testdata.KeyTestPubAddr() 46 47 sendMsg := bank.MsgSend{ 48 FromAddress: fromAddr.String(), 49 ToAddress: toAddr.String(), 50 Amount: sdk.NewCoins(sdk.NewInt64Coin("stake", 16)), 51 } 52 53 txBuilder := txConfig.NewTxBuilder() 54 err := txBuilder.SetMsgs(&sendMsg) 55 if err != nil { 56 return nil, nil 57 } 58 txBuilder.SetGasLimit(200000) 59 txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewInt64Coin("stake", 1))) 60 61 sigData := signing.SingleSignatureData{ 62 SignMode: signing.SignMode_SIGN_MODE_DIRECT, 63 Signature: nil, 64 } 65 sig := signing.SignatureV2{ 66 PubKey: fromPk, 67 Data: &sigData, 68 Sequence: 1, 69 } 70 err = txBuilder.SetSignatures(sig) 71 if err != nil { 72 return nil, nil 73 } 74 75 stdTx := txBuilder.GetTx() 76 unsignedTxHex, err = txConfig.TxEncoder()(stdTx) 77 if err != nil { 78 return nil, nil 79 } 80 81 return unsignedTxHex, fromPk.Bytes() 82 } 83 84 func (s *ConverterTestSuite) SetupTest() { 85 // create an unsigned tx 86 const unsignedTxHex = "0a8a010a87010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e6412670a2b6c696e6b3136773064766c61716e34727779706739757a36713878643778343434687568756d636370756e122b6c696e6b316c33757538657364636c6a3876706a72757737357535666a34773479746475396e6c6b6538721a0b0a057374616b651202313612640a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a210377365794209eab396f74316bb32ecb507c0e3788c14edf164f96b25cc4ef624112040a020801180112100a0a0a057374616b6512013110c09a0c1a00" 87 unsignedTxBytes, err := hex.DecodeString(unsignedTxHex) 88 s.Require().NoError(err) 89 s.unsignedTxBytes = unsignedTxBytes 90 // instantiate converter 91 cdc, ir := rosetta.MakeCodec() 92 txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes) 93 s.c = rosetta.NewConverter(cdc, ir, txConfig) 94 // add utils 95 s.ir = ir 96 s.cdc = cdc 97 s.txConf = txConfig 98 // add authsigning tx 99 sdkTx, err := txConfig.TxDecoder()(unsignedTxBytes) 100 s.Require().NoError(err) 101 builder, err := txConfig.WrapTxBuilder(sdkTx) 102 s.Require().NoError(err) 103 104 s.unsignedTx = builder.GetTx() 105 } 106 107 func (s *ConverterTestSuite) TestFromRosettaOpsToTxSuccess() { 108 addr1 := sdk.AccAddress("address1").String() 109 addr2 := sdk.AccAddress("address2").String() 110 111 msg1 := &bank.MsgSend{ 112 FromAddress: addr1, 113 ToAddress: addr2, 114 Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), 115 } 116 117 msg2 := &bank.MsgSend{ 118 FromAddress: addr2, 119 ToAddress: addr1, 120 Amount: sdk.NewCoins(sdk.NewInt64Coin("utxo", 10)), 121 } 122 123 ops, err := s.c.ToRosetta().Ops("", msg1) 124 s.Require().NoError(err) 125 126 ops2, err := s.c.ToRosetta().Ops("", msg2) 127 s.Require().NoError(err) 128 129 ops = append(ops, ops2...) 130 131 tx, err := s.c.ToSDK().UnsignedTx(ops) 132 s.Require().NoError(err) 133 134 getMsgs := tx.GetMsgs() 135 136 s.Require().Equal(2, len(getMsgs)) 137 138 s.Require().Equal(getMsgs[0], msg1) 139 s.Require().Equal(getMsgs[1], msg2) 140 } 141 142 func (s *ConverterTestSuite) TestFromRosettaOpsToTxErrors() { 143 s.Run("unrecognized op", func() { 144 op := &rosettatypes.Operation{ 145 Type: "non-existent", 146 } 147 148 _, err := s.c.ToSDK().UnsignedTx([]*rosettatypes.Operation{op}) 149 150 s.Require().ErrorIs(err, crgerrs.ErrBadArgument) 151 }) 152 153 s.Run("codec type but not sdk.Msg", func() { 154 op := &rosettatypes.Operation{ 155 Type: "cosmos.crypto.ed25519.PubKey", 156 } 157 158 _, err := s.c.ToSDK().UnsignedTx([]*rosettatypes.Operation{op}) 159 160 s.Require().ErrorIs(err, crgerrs.ErrBadArgument) 161 }) 162 } 163 164 func (s *ConverterTestSuite) TestMsgToMetaMetaToMsg() { 165 msg := &bank.MsgSend{ 166 FromAddress: "addr1", 167 ToAddress: "addr2", 168 Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), 169 } 170 msg.Route() 171 172 meta, err := s.c.ToRosetta().Meta(msg) 173 s.Require().NoError(err) 174 175 copyMsg := new(bank.MsgSend) 176 err = s.c.ToSDK().Msg(meta, copyMsg) 177 s.Require().NoError(err) 178 s.Require().Equal(msg, copyMsg) 179 } 180 181 func (s *ConverterTestSuite) TestSignedTx() { 182 s.Run("success", func() { 183 const payloadsJSON = `[{"hex_bytes":"82ccce81a3e4a7272249f0e25c3037a316ee2acce76eb0c25db00ef6634a4d57303b2420edfdb4c9a635ad8851fe5c7a9379b7bc2baadc7d74f7e76ac97459b5","public_key":{"curve_type":"secp256k1","hex_bytes":"0377365794209eab396f74316bb32ecb507c0e3788c14edf164f96b25cc4ef6241"},"signature_type":"ecdsa","signing_payload":{"account_identifier":{"address":"link16w0dvlaqn4rwypg9uz6q8xd7x444huhumccpun"},"address":"link16w0dvlaqn4rwypg9uz6q8xd7x444huhumccpun","hex_bytes":"ea43c4019ee3c888a7f99acb57513f708bb8915bc84e914cf4ecbd08ab2d9e51","signature_type":"ecdsa"}}]` 184 const expectedSignedTxHex = "0a8a010a87010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e6412670a2b6c696e6b3136773064766c61716e34727779706739757a36713878643778343434687568756d636370756e122b6c696e6b316c33757538657364636c6a3876706a72757737357535666a34773479746475396e6c6b6538721a0b0a057374616b651202313612640a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a210377365794209eab396f74316bb32ecb507c0e3788c14edf164f96b25cc4ef624112040a02087f180112100a0a0a057374616b6512013110c09a0c1a4082ccce81a3e4a7272249f0e25c3037a316ee2acce76eb0c25db00ef6634a4d57303b2420edfdb4c9a635ad8851fe5c7a9379b7bc2baadc7d74f7e76ac97459b5" 185 186 var payloads []*rosettatypes.Signature 187 s.Require().NoError(json.Unmarshal([]byte(payloadsJSON), &payloads)) 188 189 signedTx, err := s.c.ToSDK().SignedTx(s.unsignedTxBytes, payloads) 190 s.Require().NoError(err) 191 192 signedTxHex := hex.EncodeToString(signedTx) 193 194 s.Require().Equal(signedTxHex, expectedSignedTxHex) 195 }) 196 197 s.Run("signers data and signing payloads mismatch", func() { 198 _, err := s.c.ToSDK().SignedTx(s.unsignedTxBytes, nil) 199 s.Require().ErrorIs(err, crgerrs.ErrInvalidTransaction) 200 }) 201 } 202 203 func (s *ConverterTestSuite) TestOpsAndSigners() { 204 s.Run("success", func() { 205 addr1 := sdk.AccAddress("address1").String() 206 addr2 := sdk.AccAddress("address2").String() 207 208 msg := &bank.MsgSend{ 209 FromAddress: addr1, 210 ToAddress: addr2, 211 Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), 212 } 213 214 builder := s.txConf.NewTxBuilder() 215 s.Require().NoError(builder.SetMsgs(msg)) 216 217 sdkTx := builder.GetTx() 218 txBytes, err := s.txConf.TxEncoder()(sdkTx) 219 s.Require().NoError(err) 220 221 ops, signers, err := s.c.ToRosetta().OpsAndSigners(txBytes) 222 s.Require().NoError(err) 223 224 s.Require().Equal(len(ops), len(sdkTx.GetMsgs())*len(sdkTx.GetSigners()), "operation number mismatch") 225 226 s.Require().Equal(len(signers), len(sdkTx.GetSigners()), "signers number mismatch") 227 }) 228 } 229 230 func (s *ConverterTestSuite) TestBeginEndBlockAndHashToTxType() { 231 const deliverTxHex = "5229A67AA008B5C5F1A0AEA77D4DEBE146297A30AAEF01777AF10FAD62DD36AB" 232 233 deliverTxBytes, err := hex.DecodeString(deliverTxHex) 234 s.Require().NoError(err) 235 236 endBlockTxHex := s.c.ToRosetta().EndBlockTxHash(deliverTxBytes) 237 beginBlockTxHex := s.c.ToRosetta().BeginBlockTxHash(deliverTxBytes) 238 239 txType, hash := s.c.ToSDK().HashToTxType(deliverTxBytes) 240 241 s.Require().Equal(rosetta.DeliverTxTx, txType) 242 s.Require().Equal(deliverTxBytes, hash, "deliver tx hash should not change") 243 244 endBlockTxBytes, err := hex.DecodeString(endBlockTxHex) 245 s.Require().NoError(err) 246 247 txType, hash = s.c.ToSDK().HashToTxType(endBlockTxBytes) 248 249 s.Require().Equal(rosetta.EndBlockTx, txType) 250 s.Require().Equal(deliverTxBytes, hash, "end block tx hash should be equal to a block hash") 251 252 beginBlockTxBytes, err := hex.DecodeString(beginBlockTxHex) 253 s.Require().NoError(err) 254 255 txType, hash = s.c.ToSDK().HashToTxType(beginBlockTxBytes) 256 257 s.Require().Equal(rosetta.BeginBlockTx, txType) 258 s.Require().Equal(deliverTxBytes, hash, "begin block tx hash should be equal to a block hash") 259 260 txType, hash = s.c.ToSDK().HashToTxType([]byte("invalid")) 261 262 s.Require().Equal(rosetta.UnrecognizedTx, txType) 263 s.Require().Nil(hash) 264 265 txType, hash = s.c.ToSDK().HashToTxType(append([]byte{0x3}, deliverTxBytes...)) 266 s.Require().Equal(rosetta.UnrecognizedTx, txType) 267 s.Require().Nil(hash) 268 } 269 270 func (s *ConverterTestSuite) TestSigningComponents() { 271 s.Run("invalid metadata coins", func() { 272 _, _, err := s.c.ToRosetta().SigningComponents(nil, &rosetta.ConstructionMetadata{GasPrice: "invalid"}, nil) 273 s.Require().ErrorIs(err, crgerrs.ErrBadArgument) 274 }) 275 276 s.Run("length signers data does not match signers", func() { 277 _, _, err := s.c.ToRosetta().SigningComponents(s.unsignedTx, &rosetta.ConstructionMetadata{GasPrice: "10stake"}, nil) 278 s.Require().ErrorIs(err, crgerrs.ErrBadArgument) 279 }) 280 281 s.Run("length pub keys does not match signers", func() { 282 _, _, err := s.c.ToRosetta().SigningComponents( 283 s.unsignedTx, 284 &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ 285 { 286 AccountNumber: 0, 287 Sequence: 0, 288 }, 289 }}, 290 nil) 291 s.Require().ErrorIs(err, crgerrs.ErrBadArgument) 292 }) 293 294 s.Run("ros pub key is valid but not the one we expect", func() { 295 validButUnexpected, err := hex.DecodeString("030da9096a40eb1d6c25f1e26e9cbf8941fc84b8f4dc509c8df5e62a29ab8f2415") 296 s.Require().NoError(err) 297 298 _, _, err = s.c.ToRosetta().SigningComponents( 299 s.unsignedTx, 300 &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ 301 { 302 AccountNumber: 0, 303 Sequence: 0, 304 }, 305 }}, 306 []*rosettatypes.PublicKey{ 307 { 308 Bytes: validButUnexpected, 309 CurveType: rosettatypes.Secp256k1, 310 }, 311 }) 312 s.Require().ErrorIs(err, crgerrs.ErrBadArgument) 313 }) 314 315 s.Run("success", func() { 316 expectedPubKey, err := hex.DecodeString("0377365794209eab396f74316bb32ecb507c0e3788c14edf164f96b25cc4ef6241") 317 s.Require().NoError(err) 318 319 _, _, err = s.c.ToRosetta().SigningComponents( 320 s.unsignedTx, 321 &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ 322 { 323 AccountNumber: 0, 324 Sequence: 0, 325 }, 326 }}, 327 []*rosettatypes.PublicKey{ 328 { 329 Bytes: expectedPubKey, 330 CurveType: rosettatypes.Secp256k1, 331 }, 332 }) 333 s.Require().NoError(err) 334 }) 335 } 336 337 func (s *ConverterTestSuite) TestBalanceOps() { 338 s.Run("not a balance op", func() { 339 notBalanceOp := abci.Event{ 340 Type: "not-a-balance-op", 341 } 342 343 ops := s.c.ToRosetta().BalanceOps("", []abci.Event{notBalanceOp}) 344 s.Len(ops, 0, "expected no balance ops") 345 }) 346 347 s.Run("multiple balance ops from 2 multicoins event", func() { 348 subBalanceOp := bank.NewCoinSpentEvent( 349 sdk.AccAddress("test"), 350 sdk.NewCoins(sdk.NewInt64Coin("test", 10), sdk.NewInt64Coin("utxo", 10)), 351 ) 352 353 addBalanceOp := bank.NewCoinReceivedEvent( 354 sdk.AccAddress("test"), 355 sdk.NewCoins(sdk.NewInt64Coin("test", 10), sdk.NewInt64Coin("utxo", 10)), 356 ) 357 358 ops := s.c.ToRosetta().BalanceOps("", []abci.Event{(abci.Event)(subBalanceOp), (abci.Event)(addBalanceOp)}) 359 s.Len(ops, 4) 360 }) 361 362 s.Run("spec broken", func() { 363 s.Require().Panics(func() { 364 specBrokenSub := abci.Event{ 365 Type: bank.EventTypeCoinSpent, 366 } 367 _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) 368 }) 369 370 s.Require().Panics(func() { 371 specBrokenSub := abci.Event{ 372 Type: bank.EventTypeCoinBurn, 373 } 374 _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) 375 }) 376 377 s.Require().Panics(func() { 378 specBrokenSub := abci.Event{ 379 Type: bank.EventTypeCoinReceived, 380 } 381 _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) 382 }) 383 }) 384 } 385 386 func TestConverterTestSuite(t *testing.T) { 387 suite.Run(t, new(ConverterTestSuite)) 388 }