cosmos-sdk/modules/nonce/tx.go

112 lines
2.7 KiB
Go
Raw Normal View History

2017-07-11 17:00:39 -07:00
/*
2017-07-13 01:37:22 -07:00
Package nonce - This module allows replay protection to be added to process stack.
This is achieved through the use of a sequence number for each unique set of signers.
Note that the sequence number for the single signing account "foo" will be unique
from the sequence number for a multi-sig account {"foo", "bar"} which would also be
unique from a different multi-sig account {"foo", "soup"}
2017-07-11 17:00:39 -07:00
*/
package nonce
import (
2017-07-12 02:02:16 -07:00
"sort"
2017-07-11 17:00:39 -07:00
"github.com/tendermint/basecoin"
2017-07-12 02:02:16 -07:00
"github.com/tendermint/basecoin/state"
2017-07-11 17:00:39 -07:00
)
// nolint
const (
2017-07-12 02:02:16 -07:00
ByteNonce = 0x69 //TODO overhaul byte assign system don't make no sense!
TypeNonce = "nonce"
2017-07-11 17:00:39 -07:00
)
2017-07-12 02:02:16 -07:00
func init() {
2017-07-12 03:10:17 -07:00
basecoin.TxMapper.RegisterImplementation(Tx{}, TypeNonce, ByteNonce)
2017-07-12 02:02:16 -07:00
}
2017-07-11 17:00:39 -07:00
2017-07-13 01:37:22 -07:00
// Tx - Nonce transaction structure, contains list of signers and current sequence number
2017-07-11 17:00:39 -07:00
type Tx struct {
2017-07-12 03:10:17 -07:00
Sequence uint32 `json:"sequence"`
Signers []basecoin.Actor `json:"signers"`
Tx basecoin.Tx `json:"tx"`
2017-07-11 17:00:39 -07:00
}
var _ basecoin.TxInner = &Tx{}
// NewTx wraps the tx with a signable nonce
2017-07-12 03:10:17 -07:00
func NewTx(sequence uint32, signers []basecoin.Actor, tx basecoin.Tx) basecoin.Tx {
2017-07-12 02:02:16 -07:00
return (Tx{
2017-07-11 17:00:39 -07:00
Sequence: sequence,
Signers: signers,
2017-07-12 03:10:17 -07:00
Tx: tx,
2017-07-12 02:02:16 -07:00
}).Wrap()
2017-07-11 17:00:39 -07:00
}
//nolint
2017-07-12 02:02:16 -07:00
func (n Tx) Wrap() basecoin.Tx {
return basecoin.Tx{n}
2017-07-11 17:00:39 -07:00
}
2017-07-12 02:02:16 -07:00
func (n Tx) ValidateBasic() error {
2017-07-13 01:37:22 -07:00
switch {
case n.Tx.Empty():
2017-07-18 22:23:13 -07:00
return ErrTxEmpty()
2017-07-13 01:37:22 -07:00
case n.Sequence == 0:
2017-07-14 13:29:43 -07:00
return ErrZeroSequence()
2017-07-13 01:37:22 -07:00
case len(n.Signers) == 0:
2017-07-18 22:23:13 -07:00
return ErrNoSigners()
2017-07-13 01:37:22 -07:00
}
2017-07-12 02:02:16 -07:00
return n.Tx.ValidateBasic()
2017-07-11 17:00:39 -07:00
}
2017-07-13 07:34:57 -07:00
// CheckIncrementSeq - Check that the sequence number is one more than the state sequence number
2017-07-13 01:37:22 -07:00
// and further increment the sequence number
2017-07-13 07:34:57 -07:00
// NOTE It is okay to modify the sequence before running the wrapped TX because if the
// wrapped Tx fails, the state changes are not applied
func (n Tx) CheckIncrementSeq(ctx basecoin.Context, store state.SimpleDB) error {
2017-07-11 17:00:39 -07:00
2017-07-13 01:37:22 -07:00
seqKey := n.getSeqKey()
2017-07-12 03:10:17 -07:00
2017-07-11 17:00:39 -07:00
// check the current state
2017-07-12 03:10:17 -07:00
cur, err := getSeq(store, seqKey)
2017-07-12 02:02:16 -07:00
if err != nil {
return err
}
2017-07-11 17:00:39 -07:00
if n.Sequence != cur+1 {
2017-07-14 13:29:43 -07:00
return ErrBadNonce(n.Sequence, cur+1)
2017-07-11 17:00:39 -07:00
}
// make sure they all signed
for _, s := range n.Signers {
if !ctx.HasPermission(s) {
2017-07-14 13:29:43 -07:00
return ErrNotMember()
2017-07-11 17:00:39 -07:00
}
}
2017-07-13 01:37:22 -07:00
// increment the sequence by 1
2017-07-12 03:10:17 -07:00
err = setSeq(store, seqKey, cur+1)
2017-07-12 02:02:16 -07:00
if err != nil {
return err
}
2017-07-11 17:00:39 -07:00
return nil
}
2017-07-13 01:37:22 -07:00
func (n Tx) getSeqKey() (seqKey []byte) {
2017-07-18 02:26:25 -07:00
return GetSeqKey(n.Signers)
}
// GetSeqKey - Generate the sequence key as the concatenated list of signers, sorted by address.
func GetSeqKey(signers []basecoin.Actor) (seqKey []byte) {
2017-07-13 01:37:22 -07:00
// First copy the list of signers to sort as sort is done in place
2017-07-18 02:26:25 -07:00
signers2sort := make([]basecoin.Actor, len(signers))
copy(signers2sort, signers)
sort.Sort(basecoin.ByAll(signers))
2017-07-13 01:37:22 -07:00
2017-07-18 02:26:25 -07:00
for _, signer := range signers {
2017-07-17 19:50:10 -07:00
seqKey = append(seqKey, signer.Bytes()...)
2017-07-13 01:37:22 -07:00
}
2017-07-18 02:26:25 -07:00
2017-07-13 01:37:22 -07:00
return
}