Generalize auth/types.StdSignature (#4507)

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
This commit is contained in:
Alessio Treglia
2019-06-07 14:21:35 +01:00
committed by GitHub
parent c777fb9108
commit a32d5a46d7
29 changed files with 124 additions and 78 deletions
+1
View File
@@ -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
+11 -10
View File
@@ -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
}
@@ -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),
@@ -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) {
@@ -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()
}
@@ -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[:]
}
@@ -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 {
@@ -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()
}
+7 -6
View File
@@ -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)
@@ -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) {
+3 -1
View File
@@ -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"
)
@@ -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
+4 -4
View File
@@ -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 (
@@ -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")
+3 -2
View File
@@ -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) {
+1
View File
@@ -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.
+19 -7
View File
@@ -12,7 +12,8 @@ import (
)
var (
_ sdk.Tx = (*StdTx)(nil)
_ sdk.Tx = (*StdTx)(nil)
_ sdk.Signature = (*StdSignature)(nil)
maxGasWanted = uint64((1 << 63) - 1)
)
@@ -20,13 +21,13 @@ var (
// 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,
@@ -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 }
//__________________________________________________________
@@ -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) {
+12 -2
View File
@@ -1,10 +1,12 @@
package types
import (
"bytes"
"fmt"
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
@@ -22,7 +24,7 @@ var (
func TestStdTx(t *testing.T) {
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
fee := NewTestStdFee()
sigs := []StdSignature{}
sigs := []sdk.Signature{}
tx := NewStdTx(msgs, fee, sigs, "")
require.Equal(t, msgs, tx.GetMsgs())
@@ -121,7 +123,7 @@ func TestDefaultTxEncoder(t *testing.T) {
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
fee := NewTestStdFee()
sigs := []StdSignature{}
sigs := []sdk.Signature{}
tx := NewStdTx(msgs, fee, sigs, "")
@@ -133,3 +135,11 @@ func TestDefaultTxEncoder(t *testing.T) {
require.NoError(t, err)
require.Equal(t, cdcBytes, encoderBytes)
}
func TestNewStdSignature(t *testing.T) {
pub := ed25519.GenPrivKey().PubKey()
sigBytes := []byte("data")
got := NewStdSignature(pub, sigBytes)
require.True(t, bytes.Equal(got.GetSignature(), sigBytes))
require.True(t, got.GetPubKey().Equals(pub))
}
+6 -6
View File
@@ -70,7 +70,7 @@ func KeyTestPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) {
}
func NewTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums []uint64, seqs []uint64, fee StdFee) sdk.Tx {
sigs := make([]StdSignature, len(privs))
sigs := make([]sdk.Signature, len(privs))
for i, priv := range privs {
signBytes := StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, "")
@@ -79,7 +79,7 @@ func NewTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums
panic(err)
}
sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig}
sigs[i] = NewStdSignature(priv.PubKey(), sig)
}
tx := NewStdTx(msgs, fee, sigs, "")
@@ -87,7 +87,7 @@ func NewTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums
}
func NewTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums []uint64, seqs []uint64, fee StdFee, memo string) sdk.Tx {
sigs := make([]StdSignature, len(privs))
sigs := make([]sdk.Signature, len(privs))
for i, priv := range privs {
signBytes := StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, memo)
@@ -96,7 +96,7 @@ func NewTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey,
panic(err)
}
sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig}
sigs[i] = NewStdSignature(priv.PubKey(), sig)
}
tx := NewStdTx(msgs, fee, sigs, memo)
@@ -104,14 +104,14 @@ func NewTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey,
}
func NewTestTxWithSignBytes(msgs []sdk.Msg, privs []crypto.PrivKey, accNums []uint64, seqs []uint64, fee StdFee, signBytes []byte, memo string) sdk.Tx {
sigs := make([]StdSignature, len(privs))
sigs := make([]sdk.Signature, len(privs))
for i, priv := range privs {
sig, err := priv.Sign(signBytes)
if err != nil {
panic(err)
}
sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: sig}
sigs[i] = NewStdSignature(priv.PubKey(), sig)
}
tx := NewStdTx(msgs, fee, sigs, memo)
+7 -9
View File
@@ -214,7 +214,7 @@ func (bldr TxBuilder) Sign(name, passphrase string, msg StdSignMsg) ([]byte, err
return nil, err
}
return bldr.txEncoder(NewStdTx(msg.Msgs, msg.Fee, []StdSignature{sig}, msg.Memo))
return bldr.txEncoder(NewStdTx(msg.Msgs, msg.Fee, []sdk.Signature{sig}, msg.Memo))
}
// BuildAndSign builds a single message to be signed, and signs a transaction
@@ -237,7 +237,7 @@ func (bldr TxBuilder) BuildTxForSim(msgs []sdk.Msg) ([]byte, error) {
}
// the ante handler will populate with a sentinel pubkey
sigs := []StdSignature{{}}
sigs := []sdk.Signature{NewStdSignature(nil, nil)}
return bldr.txEncoder(NewStdTx(signMsg.Msgs, signMsg.Fee, sigs, signMsg.Memo))
}
@@ -262,7 +262,7 @@ func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx StdTx, appendSig
sigs := stdTx.GetSignatures()
if len(sigs) == 0 || !appendSig {
sigs = []StdSignature{stdSignature}
sigs = []sdk.Signature{stdSignature}
} else {
sigs = append(sigs, stdSignature)
}
@@ -271,8 +271,8 @@ func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx StdTx, appendSig
}
// MakeSignature builds a StdSignature given keybase, key name, passphrase, and a StdSignMsg.
func MakeSignature(keybase crkeys.Keybase, name, passphrase string,
msg StdSignMsg) (sig StdSignature, err error) {
func MakeSignature(keybase crkeys.Keybase, name,
passphrase string, msg StdSignMsg) (sig sdk.Signature, err error) {
if keybase == nil {
keybase, err = keys.NewKeyBaseFromHomeFlag()
if err != nil {
@@ -284,8 +284,6 @@ func MakeSignature(keybase crkeys.Keybase, name, passphrase string,
if err != nil {
return
}
return StdSignature{
PubKey: pubkey,
Signature: sigBytes,
}, nil
return NewStdSignature(pubkey, sigBytes), nil
}