Moved the handlers from stack into modules
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/state"
|
||||
)
|
||||
|
||||
//nolint
|
||||
const (
|
||||
NameSigs = "sigs"
|
||||
)
|
||||
|
||||
// Signatures parses out go-crypto signatures and adds permissions to the
|
||||
// context for use inside the application
|
||||
type Signatures struct {
|
||||
stack.PassOption
|
||||
}
|
||||
|
||||
// Name of the module - fulfills Middleware interface
|
||||
func (Signatures) Name() string {
|
||||
return NameSigs
|
||||
}
|
||||
|
||||
var _ stack.Middleware = Signatures{}
|
||||
|
||||
// SigPerm takes the binary address from PubKey.Address and makes it an Actor
|
||||
func SigPerm(addr []byte) basecoin.Actor {
|
||||
return basecoin.NewActor(NameSigs, addr)
|
||||
}
|
||||
|
||||
// Signed allows us to use txs.OneSig and txs.MultiSig (and others??)
|
||||
type Signed interface {
|
||||
basecoin.TxLayer
|
||||
Signers() ([]crypto.PubKey, error)
|
||||
}
|
||||
|
||||
// CheckTx verifies the signatures are correct - fulfills Middlware interface
|
||||
func (Signatures) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
||||
sigs, tnext, err := getSigners(tx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
ctx2 := addSigners(ctx, sigs)
|
||||
return next.CheckTx(ctx2, store, tnext)
|
||||
}
|
||||
|
||||
// DeliverTx verifies the signatures are correct - fulfills Middlware interface
|
||||
func (Signatures) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
||||
sigs, tnext, err := getSigners(tx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
ctx2 := addSigners(ctx, sigs)
|
||||
return next.DeliverTx(ctx2, store, tnext)
|
||||
}
|
||||
|
||||
func addSigners(ctx basecoin.Context, sigs []crypto.PubKey) basecoin.Context {
|
||||
perms := make([]basecoin.Actor, len(sigs))
|
||||
for i, s := range sigs {
|
||||
perms[i] = SigPerm(s.Address())
|
||||
}
|
||||
// add the signers to the context and continue
|
||||
return ctx.WithPermissions(perms...)
|
||||
}
|
||||
|
||||
func getSigners(tx basecoin.Tx) ([]crypto.PubKey, basecoin.Tx, error) {
|
||||
stx, ok := tx.Unwrap().(Signed)
|
||||
if !ok {
|
||||
return nil, basecoin.Tx{}, errors.ErrUnauthorized()
|
||||
}
|
||||
sig, err := stx.Signers()
|
||||
return sig, stx.Next(), err
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/state"
|
||||
"github.com/tendermint/basecoin/txs"
|
||||
)
|
||||
|
||||
func TestSignatureChecks(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// generic args
|
||||
ctx := stack.NewContext("test-chain", log.NewNopLogger())
|
||||
store := state.NewMemKVStore()
|
||||
raw := txs.NewRaw([]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())
|
||||
|
||||
// test cases to make sure signature checks are solid
|
||||
cases := []struct {
|
||||
useMultiSig bool
|
||||
keys []crypto.PrivKey
|
||||
check basecoin.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},
|
||||
|
||||
// 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)
|
||||
|
||||
// make the stack check for the given permission
|
||||
app := stack.New(
|
||||
Signatures{},
|
||||
stack.CheckMiddleware{Required: tc.check},
|
||||
).Use(stack.OKHandler{})
|
||||
|
||||
var tx basecoin.Tx
|
||||
// this does the signing as needed
|
||||
if tc.useMultiSig {
|
||||
mtx := txs.NewMulti(raw)
|
||||
for _, k := range tc.keys {
|
||||
err := txs.Sign(mtx, k)
|
||||
assert.Nil(err, "%d: %+v", i, err)
|
||||
}
|
||||
tx = mtx.Wrap()
|
||||
} else {
|
||||
otx := txs.NewSig(raw)
|
||||
for _, k := range tc.keys {
|
||||
err := txs.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.DeliverTx(ctx, store, tx)
|
||||
if tc.valid {
|
||||
assert.Nil(err, "%d: %+v", i, err)
|
||||
} else {
|
||||
assert.NotNil(err, idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user