diff --git a/modules/auth/bench_test.go b/modules/auth/bench_test.go index 739c553278..c497e2d383 100644 --- a/modules/auth/bench_test.go +++ b/modules/auth/bench_test.go @@ -1,74 +1,77 @@ package auth -import ( - "fmt" - "testing" +// import ( +// "fmt" +// "testing" - crypto "github.com/tendermint/go-crypto" - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" +// crypto "github.com/tendermint/go-crypto" +// cmn "github.com/tendermint/tmlibs/common" - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) +// sdk "github.com/cosmos/cosmos-sdk" +// "github.com/cosmos/cosmos-sdk/state" +// "github.com/cosmos/cosmos-sdk/util" +// ) -func makeSignTx() sdk.Tx { - key := crypto.GenPrivKeyEd25519().Wrap() - payload := cmn.RandBytes(32) - tx := NewSig(stack.NewRawTx(payload)) - Sign(tx, key) - return tx.Wrap() -} +// func makeSignTx() sdk.Tx { +// key := crypto.GenPrivKeyEd25519().Wrap() +// payload := cmn.RandBytes(32) +// tx := NewSig(util.RawTx{payload}) +// Sign(tx, key) +// return tx.Wrap() +// } -func makeMultiSignTx(cnt int) sdk.Tx { - payload := cmn.RandBytes(32) - tx := NewMulti(stack.NewRawTx(payload)) - for i := 0; i < cnt; i++ { - key := crypto.GenPrivKeyEd25519().Wrap() - Sign(tx, key) - } - return tx.Wrap() -} +// func makeMultiSignTx(cnt int) sdk.Tx { +// payload := cmn.RandBytes(32) +// tx := NewMulti(util.RawTx{payload}) +// for i := 0; i < cnt; i++ { +// key := crypto.GenPrivKeyEd25519().Wrap() +// Sign(tx, key) +// } +// return tx.Wrap() +// } -func makeHandler() sdk.Handler { - return stack.New(Signatures{}).Use(stack.OKHandler{}) -} +// func makeHandler() sdk.Handler { +// return sdk.ChainDecorators( +// Signatures{}, +// ).WithHandler( +// util.OKHandler{}, +// ) +// } -func BenchmarkCheckOneSig(b *testing.B) { - tx := makeSignTx() - h := makeHandler() - store := state.NewMemKVStore() - for i := 1; i <= b.N; i++ { - ctx := stack.NewContext("foo", 100, log.NewNopLogger()) - _, err := h.DeliverTx(ctx, store, tx) - // never should error - if err != nil { - panic(err) - } - } -} +// func BenchmarkCheckOneSig(b *testing.B) { +// tx := makeSignTx() +// h := makeHandler() +// store := state.NewMemKVStore() +// for i := 1; i <= b.N; i++ { +// ctx := util.MockContext("foo", 100) +// _, err := h.DeliverTx(ctx, store, tx) +// // never should error +// if err != nil { +// panic(err) +// } +// } +// } -func BenchmarkCheckMultiSig(b *testing.B) { - sigs := []int{1, 3, 8, 20} - for _, cnt := range sigs { - label := fmt.Sprintf("%dsigs", cnt) - b.Run(label, func(sub *testing.B) { - benchmarkCheckMultiSig(sub, cnt) - }) - } -} +// func BenchmarkCheckMultiSig(b *testing.B) { +// sigs := []int{1, 3, 8, 20} +// for _, cnt := range sigs { +// label := fmt.Sprintf("%dsigs", cnt) +// b.Run(label, func(sub *testing.B) { +// benchmarkCheckMultiSig(sub, cnt) +// }) +// } +// } -func benchmarkCheckMultiSig(b *testing.B, cnt int) { - tx := makeMultiSignTx(cnt) - h := makeHandler() - store := state.NewMemKVStore() - for i := 1; i <= b.N; i++ { - ctx := stack.NewContext("foo", 100, log.NewNopLogger()) - _, err := h.DeliverTx(ctx, store, tx) - // never should error - if err != nil { - panic(err) - } - } -} +// func benchmarkCheckMultiSig(b *testing.B, cnt int) { +// tx := makeMultiSignTx(cnt) +// h := makeHandler() +// store := state.NewMemKVStore() +// for i := 1; i <= b.N; i++ { +// ctx := util.MockContext("foo", 100) +// _, err := h.DeliverTx(ctx, store, tx) +// // never should error +// if err != nil { +// panic(err) +// } +// } +// } diff --git a/modules/auth/helpers_test.go b/modules/auth/helpers_test.go new file mode 100644 index 0000000000..3c1cc0e01f --- /dev/null +++ b/modules/auth/helpers_test.go @@ -0,0 +1,84 @@ +package auth + +import ( + crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/go-crypto/keys" + wire "github.com/tendermint/go-wire" + + sdk "github.com/cosmos/cosmos-sdk" + "github.com/cosmos/cosmos-sdk/util" +) + +type oneSig struct { + // Data is the payload + Data util.RawTx + // NamedSig holds credentials and exposes Sign + *NamedSig +} + +var _ Signable = oneSig{} +var _ sdk.Msg = oneSig{} +var _ keys.Signable = oneSig{} + +func (o oneSig) SignBytes() []byte { + return wire.BinaryBytes(o.Data) +} + +func (o oneSig) TxBytes() ([]byte, error) { + // if o.NamedSig.Empty() { + // return nil, errors.ErrMissingSignature() + // } + return wire.BinaryBytes(o), nil +} + +func (o oneSig) Signers() ([]crypto.PubKey, error) { + return o.NamedSig.Signers(o.SignBytes()) +} + +func (o oneSig) GetTx() interface{} { + return o.Data +} + +func OneSig(data []byte) keys.Signable { + return oneSig{ + Data: util.NewRawTx(data), + NamedSig: NewSig(), + } +} + +type multiSig struct { + // Data is the payload + Data util.RawTx + // NamedSig holds credentials and exposes Sign + *NamedSigs +} + +var _ Signable = oneSig{} +var _ sdk.Msg = oneSig{} +var _ keys.Signable = oneSig{} + +func (m multiSig) SignBytes() []byte { + return wire.BinaryBytes(m.Data) +} + +func (m multiSig) TxBytes() ([]byte, error) { + // if m.NamedSigs.Empty() { + // return nil, errors.ErrMissingSignature() + // } + return wire.BinaryBytes(m), nil +} + +func (m multiSig) Signers() ([]crypto.PubKey, error) { + return m.NamedSigs.Signers(m.SignBytes()) +} + +func (m multiSig) GetTx() interface{} { + return m.Data +} + +func MultiSig(data []byte) keys.Signable { + return multiSig{ + Data: util.NewRawTx(data), + NamedSigs: NewMultiSig(), + } +} diff --git a/modules/auth/signature.go b/modules/auth/signature.go index c0c931d56b..5270b201a1 100644 --- a/modules/auth/signature.go +++ b/modules/auth/signature.go @@ -14,8 +14,7 @@ const ( // Signatures parses out go-crypto signatures and adds permissions to the // context for use inside the application -type Signatures struct { -} +type Signatures struct{} var _ sdk.Decorator = Signatures{} @@ -24,11 +23,6 @@ func SigPerm(addr []byte) sdk.Actor { return sdk.NewActor(NameSigs, addr) } -// Signable allows us to use txs.OneSig and txs.MultiSig (and others??) -type Signable interface { - Signers() ([]crypto.PubKey, error) -} - // CheckTx verifies the signatures are correct - fulfills Middlware interface func (Signatures) CheckTx(ctx sdk.Context, store sdk.SimpleDB, tx interface{}, next sdk.Checker) (res sdk.CheckResult, err error) { diff --git a/modules/auth/signature_test.go b/modules/auth/signature_test.go index 79706f953d..a6411a09f4 100644 --- a/modules/auth/signature_test.go +++ b/modules/auth/signature_test.go @@ -1,96 +1,97 @@ package auth -import ( - "strconv" - "testing" +// import ( +// "strconv" +// "testing" - "github.com/stretchr/testify/assert" +// "github.com/stretchr/testify/assert" - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/tmlibs/log" +// crypto "github.com/tendermint/go-crypto" - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) +// sdk "github.com/cosmos/cosmos-sdk" +// "github.com/cosmos/cosmos-sdk/state" +// "github.com/cosmos/cosmos-sdk/util" +// ) -func TestSignatureChecks(t *testing.T) { - assert := assert.New(t) +// func TestSignatureChecks(t *testing.T) { +// assert := assert.New(t) - // generic args - ctx := stack.NewContext("test-chain", 100, log.NewNopLogger()) - store := state.NewMemKVStore() - raw := stack.NewRawTx([]byte{1, 2, 3, 4}) +// // generic args +// ctx := util.MockContext("test-chain", 100) +// store := state.NewMemKVStore() +// raw := util.NewRawTx([]byte{1, 2, 3, 4}) - // let's make some keys.... - priv1 := crypto.GenPrivKeyEd25519().Wrap() - actor1 := SigPerm(priv1.PubKey().Address()) - priv2 := crypto.GenPrivKeySecp256k1().Wrap() - actor2 := SigPerm(priv2.PubKey().Address()) +// // let's make some keys.... +// priv1 := crypto.GenPrivKeyEd25519().Wrap() +// actor1 := SigPerm(priv1.PubKey().Address()) +// priv2 := crypto.GenPrivKeySecp256k1().Wrap() +// actor2 := SigPerm(priv2.PubKey().Address()) - // test cases to make sure signature checks are solid - cases := []struct { - useMultiSig bool - keys []crypto.PrivKey - check sdk.Actor - valid bool - }{ - // test with single sigs - {false, []crypto.PrivKey{priv1}, actor1, true}, - {false, []crypto.PrivKey{priv1}, actor2, false}, - {false, []crypto.PrivKey{priv2}, actor2, true}, - {false, []crypto.PrivKey{}, actor2, false}, +// // test cases to make sure signature checks are solid +// cases := []struct { +// useMultiSig bool +// keys []crypto.PrivKey +// check sdk.Actor +// valid bool +// }{ +// // test with single sigs +// {false, []crypto.PrivKey{priv1}, actor1, true}, +// {false, []crypto.PrivKey{priv1}, actor2, false}, +// {false, []crypto.PrivKey{priv2}, actor2, true}, +// {false, []crypto.PrivKey{}, actor2, false}, - // same with multi sigs - {true, []crypto.PrivKey{priv1}, actor1, true}, - {true, []crypto.PrivKey{priv1}, actor2, false}, - {true, []crypto.PrivKey{priv2}, actor2, true}, - {true, []crypto.PrivKey{}, actor2, false}, +// // same with multi sigs +// {true, []crypto.PrivKey{priv1}, actor1, true}, +// {true, []crypto.PrivKey{priv1}, actor2, false}, +// {true, []crypto.PrivKey{priv2}, actor2, true}, +// {true, []crypto.PrivKey{}, actor2, false}, - // make sure both match on a multisig - {true, []crypto.PrivKey{priv1, priv2}, actor1, true}, - {true, []crypto.PrivKey{priv1, priv2}, actor2, true}, - } +// // make sure both match on a multisig +// {true, []crypto.PrivKey{priv1, priv2}, actor1, true}, +// {true, []crypto.PrivKey{priv1, priv2}, actor2, true}, +// } - for i, tc := range cases { - idx := strconv.Itoa(i) +// for i, tc := range cases { +// idx := strconv.Itoa(i) - // make the stack check for the given permission - app := stack.New( - Signatures{}, - stack.CheckMiddleware{Required: tc.check}, - ).Use(stack.OKHandler{}) +// // make the stack check for the given permission +// app := sdk.ChainDecorators( +// Signatures{}, +// util.CheckMiddleware{Required: tc.check}, +// ).WithHandler( +// util.OKHandler{}, +// ) - var tx sdk.Tx - // this does the signing as needed - if tc.useMultiSig { - mtx := NewMulti(raw) - for _, k := range tc.keys { - err := Sign(mtx, k) - assert.Nil(err, "%d: %+v", i, err) - } - tx = mtx.Wrap() - } else { - otx := NewSig(raw) - for _, k := range tc.keys { - err := Sign(otx, k) - assert.Nil(err, "%d: %+v", i, err) - } - tx = otx.Wrap() - } +// var tx sdk.Tx +// // this does the signing as needed +// if tc.useMultiSig { +// mtx := NewMulti(raw) +// for _, k := range tc.keys { +// err := Sign(mtx, k) +// assert.Nil(err, "%d: %+v", i, err) +// } +// tx = mtx.Wrap() +// } else { +// otx := NewSig(raw) +// for _, k := range tc.keys { +// err := Sign(otx, k) +// assert.Nil(err, "%d: %+v", i, err) +// } +// tx = otx.Wrap() +// } - _, err := app.CheckTx(ctx, store, tx) - if tc.valid { - assert.Nil(err, "%d: %+v", i, err) - } else { - assert.NotNil(err, idx) - } +// _, err := app.CheckTx(ctx, store, tx) +// if tc.valid { +// assert.Nil(err, "%d: %+v", i, err) +// } else { +// assert.NotNil(err, idx) +// } - _, err = app.DeliverTx(ctx, store, tx) - if tc.valid { - assert.Nil(err, "%d: %+v", i, err) - } else { - assert.NotNil(err, idx) - } - } -} +// _, err = app.DeliverTx(ctx, store, tx) +// if tc.valid { +// assert.Nil(err, "%d: %+v", i, err) +// } else { +// assert.NotNil(err, idx) +// } +// } +// } diff --git a/modules/auth/tx.go b/modules/auth/tx.go index fc1cf5c961..a25bb6321c 100644 --- a/modules/auth/tx.go +++ b/modules/auth/tx.go @@ -8,7 +8,7 @@ It currently does not support N-of-M key share signing of other more complex algorithms (although it would be great to add them). This can be embedded in another structure along with the data to be -signed and easily allow you to build a custom keys.Signable implementation. +signed and easily allow you to build a custom Signable implementation. Please see example usage of Credential. */ package auth @@ -30,6 +30,11 @@ type Credential interface { Signers(signBytes []byte) ([]crypto.PubKey, error) } +// Signable is data along with credentials, which can be verified +type Signable interface { + Signers() ([]crypto.PubKey, error) +} + ///////////////////////////////////////// // NamedSig - one signature @@ -41,6 +46,10 @@ type NamedSig struct { var _ Credential = &NamedSig{} +func NewSig() *NamedSig { + return new(NamedSig) +} + // Empty returns true if there is not enough signature info func (s *NamedSig) Empty() bool { return s.Sig.Empty() || s.Pubkey.Empty() @@ -106,6 +115,12 @@ type NamedSigs []NamedSig var _ Credential = &NamedSigs{} +func NewMultiSig() *NamedSigs { + // pre-allocate space of two, as we expect multiple signatures + s := make(NamedSigs, 0, 2) + return &s +} + // Empty returns true iff no signatures were ever added func (s *NamedSigs) Empty() bool { return len(*s) == 0 diff --git a/modules/auth/tx_test.go b/modules/auth/tx_test.go index 4ec555d853..6fe3c3b96c 100644 --- a/modules/auth/tx_test.go +++ b/modules/auth/tx_test.go @@ -12,20 +12,16 @@ import ( "github.com/tendermint/go-crypto/keys/storage/memstorage" wire "github.com/tendermint/go-wire" - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/stack" + "github.com/cosmos/cosmos-sdk/util" ) func checkSignBytes(t *testing.T, bytes []byte, expected string) { // load it back... unwrap the tx - var preTx sdk.Tx - err := wire.ReadBinaryBytes(bytes, &preTx) + var raw util.RawTx + err := wire.ReadBinaryBytes(bytes, &raw) require.Nil(t, err) - - // now make sure this tx is data.Bytes with the info we want - raw, ok := preTx.Unwrap().(stack.RawTx) - require.True(t, ok) - assert.Equal(t, expected, string(raw.Bytes)) + // now make sure this is data.Bytes with the info we expect + assert.Equal(t, expected, string(raw.Data)) } func TestOneSig(t *testing.T) { @@ -56,8 +52,7 @@ func TestOneSig(t *testing.T) { } for _, tc := range cases { - inner := stack.NewRawTx([]byte(tc.data)).Wrap() - tx := NewSig(inner) + tx := OneSig([]byte(tc.data)) // unsigned version _, err = tx.Signers() assert.NotNil(err) @@ -122,8 +117,7 @@ func TestMultiSig(t *testing.T) { } for _, tc := range cases { - inner := stack.NewRawTx([]byte(tc.data)).Wrap() - tx := NewMulti(inner) + tx := MultiSig([]byte(tc.data)) // unsigned version _, err = tx.Signers() assert.NotNil(err) diff --git a/util/helpers.go b/util/helpers.go index f1d3c97f44..f8faeb376f 100644 --- a/util/helpers.go +++ b/util/helpers.go @@ -32,6 +32,11 @@ type RawTx struct { Data data.Bytes } +// NewRawTx creates a RawTx object +func NewRawTx(data []byte) RawTx { + return RawTx{Data: data} +} + // ValidateBasic can ensure a limited size of tx func (r RawTx) ValidateBasic() error { if len(r.Data) > rawMaxSize {