2020-07-06 10:03:45 -07:00
|
|
|
package tx
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2020-07-29 15:33:42 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
|
|
|
2020-07-06 10:03:45 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/types/tx"
|
|
|
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
|
|
|
)
|
|
|
|
|
|
|
|
// SignatureDataToModeInfoAndSig converts a SignatureData to a ModeInfo and raw bytes signature
|
|
|
|
func SignatureDataToModeInfoAndSig(data signing.SignatureData) (*tx.ModeInfo, []byte) {
|
|
|
|
if data == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
switch data := data.(type) {
|
|
|
|
case *signing.SingleSignatureData:
|
|
|
|
return &tx.ModeInfo{
|
|
|
|
Sum: &tx.ModeInfo_Single_{
|
|
|
|
Single: &tx.ModeInfo_Single{Mode: data.SignMode},
|
|
|
|
},
|
|
|
|
}, data.Signature
|
|
|
|
case *signing.MultiSignatureData:
|
|
|
|
n := len(data.Signatures)
|
|
|
|
modeInfos := make([]*tx.ModeInfo, n)
|
|
|
|
sigs := make([][]byte, n)
|
|
|
|
|
|
|
|
for i, d := range data.Signatures {
|
|
|
|
modeInfos[i], sigs[i] = SignatureDataToModeInfoAndSig(d)
|
|
|
|
}
|
|
|
|
|
|
|
|
multisig := types.MultiSignature{
|
|
|
|
Signatures: sigs,
|
|
|
|
}
|
|
|
|
sig, err := multisig.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &tx.ModeInfo{
|
|
|
|
Sum: &tx.ModeInfo_Multi_{
|
|
|
|
Multi: &tx.ModeInfo_Multi{
|
|
|
|
Bitarray: data.BitArray,
|
|
|
|
ModeInfos: modeInfos,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, sig
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("unexpected signature data type %T", data))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ModeInfoAndSigToSignatureData converts a ModeInfo and raw bytes signature to a SignatureData or returns
|
|
|
|
// an error
|
|
|
|
func ModeInfoAndSigToSignatureData(modeInfo *tx.ModeInfo, sig []byte) (signing.SignatureData, error) {
|
|
|
|
switch modeInfo := modeInfo.Sum.(type) {
|
|
|
|
case *tx.ModeInfo_Single_:
|
|
|
|
return &signing.SingleSignatureData{
|
|
|
|
SignMode: modeInfo.Single.Mode,
|
|
|
|
Signature: sig,
|
|
|
|
}, nil
|
|
|
|
|
|
|
|
case *tx.ModeInfo_Multi_:
|
|
|
|
multi := modeInfo.Multi
|
|
|
|
|
|
|
|
sigs, err := decodeMultisignatures(sig)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
sigv2s := make([]signing.SignatureData, len(sigs))
|
|
|
|
for i, mi := range multi.ModeInfos {
|
|
|
|
sigv2s[i], err = ModeInfoAndSigToSignatureData(mi, sigs[i])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &signing.MultiSignatureData{
|
|
|
|
BitArray: multi.Bitarray,
|
|
|
|
Signatures: sigv2s,
|
|
|
|
}, nil
|
|
|
|
|
|
|
|
default:
|
|
|
|
panic(fmt.Errorf("unexpected ModeInfo data type %T", modeInfo))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// decodeMultisignatures safely decodes the the raw bytes as a MultiSignature protobuf message
|
|
|
|
func decodeMultisignatures(bz []byte) ([][]byte, error) {
|
|
|
|
multisig := types.MultiSignature{}
|
|
|
|
err := multisig.Unmarshal(bz)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// NOTE: it is import to reject multi-signatures that contain unrecognized fields because this is an exploitable
|
|
|
|
// malleability in the protobuf message. Basically an attacker could bloat a MultiSignature message with unknown
|
|
|
|
// fields, thus bloating the transaction and causing it to fail.
|
|
|
|
if len(multisig.XXX_unrecognized) > 0 {
|
|
|
|
return nil, fmt.Errorf("rejecting unrecognized fields found in MultiSignature")
|
|
|
|
}
|
|
|
|
return multisig.Signatures, nil
|
|
|
|
}
|
2020-07-29 15:33:42 -07:00
|
|
|
|
2020-08-03 12:47:25 -07:00
|
|
|
func (g config) MarshalSignatureJSON(sigs []signing.SignatureV2) ([]byte, error) {
|
2020-07-29 15:33:42 -07:00
|
|
|
descs := make([]*signing.SignatureDescriptor, len(sigs))
|
|
|
|
|
|
|
|
for i, sig := range sigs {
|
|
|
|
publicKey, err := g.pubkeyCodec.Encode(sig.PubKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
descData := signing.SignatureDataToProto(sig.Data)
|
|
|
|
|
|
|
|
descs[i] = &signing.SignatureDescriptor{
|
|
|
|
PublicKey: publicKey,
|
|
|
|
Data: descData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
toJSON := &signing.SignatureDescriptors{Signatures: descs}
|
|
|
|
|
|
|
|
return codec.ProtoMarshalJSON(toJSON)
|
|
|
|
}
|
|
|
|
|
2020-08-03 12:47:25 -07:00
|
|
|
func (g config) UnmarshalSignatureJSON(bz []byte) ([]signing.SignatureV2, error) {
|
2020-07-29 15:33:42 -07:00
|
|
|
var sigDescs signing.SignatureDescriptors
|
|
|
|
err := g.protoCodec.UnmarshalJSON(bz, &sigDescs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
sigs := make([]signing.SignatureV2, len(sigDescs.Signatures))
|
|
|
|
for i, desc := range sigDescs.Signatures {
|
|
|
|
pubKey, err := g.pubkeyCodec.Decode(desc.PublicKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
data := signing.SignatureDataFromProto(desc.Data)
|
|
|
|
|
|
|
|
sigs[i] = signing.SignatureV2{
|
2020-08-21 07:20:47 -07:00
|
|
|
PubKey: pubKey,
|
|
|
|
Data: data,
|
|
|
|
Sequence: desc.Sequence,
|
2020-07-29 15:33:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sigs, nil
|
|
|
|
}
|