2021-03-15 05:42:10 -07:00
|
|
|
package multisig
|
|
|
|
|
|
|
|
import (
|
|
|
|
types "github.com/cosmos/cosmos-sdk/codec/types"
|
|
|
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
|
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
// tmMultisig implements a K of N threshold multisig. It is used for
|
|
|
|
// Amino JSON marshaling of LegacyAminoPubKey (see below for details).
|
|
|
|
//
|
|
|
|
// This struct is copy-pasted from:
|
|
|
|
// https://github.com/tendermint/tendermint/blob/v0.33.9/crypto/multisig/threshold_pubkey.go
|
|
|
|
//
|
|
|
|
// This struct was used in the SDK <=0.39. In 0.40 and the switch to protobuf,
|
|
|
|
// it has been converted to LegacyAminoPubKey. However, there's one difference:
|
|
|
|
// the threshold field was an `uint` before, and an `uint32` after. This caused
|
|
|
|
// amino marshaling to be breaking: amino marshals `uint32` as a JSON number,
|
|
|
|
// and `uint` as a JSON string.
|
|
|
|
//
|
|
|
|
// In this file, we're overriding LegacyAminoPubKey's default JSON Amino
|
|
|
|
// marshaling by using this struct. Please note that we are NOT overriding the
|
|
|
|
// Amino binary marshaling, as that _might_ introduce breaking changes in the
|
|
|
|
// keyring, where multisigs are amino-binary-encoded.
|
|
|
|
//
|
|
|
|
// ref: https://github.com/cosmos/cosmos-sdk/issues/8776
|
|
|
|
type tmMultisig struct {
|
|
|
|
K uint `json:"threshold"`
|
|
|
|
PubKeys []cryptotypes.PubKey `json:"pubkeys"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// protoToTm converts a LegacyAminoPubKey into a tmMultisig.
|
|
|
|
func protoToTm(protoPk *LegacyAminoPubKey) (tmMultisig, error) {
|
|
|
|
var ok bool
|
|
|
|
pks := make([]cryptotypes.PubKey, len(protoPk.PubKeys))
|
|
|
|
for i, pk := range protoPk.PubKeys {
|
|
|
|
pks[i], ok = pk.GetCachedValue().(cryptotypes.PubKey)
|
|
|
|
if !ok {
|
|
|
|
return tmMultisig{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", (cryptotypes.PubKey)(nil), pk.GetCachedValue())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmMultisig{
|
|
|
|
K: uint(protoPk.Threshold),
|
|
|
|
PubKeys: pks,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// tmToProto converts a tmMultisig into a LegacyAminoPubKey.
|
|
|
|
func tmToProto(tmPk tmMultisig) (*LegacyAminoPubKey, error) {
|
|
|
|
var err error
|
|
|
|
pks := make([]*types.Any, len(tmPk.PubKeys))
|
|
|
|
for i, pk := range tmPk.PubKeys {
|
|
|
|
pks[i], err = types.NewAnyWithValue(pk)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &LegacyAminoPubKey{
|
|
|
|
Threshold: uint32(tmPk.K),
|
|
|
|
PubKeys: pks,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalAminoJSON overrides amino JSON unmarshaling.
|
2021-11-16 11:24:38 -08:00
|
|
|
func (m LegacyAminoPubKey) MarshalAminoJSON() (tmMultisig, error) { //nolint:golint,revive
|
2021-03-15 05:42:10 -07:00
|
|
|
return protoToTm(&m)
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalAminoJSON overrides amino JSON unmarshaling.
|
|
|
|
func (m *LegacyAminoPubKey) UnmarshalAminoJSON(tmPk tmMultisig) error {
|
|
|
|
protoPk, err := tmToProto(tmPk)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instead of just doing `*m = *protoPk`, we prefer to modify in-place the
|
|
|
|
// existing Anys inside `m` (instead of allocating new Anys), as so not to
|
|
|
|
// break the `.compat` fields in the existing Anys.
|
2021-11-10 02:07:40 -08:00
|
|
|
if m.PubKeys == nil {
|
|
|
|
m.PubKeys = make([]*types.Any, len(tmPk.PubKeys))
|
|
|
|
}
|
2021-03-15 05:42:10 -07:00
|
|
|
for i := range m.PubKeys {
|
2021-11-10 02:07:40 -08:00
|
|
|
if m.PubKeys[i] == nil {
|
|
|
|
// create the compat jsonBz value
|
|
|
|
bz, err := AminoCdc.MarshalJSON(tmPk.PubKeys[i])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
m.PubKeys[i] = protoPk.PubKeys[i]
|
|
|
|
// UnmarshalJSON():
|
|
|
|
// just sets the compat.jsonBz value.
|
|
|
|
// always succeeds: err == nil
|
|
|
|
if err := m.PubKeys[i].UnmarshalJSON(bz); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m.PubKeys[i].TypeUrl = protoPk.PubKeys[i].TypeUrl
|
|
|
|
m.PubKeys[i].Value = protoPk.PubKeys[i].Value
|
|
|
|
}
|
2021-03-15 05:42:10 -07:00
|
|
|
}
|
|
|
|
m.Threshold = protoPk.Threshold
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|