Auth Tx sign tests pass

This commit is contained in:
Ethan Frey 2017-10-24 16:24:02 +02:00
parent 8e442d5ded
commit 3aeab43acb
7 changed files with 261 additions and 165 deletions

View File

@ -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)
// }
// }
// }

View File

@ -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(),
}
}

View File

@ -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) {

View File

@ -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)
// }
// }
// }

View File

@ -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

View File

@ -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)

View File

@ -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 {