Tested signature middleware with standard tx wrappers

This commit is contained in:
Ethan Frey 2017-06-29 20:34:43 +02:00
parent b9ce148e8e
commit 4eef581396
5 changed files with 130 additions and 9 deletions

View File

@ -61,7 +61,7 @@ func NewDefault(chainID string, middlewares ...Middleware) *Stack {
mids := []Middleware{
Logger{},
Recovery{},
SignedHandler{true},
Signatures{},
Chain{chainID},
}
mids = append(mids, middlewares...)

View File

@ -1,6 +1,8 @@
package stack
import (
"fmt"
crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/basecoin"
@ -13,15 +15,13 @@ const (
NameSigs = "sigs"
)
type SignedHandler struct {
AllowMultiSig bool
}
type Signatures struct{}
func (_ SignedHandler) Name() string {
func (_ Signatures) Name() string {
return NameSigs
}
var _ Middleware = SignedHandler{}
var _ Middleware = Signatures{}
func SigPerm(addr []byte) basecoin.Actor {
return basecoin.NewActor(NameSigs, addr)
@ -33,7 +33,7 @@ type Signed interface {
Signers() ([]crypto.PubKey, error)
}
func (h SignedHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
func (h Signatures) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
sigs, tnext, err := getSigners(tx)
if err != nil {
return res, err
@ -42,7 +42,7 @@ func (h SignedHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx bas
return next.CheckTx(ctx2, store, tnext)
}
func (h SignedHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
func (h Signatures) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
sigs, tnext, err := getSigners(tx)
if err != nil {
return res, err
@ -53,7 +53,9 @@ func (h SignedHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx b
func addSigners(ctx basecoin.Context, sigs []crypto.PubKey) basecoin.Context {
perms := make([]basecoin.Actor, len(sigs))
fmt.Printf("Add %d signers\n", len(sigs))
for i, s := range sigs {
fmt.Printf("Add %X\n", s.Address())
perms[i] = SigPerm(s.Address())
}
// add the signers to the context and continue
@ -61,8 +63,10 @@ func addSigners(ctx basecoin.Context, sigs []crypto.PubKey) basecoin.Context {
}
func getSigners(tx basecoin.Tx) ([]crypto.PubKey, basecoin.Tx, error) {
fmt.Println("getSigners")
stx, ok := tx.Unwrap().(Signed)
if !ok {
fmt.Printf("Not okay: %#v\n", tx)
return nil, basecoin.Tx{}, errors.Unauthorized()
}
sig, err := stx.Signers()

99
stack/signature_test.go Normal file
View File

@ -0,0 +1,99 @@
package stack
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/txs"
"github.com/tendermint/basecoin/types"
)
func TestSignatureChecks(t *testing.T) {
assert := assert.New(t)
// generic args
ctx := NewContext(log.NewNopLogger())
store := types.NewMemKVStore()
raw := txs.NewRaw([]byte{1, 2, 3, 4}).Wrap()
// 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 := New(
Recovery{}, // we need this so panics turn to errors
Signatures{},
CheckMiddleware{tc.check},
).Use(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()
}
// this will trivial expose the printing error...
// _, err := app.CheckTx(ctx, store, raw)
_, err := app.CheckTx(ctx, store, tx)
if tc.valid {
// TODO: why doen't tmerror print properly???
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

@ -9,7 +9,8 @@ import (
const (
// for utils...
ByteRaw = 0x1
ByteRaw = 0x1
// TODO: move fees into a module, multiplexer is standard
ByteFees = 0x2
ByteMulti = 0x3
ByteChain = 0x4

View File

@ -49,6 +49,7 @@ type OneSig struct {
}
var _ keys.Signable = &OneSig{}
var _ basecoin.TxLayer = &OneSig{}
func NewSig(tx basecoin.Tx) *OneSig {
return &OneSig{Tx: tx}
@ -58,6 +59,10 @@ func (s *OneSig) Wrap() basecoin.Tx {
return basecoin.Tx{s}
}
func (s *OneSig) Next() basecoin.Tx {
return s.Tx
}
func (s *OneSig) ValidateBasic() error {
// TODO: VerifyBytes here, we do it in Signers?
if s.Empty() || !s.Pubkey.VerifyBytes(s.SignBytes(), s.Sig) {
@ -119,6 +124,7 @@ type MultiSig struct {
}
var _ keys.Signable = &MultiSig{}
var _ basecoin.TxLayer = &MultiSig{}
func NewMulti(tx basecoin.Tx) *MultiSig {
return &MultiSig{Tx: tx}
@ -128,6 +134,10 @@ func (s *MultiSig) Wrap() basecoin.Tx {
return basecoin.Tx{s}
}
func (s *MultiSig) Next() basecoin.Tx {
return s.Tx
}
func (s *MultiSig) ValidateBasic() error {
// TODO: more efficient
_, err := s.Signers()
@ -185,3 +195,10 @@ func (s *MultiSig) Signers() ([]crypto.PubKey, error) {
return keys, nil
}
func Sign(tx keys.Signable, key crypto.PrivKey) error {
msg := tx.SignBytes()
pubkey := key.PubKey()
sig := key.Sign(msg)
return tx.Sign(pubkey, sig)
}