Skip to content

Commit

Permalink
Generalize auth/types.StdSignature (#4507)
Browse files Browse the repository at this point in the history
New Signature interface available in the top level types package.
auth.StdSignature implements such interface. User defined auth
module can now define their own custom signature types.

Work carried out in the context of the following issues:
- #4488
- #4487
  • Loading branch information
Alessio Treglia authored Jun 7, 2019
1 parent c777fb9 commit a32d5a4
Show file tree
Hide file tree
Showing 29 changed files with 124 additions and 78 deletions.
3 changes: 3 additions & 0 deletions .pending/breaking/sdk/4507-New-Signature-g
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#4507 New `Signature` generic interface available in the top level types package.
`auth.StdSignature` implements such interface. User defined auth module can now
define their own custom signature types.
3 changes: 2 additions & 1 deletion client/keys/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package keys
import (
"io/ioutil"

"github.com/cosmos/cosmos-sdk/client/input"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client/input"
)

func importKeyCommand() *cobra.Command {
Expand Down
3 changes: 2 additions & 1 deletion client/keys/list.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package keys

import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client/flags"
)

func listKeysCmd() *cobra.Command {
Expand Down
3 changes: 2 additions & 1 deletion client/keys/mnemonic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"strings"
"testing"

"github.com/cosmos/cosmos-sdk/client/input"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/client/input"
)

func Test_RunMnemonicCmdNormal(t *testing.T) {
Expand Down
3 changes: 2 additions & 1 deletion client/keys/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package keys
import (
"fmt"

"github.com/cosmos/cosmos-sdk/client/input"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client/input"
)

func updateKeyCommand() *cobra.Command {
Expand Down
8 changes: 4 additions & 4 deletions client/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func TestReadStdTxFromFile(t *testing.T) {

// Build a test transaction
fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)})
stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo")
stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, nil, "foomemo")

// Write it to the file
encodedTx, _ := cdc.MarshalJSON(stdTx)
Expand Down Expand Up @@ -143,8 +143,8 @@ func TestValidateCmd(t *testing.T) {
}{
{"misspelled command", []string{"comission"}, true},
{"no command provided", []string{}, false},
{"help flag", []string{"comission", "--help"}, false},
{"shorthand help flag", []string{"comission", "-h"}, false},
{"help flag", []string{"commission", "--help"}, false},
{"shorthand help flag", []string{"commission", "-h"}, false},
}

