Proto Tx with Any (#7276)

* WIP on protobuf keys

* Use Type() and Bytes() in sr25519 pub key Equals

* Add tests

* Add few more tests

* Update other pub/priv key types Equals

* Fix PrivKey's Sign method

* Rename variables in tests

* Fix infinite recursive calls

* Use tm ed25519 keys

* Add Sign and VerifySignature tests

* Remove ed25519 and sr25519 references

* proto linting

* Add proto crypto file

* Implement some of the new multisig proto type methods

* Add tests for MultisigThresholdPubKey

* Add tests for pubkey pb/amino conversion functions

* Move crypto types.go and register new proto pubkeys

* Add missing pointer ref

* Address review comments

* panic in MultisigThresholdPubKey VerifySignature

* Use internal crypto.PubKey in multisig

* Add tests for MultisigThresholdPubKey VerifyMultisignature

* Only keep LegacyAminoMultisigThresholdPubKey and move to proto keys to v1

* Remove conversion functions and introduce internal PubKey type

* Override Amino marshaling for proto pubkeys

* Merge master

* Make proto-gen

* Start removal of old PubKeyMultisigThreshold references

* Fix tests

* Fix solomachine

* Fix ante handler tests

* Pull latest go-amino

* Remove ed25519

* Remove old secp256k1 PubKey and PrivKey

* Uncomment test case

* Fix linting issues

* More linting

* Revert tests keys values

* Add Amino overrides to proto keys

* Add pubkey test

* Fix tests

* Use threshold isntead of K

* Standardize Type

* Revert standardize types commit

* Fix build

* Fix lint

* Fix lint

* Add comment

* Register crypto.PubKey

* Add empty key in BuildSimTx

* Simplify proto names

* Unpack interfaces for signing desc

* Fix IBC tests?

* Format proto

* Use secp256k1 in ibc

* Fixed merge issues

* Uncomment tests

* Update x/ibc/testing/solomachine.go

* UnpackInterfaces for solomachine types

* Remove old multisig

* Add amino marshal for multisig

* Fix lint

* Correctly register amino

* One test left!

* Remove old struct

* Fix test

* Fix test

* Unpack into tmcrypto

* Remove old threshold pubkey tests

* Fix register amino

* Fix lint

* Use sdk crypto PubKey in multisig UnpackInterfaces

* Potential fix?

* Register LegacyAminoPubKey

* Register our own PubKey

* Register tmcrypto PubKey

* Register both PubKeys

* Register interfaces in test

* Refactor fiels

* Add comments

* Use anil's suggestion

* Add norace back

* Check nil

* Address comments

* FIx lint

* Add tests for solomachine unpack interfaces

* Fix query tx by hash

* Better name in amino register

* Display StdTx instead of proto Tx

* Remove useless check

Co-authored-by: Aaron Craelius <aaronc@users.noreply.github.com>
Co-authored-by: blushi <marie.gauthier63@gmail.com>
Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>
This commit is contained in:
Amaury Martiny
2020-09-21 16:48:28 +00:00
committed by GitHub
co-authored by Aaron Craelius blushi Alexander Bezobchuk colin axnér
parent 535510be1f
commit 7cd25abb87
42 changed files with 584 additions and 619 deletions
+24 -12
View File
@@ -47,19 +47,8 @@ func DecodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
return
}
txI, err := clientCtx.TxConfig.TxDecoder()(txBytes)
if rest.CheckBadRequestError(w, err) {
return
}
tx, ok := txI.(signing.Tx)
stdTx, ok := convertToStdTx(w, clientCtx, txBytes)
if !ok {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("%+v is not backwards compatible with %T", tx, authtypes.StdTx{}))
return
}
stdTx, err := clienttx.ConvertTxToStdTx(clientCtx.LegacyAmino, tx)
if rest.CheckBadRequestError(w, err) {
return
}
@@ -68,3 +57,26 @@ func DecodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
rest.PostProcessResponse(w, clientCtx, response)
}
}
// convertToStdTx converts tx proto binary bytes retrieved from Tendermint into
// a StdTx. Returns the StdTx, as well as a flag denoting if the function
// successfully converted or not.
func convertToStdTx(w http.ResponseWriter, clientCtx client.Context, txBytes []byte) (authtypes.StdTx, bool) {
txI, err := clientCtx.TxConfig.TxDecoder()(txBytes)
if rest.CheckBadRequestError(w, err) {
return authtypes.StdTx{}, false
}
tx, ok := txI.(signing.Tx)
if !ok {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("%+v is not backwards compatible with %T", tx, authtypes.StdTx{}))
return authtypes.StdTx{}, false
}
stdTx, err := clienttx.ConvertTxToStdTx(clientCtx.LegacyAmino, tx)
if rest.CheckBadRequestError(w, err) {
return authtypes.StdTx{}, false
}
return stdTx, true
}
+10 -2
View File
@@ -53,7 +53,7 @@ func QueryAccountRequestHandlerFn(storeName string, clientCtx client.Context) ht
}
}
// QueryTxsHandlerFn implements a REST handler that searches for transactions.
// QueryTxsRequestHandlerFn implements a REST handler that searches for transactions.
// Genesis transactions are returned if the height parameter is set to zero,
// otherwise the transactions are searched for by events.
func QueryTxsRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
@@ -128,11 +128,19 @@ func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
return
}
// We just unmarshalled from Tendermint, we take the proto Tx's raw
// bytes, and convert them into a StdTx to be displayed.
txBytes := output.Tx.Value
stdTx, ok := convertToStdTx(w, clientCtx, txBytes)
if !ok {
return
}
if output.Empty() {
rest.WriteErrorResponse(w, http.StatusNotFound, fmt.Sprintf("no transaction found with hash %s", hashHexStr))
}
rest.PostProcessResponseBare(w, clientCtx, output)
rest.PostProcessResponseBare(w, clientCtx, stdTx)
}
}
+69 -45
View File
@@ -1,25 +1,22 @@
// +build norace
package rest_test
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"strings"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
rest2 "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/types/rest"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
rest2 "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)
type IntegrationTestSuite struct {
@@ -33,7 +30,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := network.DefaultConfig()
cfg.NumValidators = 1
cfg.NumValidators = 2
s.cfg = cfg
s.network = network.New(s.T(), cfg)
@@ -109,11 +106,31 @@ func (s *IntegrationTestSuite) TestBroadcastTxRequest() {
s.Require().NotEmpty(txRes.TxHash)
}
func (s *IntegrationTestSuite) TestMultipleSyncBroadcastTxRequests() {
func (s *IntegrationTestSuite) TestQueryTxByHash() {
val0 := s.network.Validators[0]
txConfig := authtypes.StdTxConfig{Cdc: s.cfg.LegacyAmino}
// Create and broadcast a tx.
stdTx := s.createTestStdTx(val0, 1) // Validator's sequence starts at 1.
res, err := s.broadcastReq(stdTx, "block")
s.Require().NoError(err)
var txRes sdk.TxResponse
// NOTE: this uses amino explicitly, don't migrate it!
s.Require().NoError(s.cfg.LegacyAmino.UnmarshalJSON(res, &txRes))
// we just check for a non-empty TxHash here, the actual hash will depend on the underlying tx configuration
s.Require().NotEmpty(txRes.TxHash)
s.network.WaitForNextBlock()
// We now fetch the tx by has on the `/tx/{hash}` route.
txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs/%s", val0.APIAddress, txRes.TxHash))
s.Require().NoError(err)
// txJSON should contain the whole tx, we just make sure that our custom
// memo is there.
s.Require().True(strings.Contains(string(txJSON), stdTx.Memo))
}
func (s *IntegrationTestSuite) TestMultipleSyncBroadcastTxRequests() {
// First test transaction from validator should have sequence=1 (non-genesis tx)
testCases := []struct {
desc string
@@ -139,35 +156,8 @@ func (s *IntegrationTestSuite) TestMultipleSyncBroadcastTxRequests() {
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.desc), func() {
msg := &types.MsgSend{
val0.Address,
val0.Address,
sdk.Coins{sdk.NewInt64Coin("foo", 100)},
}
// prepare txBuilder with msg
txBuilder := txConfig.NewTxBuilder()
feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}
gasLimit := testdata.NewTestGasLimit()
txBuilder.SetMsgs(msg)
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
// setup txFactory
txFactory := tx.Factory{}
txFactory = txFactory.
WithChainID(val0.ClientCtx.ChainID).
WithKeybase(val0.ClientCtx.Keyring).
WithTxConfig(txConfig).
WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON).
WithSequence(tc.sequence)
// sign Tx (offline mode so we can manually set sequence number)
err := authclient.SignTx(txFactory, val0.ClientCtx, val0.Moniker, txBuilder, true)
s.Require().NoError(err)
// broadcast test with sync mode, as we want to run CheckTx to verify account sequence is correct
stdTx := txBuilder.GetTx().(authtypes.StdTx)
stdTx := s.createTestStdTx(s.network.Validators[0], tc.sequence)
res, err := s.broadcastReq(stdTx, "sync")
s.Require().NoError(err)
@@ -190,7 +180,41 @@ func (s *IntegrationTestSuite) TestMultipleSyncBroadcastTxRequests() {
}
})
}
}
func (s *IntegrationTestSuite) createTestStdTx(val *network.Validator, sequence uint64) authtypes.StdTx {
txConfig := authtypes.StdTxConfig{Cdc: s.cfg.LegacyAmino}
msg := &types.MsgSend{
FromAddress: val.Address,
ToAddress: val.Address,
Amount: sdk.Coins{sdk.NewInt64Coin(fmt.Sprintf("%stoken", val.Moniker), 100)},
}
// prepare txBuilder with msg
txBuilder := txConfig.NewTxBuilder()
feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}
gasLimit := testdata.NewTestGasLimit()
txBuilder.SetMsgs(msg)
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
txBuilder.SetMemo("foobar")
// setup txFactory
txFactory := tx.Factory{}.
WithChainID(val.ClientCtx.ChainID).
WithKeybase(val.ClientCtx.Keyring).
WithTxConfig(txConfig).
WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON).
WithSequence(sequence)
// sign Tx (offline mode so we can manually set sequence number)
err := authclient.SignTx(txFactory, val.ClientCtx, val.Moniker, txBuilder, true)
s.Require().NoError(err)
stdTx := txBuilder.GetTx().(authtypes.StdTx)
return stdTx
}
func (s *IntegrationTestSuite) broadcastReq(stdTx authtypes.StdTx, mode string) ([]byte, error) {