for _, tt := range tests {
Expand All @@ -158,7 +158,7 @@ func TestValidateCmd(t *testing.T) {

func compareEncoders(t *testing.T, expected sdk.TxEncoder, actual sdk.TxEncoder) {
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
tx := authtypes.NewStdTx(msgs, authtypes.StdFee{}, []authtypes.StdSignature{}, "")
tx := authtypes.NewStdTx(msgs, authtypes.StdFee{}, []sdk.Signature{}, "")

defaultEncoderBytes, err := expected(tx)
require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion contrib/runsim/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var (
989182, 89182391, 11, 22, 44, 77, 99, 2020,
3232, 123123, 124124, 582582, 18931893,
29892989, 30123012, 47284728, 7601778, 8090485,
977367484, 491163361, 424254581, 673398983,
977367484, 491163361, 424254581, 673398983,
}

// goroutine-safe process map
Expand Down
6 changes: 3 additions & 3 deletions docs/spec/auth/03_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ type StdFee struct {

## StdSignature

A `StdSignature` is the combination of an optional public key and a cryptographic signature
as a byte array. The SDK is agnostic to particular key or signature formats and supports any
supported by the `PubKey` interface.
`StdSignature` implements the `sdk.Signature` interface and consists of a combination of an
optional public key and a cryptographic signature as a byte slice. The SDK is agnostic to
particular key or signature formats and supports any supported by the `PubKey` interface.

```golang
type StdSignature struct {
Expand Down
3 changes: 2 additions & 1 deletion simapp/test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import (

"github.com/tendermint/tendermint/libs/log"

dbm "github.com/tendermint/tendermint/libs/db"

bam "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking"
dbm "github.com/tendermint/tendermint/libs/db"
)

// NewSimAppUNSAFE is used for debugging purposes only.
Expand Down
1 change: 1 addition & 0 deletions types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import "github.com/cosmos/cosmos-sdk/codec"
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterInterface((*Msg)(nil), nil)
cdc.RegisterInterface((*Tx)(nil), nil)
cdc.RegisterInterface((*Signature)(nil), nil)
}
3 changes: 2 additions & 1 deletion types/coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import (
"strings"
"testing"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/codec"
)

var (
Expand Down
8 changes: 8 additions & 0 deletions types/tx_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package types

import (
"encoding/json"

"github.com/tendermint/tendermint/crypto"
)

// Transactions messages must fulfill the Msg
Expand Down Expand Up @@ -42,6 +44,12 @@ type Tx interface {

//__________________________________________________________

// Signature defines the properties of the signature payload.
type Signature interface {
GetPubKey() crypto.PubKey
GetSignature() []byte
}

// TxDecoder unmarshals transaction bytes
type TxDecoder func(txBytes []byte) (Tx, Error)

Expand Down
1 change: 1 addition & 0 deletions x/auth/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ var (
NewStdTx = types.NewStdTx
CountSubKeys = types.CountSubKeys
NewStdFee = types.NewStdFee
NewStdSignature = types.NewStdSignature
StdSignBytes = types.StdSignBytes
DefaultTxDecoder = types.DefaultTxDecoder
DefaultTxEncoder = types.DefaultTxEncoder
Expand Down
21 changes: 11 additions & 10 deletions x/auth/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ func NewAnteHandler(ak AccountKeeper, fck FeeCollectionKeeper, sigGasConsumer Si

// check signature, return account with incremented nonce
signBytes := GetSignBytes(newCtx.ChainID(), stdTx, signerAccs[i], isGenesis)
signerAccs[i], res = processSig(newCtx, signerAccs[i], stdSigs[i], signBytes, simulate, params, sigGasConsumer)
signerAccs[i], res = processSig(newCtx, signerAccs[i], stdSigs[i], signBytes,
simulate, params, sigGasConsumer)
if !res.IsOK() {
return newCtx, res, true
}
Expand Down Expand Up @@ -165,7 +166,7 @@ func ValidateSigCount(stdTx StdTx, params Params) sdk.Result {

sigCount := 0
for i := 0; i < len(stdSigs); i++ {
sigCount += CountSubKeys(stdSigs[i].PubKey)
sigCount += CountSubKeys(stdSigs[i].GetPubKey())
if uint64(sigCount) > params.TxSigLimit {
return sdk.ErrTooManySignatures(
fmt.Sprintf("signatures: %d, limit: %d", sigCount, params.TxSigLimit),
Expand Down Expand Up @@ -194,7 +195,7 @@ func ValidateMemo(stdTx StdTx, params Params) sdk.Result {
// verify the signature and increment the sequence. If the account doesn't have
// a pubkey, set it.
func processSig(
ctx sdk.Context, acc Account, sig StdSignature, signBytes []byte, simulate bool, params Params,
ctx sdk.Context, acc Account, sig sdk.Signature, signBytes []byte, simulate bool, params Params,
sigGasConsumer SignatureVerificationGasConsumer,
) (updatedAcc Account, res sdk.Result) {

Expand All @@ -216,11 +217,11 @@ func processSig(
consumeSimSigGas(ctx.GasMeter(), pubKey, sig, params)
}

if res := sigGasConsumer(ctx.GasMeter(), sig.Signature, pubKey, params); !res.IsOK() {
if res := sigGasConsumer(ctx.GasMeter(), sig.GetSignature(), pubKey, params); !res.IsOK() {
return nil, res
}

if !simulate && !pubKey.VerifyBytes(signBytes, sig.Signature) {
if !simulate && !pubKey.VerifyBytes(signBytes, sig.GetSignature()) {
return nil, sdk.ErrUnauthorized("signature verification failed; verify correct account sequence and chain-id").Result()
}

Expand All @@ -231,9 +232,9 @@ func processSig(
return acc, res
}

func consumeSimSigGas(gasmeter sdk.GasMeter, pubkey crypto.PubKey, sig StdSignature, params Params) {
simSig := StdSignature{PubKey: pubkey}
if len(sig.Signature) == 0 {
func consumeSimSigGas(gasmeter sdk.GasMeter, pubkey crypto.PubKey, sig sdk.Signature, params Params) {
simSig := NewStdSignature(pubkey, nil)
if len(sig.GetSignature()) == 0 {
simSig.Signature = simSecp256k1Sig[:]
}

Expand All @@ -252,7 +253,7 @@ func consumeSimSigGas(gasmeter sdk.GasMeter, pubkey crypto.PubKey, sig StdSignat
// ProcessPubKey verifies that the given account address matches that of the
// StdSignature. In addition, it will set the public key of the account if it
// has not been set.
func ProcessPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey, sdk.Result) {
func ProcessPubKey(acc Account, sig sdk.Signature, simulate bool) (crypto.PubKey, sdk.Result) {
// If pubkey is not known for account, set it from the StdSignature.
pubKey := acc.GetPubKey()
if simulate {
Expand All @@ -268,7 +269,7 @@ func ProcessPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey,
}

if pubKey == nil {
pubKey = sig.PubKey
pubKey = sig.GetPubKey()
if pubKey == nil {
return nil, sdk.ErrInvalidPubKey("PubKey not found").Result()
}
Expand Down
13 changes: 7 additions & 6 deletions x/auth/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,8 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
msgs = []sdk.Msg{msg}
tx = NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee)
sigs := tx.(types.StdTx).GetSignatures()
sigs[0].PubKey = nil
sig := sigs[0].(StdSignature)
sig.PubKey = nil
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)

acc2 = input.ak.GetAccount(ctx, addr2)
Expand Down Expand Up @@ -551,11 +552,11 @@ func TestProcessPubKey(t *testing.T) {
args args
wantErr bool
}{
{"no sigs, simulate off", args{acc1, StdSignature{}, false}, true},
{"no sigs, simulate on", args{acc1, StdSignature{}, true}, false},
{"no sigs, account with pub, simulate on", args{acc2, StdSignature{}, true}, false},
{"pubkey doesn't match addr, simulate off", args{acc1, StdSignature{PubKey: priv2.PubKey()}, false}, true},
{"pubkey doesn't match addr, simulate on", args{acc1, StdSignature{PubKey: priv2.PubKey()}, true}, false},
{"no sigs, simulate off", args{acc1, NewStdSignature(nil, nil), false}, true},
{"no sigs, simulate on", args{acc1, NewStdSignature(nil, nil), true}, false},
{"no sigs, account with pub, simulate on", args{acc2, NewStdSignature(nil, nil), true}, false},
{"pubkey doesn't match addr, simulate off", args{acc1, NewStdSignature(priv2.PubKey(), nil), false}, true},
{"pubkey doesn't match addr, simulate on", args{acc1, NewStdSignature(priv2.PubKey(), nil), true}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
4 changes: 3 additions & 1 deletion x/auth/client/cli/tx_multisign.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/codec"
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
Expand Down Expand Up @@ -119,7 +120,8 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string)
}

newStdSig := types.StdSignature{Signature: cdc.MustMarshalBinaryBare(multisigSig), PubKey: multisigPub}
newTx := types.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, []types.StdSignature{newStdSig}, stdTx.GetMemo())
newTx := types.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, []sdk.Signature{newStdSig},
stdTx.GetMemo())

sigOnly := viper.GetBool(flagSigOnly)
var json []byte
Expand Down
8 changes: 4 additions & 4 deletions x/auth/client/cli/tx_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func printAndValidateSigs(
}

for i, sig := range sigs {
sigAddr := sdk.AccAddress(sig.Address())
sigAddr := sdk.AccAddress(sig.GetPubKey().Address())
sigSanity := "OK"

var (
Expand All @@ -233,16 +233,16 @@ func printAndValidateSigs(
stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(),
)

if ok := sig.VerifyBytes(sigBytes, sig.Signature); !ok {
if ok := sig.GetPubKey().VerifyBytes(sigBytes, sig.GetSignature()); !ok {
sigSanity = "ERROR: signature invalid"
success = false
}
}

multiPK, ok := sig.PubKey.(multisig.PubKeyMultisigThreshold)
multiPK, ok := sig.GetPubKey().(multisig.PubKeyMultisigThreshold)
if ok {
var multiSig multisig.Multisignature
cliCtx.Codec.MustUnmarshalBinaryBare(sig.Signature, &multiSig)
cliCtx.Codec.MustUnmarshalBinaryBare(sig.GetSignature(), &multiSig)

var b strings.Builder
b.WriteString("\n MultiSig Signatures:\n")
Expand Down
5 changes: 3 additions & 2 deletions x/auth/genaccounts/genesis_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package genaccounts
import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)

func TestSanitize(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions x/auth/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(&ContinuousVestingAccount{}, "auth/ContinuousVestingAccount", nil)
cdc.RegisterConcrete(&DelayedVestingAccount{}, "auth/DelayedVestingAccount", nil)
cdc.RegisterConcrete(StdTx{}, "auth/StdTx", nil)
cdc.RegisterConcrete(StdSignature{}, "auth/StdSignature", nil)
}

// RegisterBaseAccount most users shouldn't use this, but this comes in handy for tests.
Expand Down
26 changes: 19 additions & 7 deletions x/auth/types/stdtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,22 @@ import (
)

var (
_ sdk.Tx = (*StdTx)(nil)
_ sdk.Tx = (*StdTx)(nil)
_ sdk.Signature = (*StdSignature)(nil)

maxGasWanted = uint64((1 << 63) - 1)
)

// StdTx is a standard way to wrap a Msg with Fee and Signatures.
// NOTE: the first signature is the fee payer (Signatures must not be nil).
type StdTx struct {
Msgs []sdk.Msg `json:"msg"`
Fee StdFee `json:"fee"`
Signatures []StdSignature `json:"signatures"`
Memo string `json:"memo"`
Msgs []sdk.Msg `json:"msg"`
Fee StdFee `json:"fee"`
Signatures []sdk.Signature `json:"signatures"`
Memo string `json:"memo"`
}

func NewStdTx(msgs []sdk.Msg, fee StdFee, sigs []StdSignature, memo string) StdTx {
func NewStdTx(msgs []sdk.Msg, fee StdFee, sigs []sdk.Signature, memo string) StdTx {
return StdTx{
Msgs: msgs,
Fee: fee,
Expand Down Expand Up @@ -104,7 +105,7 @@ func (tx StdTx) GetMemo() string { return tx.Memo }
// CONTRACT: If the signature is missing (ie the Msg is
// invalid), then the corresponding signature is
// .Empty().
func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures }
func (tx StdTx) GetSignatures() []sdk.Signature { return tx.Signatures }

//__________________________________________________________

Expand Down Expand Up @@ -191,6 +192,17 @@ type StdSignature struct {
Signature []byte `json:"signature"`
}

// NewStdSignature constructs a new StdSignature instance.
func NewStdSignature(pubKey crypto.PubKey, signature []byte) StdSignature {
return StdSignature{PubKey: pubKey, Signature: signature}
}

// GetPubKey returns the embedded crypto.PubKey type.
func (sig StdSignature) GetPubKey() crypto.PubKey { return sig.PubKey }

// GetSignature returns the embedded byte signature.
func (sig StdSignature) GetSignature() []byte { return sig.Signature }

// DefaultTxDecoder logic for standard transaction decoding
func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, sdk.Error) {
Expand Down
Loading

0 comments on commit a32d5a4

Please sign in to comment.