refactor(client/v2): offchain uses client/v2/factory (#22344)
Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
parent
62ddd3e939
commit
ed46a4c93a
@ -1,2 +1,2 @@
|
||||
codegen:
|
||||
@(cd internal; buf generate)
|
||||
@(cd internal; buf generate --template buf.gen.pulsar.yaml)
|
||||
5
client/v2/internal/buf.gen.gogo.yaml
Normal file
5
client/v2/internal/buf.gen.gogo.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
version: v1
|
||||
plugins:
|
||||
- name: gocosmos
|
||||
out: ..
|
||||
opt: plugins=grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/gogoproto/types/any
|
||||
@ -6,6 +6,8 @@ import "cosmos_proto/cosmos.proto";
|
||||
import "cosmos/msg/v1/msg.proto";
|
||||
import "amino/amino.proto";
|
||||
|
||||
option go_package = "cosmossdk.io/client/v2/offchain";
|
||||
|
||||
// MsgSignArbitraryData defines an arbitrary, general-purpose, off-chain message
|
||||
message MsgSignArbitraryData {
|
||||
option (amino.name) = "offchain/MsgSignArbitraryData";
|
||||
|
||||
@ -4287,27 +4287,27 @@ var file_testpb_msg_proto_rawDesc = []byte{
|
||||
0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x14, 0x0a, 0x12, 0x4d, 0x73, 0x67, 0x43,
|
||||
0x6c, 0x61, 0x77, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x15,
|
||||
0x0a, 0x13, 0x4d, 0x73, 0x67, 0x43, 0x6c, 0x61, 0x77, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xab, 0x01, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x47, 0x0a,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xac, 0x01, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x47, 0x0a,
|
||||
0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x4d,
|
||||
0x73, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74,
|
||||
0x70, 0x62, 0x2e, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16,
|
||||
0xca, 0xb4, 0x2d, 0x12, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x20, 0x76,
|
||||
0x30, 0x2e, 0x35, 0x30, 0x2e, 0x30, 0x12, 0x5b, 0x0a, 0x08, 0x43, 0x6c, 0x61, 0x77, 0x62, 0x61,
|
||||
0x30, 0x2e, 0x35, 0x30, 0x2e, 0x30, 0x12, 0x5c, 0x0a, 0x08, 0x43, 0x6c, 0x61, 0x77, 0x62, 0x61,
|
||||
0x63, 0x6b, 0x12, 0x1a, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x73, 0x67, 0x43,
|
||||
0x6c, 0x61, 0x77, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b,
|
||||
0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x4d, 0x73, 0x67, 0x43, 0x6c, 0x61, 0x77, 0x62,
|
||||
0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0xca, 0xb4, 0x2d,
|
||||
0x12, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x20, 0x76, 0x30, 0x2e, 0x35,
|
||||
0x31, 0x2e, 0x30, 0x42, 0x86, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x65, 0x73, 0x74,
|
||||
0x70, 0x62, 0x42, 0x08, 0x4d, 0x73, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x36,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f,
|
||||
0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x63, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x2f, 0x76, 0x32, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
||||
0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x54,
|
||||
0x65, 0x73, 0x74, 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xe2, 0x02,
|
||||
0x12, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64,
|
||||
0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0xca, 0xb4, 0x2d,
|
||||
0x13, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x20, 0x76, 0x30, 0x2e, 0x35,
|
||||
0x33, 0x2e, 0x30, 0x20, 0x42, 0x86, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x65, 0x73,
|
||||
0x74, 0x70, 0x62, 0x42, 0x08, 0x4d, 0x73, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
|
||||
0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d,
|
||||
0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x63, 0x6c,
|
||||
0x69, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x32, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
||||
0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x06,
|
||||
0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xe2,
|
||||
0x02, 0x12, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61,
|
||||
0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc (unknown)
|
||||
// source: testpb/msg.proto
|
||||
|
||||
@ -18,11 +18,6 @@ import (
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
Msg_Send_FullMethodName = "/testpb.Msg/Send"
|
||||
Msg_Clawback_FullMethodName = "/testpb.Msg/Clawback"
|
||||
)
|
||||
|
||||
// MsgClient is the client API for Msg service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
@ -42,7 +37,7 @@ func NewMsgClient(cc grpc.ClientConnInterface) MsgClient {
|
||||
|
||||
func (c *msgClient) Send(ctx context.Context, in *MsgRequest, opts ...grpc.CallOption) (*MsgResponse, error) {
|
||||
out := new(MsgResponse)
|
||||
err := c.cc.Invoke(ctx, Msg_Send_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/testpb.Msg/Send", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -51,7 +46,7 @@ func (c *msgClient) Send(ctx context.Context, in *MsgRequest, opts ...grpc.CallO
|
||||
|
||||
func (c *msgClient) Clawback(ctx context.Context, in *MsgClawbackRequest, opts ...grpc.CallOption) (*MsgClawbackResponse, error) {
|
||||
out := new(MsgClawbackResponse)
|
||||
err := c.cc.Invoke(ctx, Msg_Clawback_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/testpb.Msg/Clawback", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -101,7 +96,7 @@ func _Msg_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Msg_Send_FullMethodName,
|
||||
FullMethod: "/testpb.Msg/Send",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MsgServer).Send(ctx, req.(*MsgRequest))
|
||||
@ -119,7 +114,7 @@ func _Msg_Clawback_Handler(srv interface{}, ctx context.Context, dec func(interf
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Msg_Clawback_FullMethodName,
|
||||
FullMethod: "/testpb.Msg/Clawback",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MsgServer).Clawback(ctx, req.(*MsgClawbackRequest))
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc (unknown)
|
||||
// source: testpb/query.proto
|
||||
|
||||
@ -18,10 +18,6 @@ import (
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
Query_Echo_FullMethodName = "/testpb.Query/Echo"
|
||||
)
|
||||
|
||||
// QueryClient is the client API for Query service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
@ -40,7 +36,7 @@ func NewQueryClient(cc grpc.ClientConnInterface) QueryClient {
|
||||
|
||||
func (c *queryClient) Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) {
|
||||
out := new(EchoResponse)
|
||||
err := c.cc.Invoke(ctx, Query_Echo_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/testpb.Query/Echo", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -86,7 +82,7 @@ func _Query_Echo_Handler(srv interface{}, ctx context.Context, dec func(interfac
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Query_Echo_FullMethodName,
|
||||
FullMethod: "/testpb.Query/Echo",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(QueryServer).Echo(ctx, req.(*EchoRequest))
|
||||
|
||||
@ -1,318 +0,0 @@
|
||||
package offchain
|
||||
|
||||
// TODO: remove custom off-chain builder once v2 tx builder is developed.
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-proto/anyutil"
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
protov2 "google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
|
||||
basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
|
||||
apitx "cosmossdk.io/api/cosmos/tx/v1beta1"
|
||||
txsigning "cosmossdk.io/x/tx/signing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
)
|
||||
|
||||
type builder struct {
|
||||
cdc codec.Codec
|
||||
tx *apitx.Tx
|
||||
}
|
||||
|
||||
func newBuilder(cdc codec.Codec) *builder {
|
||||
return &builder{
|
||||
cdc: cdc,
|
||||
tx: &apitx.Tx{
|
||||
Body: &apitx.TxBody{},
|
||||
AuthInfo: &apitx.AuthInfo{
|
||||
Fee: &apitx.Fee{
|
||||
Amount: nil,
|
||||
GasLimit: 0,
|
||||
Payer: "",
|
||||
Granter: "",
|
||||
},
|
||||
},
|
||||
Signatures: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetTx returns the tx.
|
||||
func (b *builder) GetTx() *apitx.Tx {
|
||||
return b.tx
|
||||
}
|
||||
|
||||
// GetSigningTxData returns the necessary data to generate sign bytes.
|
||||
func (b *builder) GetSigningTxData() (txsigning.TxData, error) {
|
||||
body := b.tx.Body
|
||||
authInfo := b.tx.AuthInfo
|
||||
|
||||
msgs := make([]*anypb.Any, len(body.Messages))
|
||||
for i, msg := range body.Messages {
|
||||
msgs[i] = &anypb.Any{
|
||||
TypeUrl: msg.TypeUrl,
|
||||
Value: msg.Value,
|
||||
}
|
||||
}
|
||||
|
||||
extOptions := make([]*anypb.Any, len(body.ExtensionOptions))
|
||||
for i, extOption := range body.ExtensionOptions {
|
||||
extOptions[i] = &anypb.Any{
|
||||
TypeUrl: extOption.TypeUrl,
|
||||
Value: extOption.Value,
|
||||
}
|
||||
}
|
||||
|
||||
nonCriticalExtOptions := make([]*anypb.Any, len(body.NonCriticalExtensionOptions))
|
||||
for i, extOption := range body.NonCriticalExtensionOptions {
|
||||
nonCriticalExtOptions[i] = &anypb.Any{
|
||||
TypeUrl: extOption.TypeUrl,
|
||||
Value: extOption.Value,
|
||||
}
|
||||
}
|
||||
|
||||
feeCoins := authInfo.Fee.Amount
|
||||
feeAmount := make([]*basev1beta1.Coin, len(feeCoins))
|
||||
for i, coin := range feeCoins {
|
||||
feeAmount[i] = &basev1beta1.Coin{
|
||||
Denom: coin.Denom,
|
||||
Amount: coin.Amount,
|
||||
}
|
||||
}
|
||||
|
||||
txSignerInfos := make([]*apitx.SignerInfo, len(authInfo.SignerInfos))
|
||||
for i, signerInfo := range authInfo.SignerInfos {
|
||||
txSignerInfo := &apitx.SignerInfo{
|
||||
PublicKey: &anypb.Any{
|
||||
TypeUrl: signerInfo.PublicKey.TypeUrl,
|
||||
Value: signerInfo.PublicKey.Value,
|
||||
},
|
||||
Sequence: signerInfo.Sequence,
|
||||
ModeInfo: signerInfo.ModeInfo,
|
||||
}
|
||||
txSignerInfos[i] = txSignerInfo
|
||||
}
|
||||
|
||||
txAuthInfo := &apitx.AuthInfo{
|
||||
SignerInfos: txSignerInfos,
|
||||
Fee: &apitx.Fee{
|
||||
Amount: feeAmount,
|
||||
GasLimit: authInfo.Fee.GasLimit,
|
||||
Payer: authInfo.Fee.Payer,
|
||||
Granter: authInfo.Fee.Granter,
|
||||
},
|
||||
}
|
||||
|
||||
txBody := &apitx.TxBody{
|
||||
Messages: msgs,
|
||||
Memo: body.Memo,
|
||||
TimeoutHeight: body.TimeoutHeight,
|
||||
TimeoutTimestamp: body.TimeoutTimestamp,
|
||||
ExtensionOptions: extOptions,
|
||||
NonCriticalExtensionOptions: nonCriticalExtOptions,
|
||||
}
|
||||
authInfoBz, err := protov2.Marshal(b.tx.AuthInfo)
|
||||
if err != nil {
|
||||
return txsigning.TxData{}, err
|
||||
}
|
||||
bodyBz, err := protov2.Marshal(b.tx.Body)
|
||||
if err != nil {
|
||||
return txsigning.TxData{}, err
|
||||
}
|
||||
txData := txsigning.TxData{
|
||||
AuthInfo: txAuthInfo,
|
||||
AuthInfoBytes: authInfoBz,
|
||||
Body: txBody,
|
||||
BodyBytes: bodyBz,
|
||||
}
|
||||
return txData, nil
|
||||
}
|
||||
|
||||
// GetPubKeys returns the pubKeys of the tx.
|
||||
func (b *builder) GetPubKeys() ([]cryptotypes.PubKey, error) { // If signer already has pubkey in context, this list will have nil in its place
|
||||
signerInfos := b.tx.AuthInfo.SignerInfos
|
||||
pks := make([]cryptotypes.PubKey, len(signerInfos))
|
||||
|
||||
for i, si := range signerInfos {
|
||||
// NOTE: it is okay to leave this nil if there is no PubKey in the SignerInfo.
|
||||
// PubKey's can be left unset in SignerInfo.
|
||||
if si.PublicKey == nil {
|
||||
continue
|
||||
}
|
||||
var pk cryptotypes.PubKey
|
||||
anyPk := &codectypes.Any{
|
||||
TypeUrl: si.PublicKey.TypeUrl,
|
||||
Value: si.PublicKey.Value,
|
||||
}
|
||||
err := b.cdc.UnpackAny(anyPk, &pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pks[i] = pk
|
||||
}
|
||||
|
||||
return pks, nil
|
||||
}
|
||||
|
||||
// GetSignatures returns the signatures of the tx.
|
||||
func (b *builder) GetSignatures() ([]OffchainSignature, error) {
|
||||
signerInfos := b.tx.AuthInfo.SignerInfos
|
||||
sigs := b.tx.Signatures
|
||||
pubKeys, err := b.GetPubKeys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n := len(signerInfos)
|
||||
res := make([]OffchainSignature, n)
|
||||
|
||||
for i, si := range signerInfos {
|
||||
// handle nil signatures (in case of simulation)
|
||||
if si.ModeInfo == nil {
|
||||
res[i] = OffchainSignature{
|
||||
PubKey: pubKeys[i],
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
sigData, err := modeInfoAndSigToSignatureData(si.ModeInfo, sigs[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// sequence number is functionally a transaction nonce and referred to as such in the SDK
|
||||
nonce := si.GetSequence()
|
||||
res[i] = OffchainSignature{
|
||||
PubKey: pubKeys[i],
|
||||
Data: sigData,
|
||||
Sequence: nonce,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetSigners returns the signers of the tx.
|
||||
func (b *builder) GetSigners() ([][]byte, error) {
|
||||
signers, _, err := b.getSigners()
|
||||
return signers, err
|
||||
}
|
||||
|
||||
func (b *builder) getSigners() ([][]byte, []protov2.Message, error) {
|
||||
var signers [][]byte
|
||||
seen := map[string]bool{}
|
||||
|
||||
var msgsv2 []protov2.Message
|
||||
for _, msg := range b.tx.Body.Messages {
|
||||
msgv2, err := anyutil.Unpack(msg, b.cdc.InterfaceRegistry(), nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
xs, err := b.cdc.InterfaceRegistry().SigningContext().GetSigners(msgv2)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
msgsv2 = append(msgsv2, msg)
|
||||
|
||||
for _, signer := range xs {
|
||||
if !seen[string(signer)] {
|
||||
signers = append(signers, signer)
|
||||
seen[string(signer)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return signers, msgsv2, nil
|
||||
}
|
||||
|
||||
func (b *builder) setMsgs(msgs ...proto.Message) error {
|
||||
anys := make([]*anypb.Any, len(msgs))
|
||||
for i, msg := range msgs {
|
||||
protoMsg, ok := msg.(protov2.Message)
|
||||
if !ok {
|
||||
return errors.New("message is not a proto.Message")
|
||||
}
|
||||
protov2MarshalOpts := protov2.MarshalOptions{Deterministic: true}
|
||||
bz, err := protov2MarshalOpts.Marshal(protoMsg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
anys[i] = &anypb.Any{
|
||||
TypeUrl: codectypes.MsgTypeURL(msg),
|
||||
Value: bz,
|
||||
}
|
||||
}
|
||||
b.tx.Body.Messages = anys
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSignatures set the signatures of the tx.
|
||||
func (b *builder) SetSignatures(signatures ...OffchainSignature) error {
|
||||
n := len(signatures)
|
||||
signerInfos := make([]*apitx.SignerInfo, n)
|
||||
rawSigs := make([][]byte, n)
|
||||
var err error
|
||||
for i, sig := range signatures {
|
||||
var mi *apitx.ModeInfo
|
||||
mi, rawSigs[i], err = b.signatureDataToModeInfoAndSig(sig.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pubKey, err := codectypes.NewAnyWithValue(sig.PubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
signerInfos[i] = &apitx.SignerInfo{
|
||||
PublicKey: &anypb.Any{
|
||||
TypeUrl: pubKey.TypeUrl,
|
||||
Value: pubKey.Value,
|
||||
},
|
||||
ModeInfo: mi,
|
||||
Sequence: sig.Sequence,
|
||||
}
|
||||
}
|
||||
|
||||
b.tx.AuthInfo.SignerInfos = signerInfos
|
||||
b.tx.Signatures = rawSigs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// signatureDataToModeInfoAndSig converts a SignatureData to a ModeInfo and raw bytes signature.
|
||||
func (b *builder) signatureDataToModeInfoAndSig(data SignatureData) (*apitx.ModeInfo, []byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil, errors.New("empty SignatureData")
|
||||
}
|
||||
|
||||
switch data := data.(type) {
|
||||
case *SingleSignatureData:
|
||||
return &apitx.ModeInfo{
|
||||
Sum: &apitx.ModeInfo_Single_{
|
||||
Single: &apitx.ModeInfo_Single{Mode: data.SignMode},
|
||||
},
|
||||
}, data.Signature, nil
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unexpected signature data type %T", data)
|
||||
}
|
||||
}
|
||||
|
||||
// modeInfoAndSigToSignatureData converts a ModeInfo and raw bytes signature to a SignatureData.
|
||||
func modeInfoAndSigToSignatureData(modeInfo *apitx.ModeInfo, sig []byte) (SignatureData, error) {
|
||||
switch modeInfoType := modeInfo.Sum.(type) {
|
||||
case *apitx.ModeInfo_Single_:
|
||||
return &SingleSignatureData{
|
||||
SignMode: modeInfoType.Single.Mode,
|
||||
Signature: sig,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected ModeInfo data type %T", modeInfo)
|
||||
}
|
||||
}
|
||||
@ -13,10 +13,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
flagNotEmitUnpopulated = "notEmitUnpopulated"
|
||||
flagIndent = "indent"
|
||||
flagEncoding = "encoding"
|
||||
flagFileFormat = "file-format"
|
||||
flagEncoding = "encoding"
|
||||
flagFileFormat = "file-format"
|
||||
)
|
||||
|
||||
// OffChain off-chain utilities.
|
||||
@ -51,13 +49,12 @@ func SignFile() *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
notEmitUnpopulated, _ := cmd.Flags().GetBool(flagNotEmitUnpopulated)
|
||||
indent, _ := cmd.Flags().GetString(flagIndent)
|
||||
encoding, _ := cmd.Flags().GetString(flagEncoding)
|
||||
outputFormat, _ := cmd.Flags().GetString(v2flags.FlagOutput)
|
||||
outputFile, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
|
||||
signMode, _ := cmd.Flags().GetString(flags.FlagSignMode)
|
||||
|
||||
signedTx, err := Sign(clientCtx, bz, args[0], indent, encoding, outputFormat, !notEmitUnpopulated)
|
||||
signedTx, err := Sign(clientCtx, bz, args[0], encoding, signMode, outputFormat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -75,28 +72,27 @@ func SignFile() *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagIndent, " ", "Choose an indent for the tx")
|
||||
cmd.Flags().String(v2flags.FlagOutput, "json", "Choose an output format for the tx (json|text")
|
||||
cmd.Flags().Bool(flagNotEmitUnpopulated, false, "Don't show unpopulated fields in the tx")
|
||||
cmd.Flags().String(flagEncoding, "no-encoding", "Choose an encoding method for the file content to be added as msg data (no-encoding|base64|hex)")
|
||||
cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT")
|
||||
cmd.PersistentFlags().String(flags.FlagSignMode, "direct", "Choose sign mode (direct|amino-json)")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// VerifyFile verifies given file with given key.
|
||||
func VerifyFile() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "verify-file <keyName> <fileName>",
|
||||
Use: "verify-file <signedFileName>",
|
||||
Short: "Verify a file.",
|
||||
Long: "Verify a previously signed file with the given key.",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bz, err := os.ReadFile(args[1])
|
||||
bz, err := os.ReadFile(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -42,3 +42,12 @@ func getEncoder(encoder string) (encodingFunc, error) {
|
||||
return nil, fmt.Errorf("unknown encoder: %s", encoder)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeDigest(encodingFormat string, digest []byte) (string, error) {
|
||||
encoder, err := getEncoder(encodingFormat)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return encoder(digest)
|
||||
}
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
package offchain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
apitx "cosmossdk.io/api/cosmos/tx/v1beta1"
|
||||
v2flags "cosmossdk.io/client/v2/internal/flags"
|
||||
)
|
||||
|
||||
// marshaller marshals Messages.
|
||||
type marshaller interface {
|
||||
Marshal(message proto.Message) ([]byte, error)
|
||||
}
|
||||
|
||||
// getMarshaller returns the marshaller for the given marshaller id.
|
||||
func getMarshaller(marshallerId, indent string, emitUnpopulated bool) (marshaller, error) {
|
||||
switch marshallerId {
|
||||
case v2flags.OutputFormatJSON:
|
||||
return protojson.MarshalOptions{
|
||||
Indent: indent,
|
||||
EmitUnpopulated: emitUnpopulated,
|
||||
}, nil
|
||||
case v2flags.OutputFormatText:
|
||||
return prototext.MarshalOptions{
|
||||
Indent: indent,
|
||||
EmitUnknown: emitUnpopulated,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("marshaller with id '%s' not identified", marshallerId)
|
||||
}
|
||||
|
||||
// marshalOffChainTx marshals a Tx using given marshaller.
|
||||
func marshalOffChainTx(tx *apitx.Tx, marshaller marshaller) (string, error) {
|
||||
bytesTx, err := marshaller.Marshal(tx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytesTx), nil
|
||||
}
|
||||
432
client/v2/offchain/msgSignArbitraryData.pb.go
Normal file
432
client/v2/offchain/msgSignArbitraryData.pb.go
Normal file
@ -0,0 +1,432 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: offchain/msgSignArbitraryData.proto
|
||||
|
||||
package offchain
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/cosmos/cosmos-proto"
|
||||
_ "github.com/cosmos/cosmos-sdk/types/msgservice"
|
||||
_ "github.com/cosmos/cosmos-sdk/types/tx/amino"
|
||||
proto "github.com/cosmos/gogoproto/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// MsgSignArbitraryData defines an arbitrary, general-purpose, off-chain message
|
||||
type MsgSignArbitraryData struct {
|
||||
// AppDomain is the application requesting off-chain message signing
|
||||
AppDomain string `protobuf:"bytes,1,opt,name=app_domain,json=appDomain,proto3" json:"app_domain,omitempty"`
|
||||
// Signer is the sdk.AccAddress of the message signer
|
||||
Signer string `protobuf:"bytes,2,opt,name=signer,proto3" json:"signer,omitempty"`
|
||||
// Data represents the raw bytes of the content that is signed (text, json, etc)
|
||||
Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (m *MsgSignArbitraryData) Reset() { *m = MsgSignArbitraryData{} }
|
||||
func (m *MsgSignArbitraryData) String() string { return proto.CompactTextString(m) }
|
||||
func (*MsgSignArbitraryData) ProtoMessage() {}
|
||||
func (*MsgSignArbitraryData) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f3e1b1b538b29252, []int{0}
|
||||
}
|
||||
func (m *MsgSignArbitraryData) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *MsgSignArbitraryData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_MsgSignArbitraryData.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *MsgSignArbitraryData) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_MsgSignArbitraryData.Merge(m, src)
|
||||
}
|
||||
func (m *MsgSignArbitraryData) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *MsgSignArbitraryData) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_MsgSignArbitraryData.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_MsgSignArbitraryData proto.InternalMessageInfo
|
||||
|
||||
func (m *MsgSignArbitraryData) GetAppDomain() string {
|
||||
if m != nil {
|
||||
return m.AppDomain
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *MsgSignArbitraryData) GetSigner() string {
|
||||
if m != nil {
|
||||
return m.Signer
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *MsgSignArbitraryData) GetData() string {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*MsgSignArbitraryData)(nil), "offchain.MsgSignArbitraryData")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("offchain/msgSignArbitraryData.proto", fileDescriptor_f3e1b1b538b29252)
|
||||
}
|
||||
|
||||
var fileDescriptor_f3e1b1b538b29252 = []byte{
|
||||
// 267 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xce, 0x4f, 0x4b, 0x4b,
|
||||
0xce, 0x48, 0xcc, 0xcc, 0xd3, 0xcf, 0x2d, 0x4e, 0x0f, 0xce, 0x4c, 0xcf, 0x73, 0x2c, 0x4a, 0xca,
|
||||
0x2c, 0x29, 0x4a, 0x2c, 0xaa, 0x74, 0x49, 0x2c, 0x49, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
|
||||
0xe2, 0x80, 0x29, 0x92, 0x92, 0x4c, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0x8e, 0x07, 0x8b, 0xeb, 0x43,
|
||||
0x38, 0x10, 0x45, 0x52, 0xe2, 0x10, 0x1e, 0xc8, 0x1c, 0xfd, 0x32, 0x43, 0x10, 0x05, 0x95, 0x10,
|
||||
0x4c, 0xcc, 0xcd, 0xcc, 0xcb, 0xd7, 0x07, 0x93, 0x10, 0x21, 0xa5, 0x55, 0x8c, 0x5c, 0x22, 0xbe,
|
||||
0x58, 0xec, 0x13, 0x92, 0xe5, 0xe2, 0x4a, 0x2c, 0x28, 0x88, 0x4f, 0xc9, 0xcf, 0x4d, 0xcc, 0xcc,
|
||||
0x93, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0xe2, 0x4c, 0x2c, 0x28, 0x70, 0x01, 0x0b, 0x08, 0x19,
|
||||
0x70, 0xb1, 0x15, 0x67, 0xa6, 0xe7, 0xa5, 0x16, 0x49, 0x30, 0x81, 0xa4, 0x9c, 0x24, 0x2e, 0x6d,
|
||||
0xd1, 0x15, 0x81, 0xba, 0xc2, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb8, 0xa4, 0x28, 0x33,
|
||||
0x2f, 0x3d, 0x08, 0xaa, 0x4e, 0x48, 0x88, 0x8b, 0x25, 0x25, 0xb1, 0x24, 0x51, 0x82, 0x19, 0x6c,
|
||||
0x14, 0x98, 0x6d, 0xa5, 0xdb, 0xf4, 0x7c, 0x83, 0x16, 0x54, 0x41, 0xd7, 0xf3, 0x0d, 0x5a, 0xb2,
|
||||
0xf0, 0x30, 0xc0, 0xe6, 0x26, 0x27, 0xcb, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c,
|
||||
0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63,
|
||||
0x88, 0x92, 0x87, 0x58, 0x5d, 0x9c, 0x92, 0xad, 0x97, 0x99, 0xaf, 0x9f, 0x9c, 0x93, 0x99, 0x9a,
|
||||
0x57, 0xa2, 0x5f, 0x66, 0xa4, 0x0f, 0x33, 0x2f, 0x89, 0x0d, 0xec, 0x5d, 0x63, 0x40, 0x00, 0x00,
|
||||
0x00, 0xff, 0xff, 0x78, 0x04, 0xe8, 0x80, 0x66, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *MsgSignArbitraryData) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *MsgSignArbitraryData) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *MsgSignArbitraryData) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Data) > 0 {
|
||||
i -= len(m.Data)
|
||||
copy(dAtA[i:], m.Data)
|
||||
i = encodeVarintMsgSignArbitraryData(dAtA, i, uint64(len(m.Data)))
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
}
|
||||
if len(m.Signer) > 0 {
|
||||
i -= len(m.Signer)
|
||||
copy(dAtA[i:], m.Signer)
|
||||
i = encodeVarintMsgSignArbitraryData(dAtA, i, uint64(len(m.Signer)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if len(m.AppDomain) > 0 {
|
||||
i -= len(m.AppDomain)
|
||||
copy(dAtA[i:], m.AppDomain)
|
||||
i = encodeVarintMsgSignArbitraryData(dAtA, i, uint64(len(m.AppDomain)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintMsgSignArbitraryData(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovMsgSignArbitraryData(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *MsgSignArbitraryData) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.AppDomain)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovMsgSignArbitraryData(uint64(l))
|
||||
}
|
||||
l = len(m.Signer)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovMsgSignArbitraryData(uint64(l))
|
||||
}
|
||||
l = len(m.Data)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovMsgSignArbitraryData(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovMsgSignArbitraryData(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozMsgSignArbitraryData(x uint64) (n int) {
|
||||
return sovMsgSignArbitraryData(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *MsgSignArbitraryData) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMsgSignArbitraryData
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: MsgSignArbitraryData: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: MsgSignArbitraryData: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AppDomain", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMsgSignArbitraryData
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AppDomain = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMsgSignArbitraryData
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Signer = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowMsgSignArbitraryData
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Data = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipMsgSignArbitraryData(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipMsgSignArbitraryData(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowMsgSignArbitraryData
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowMsgSignArbitraryData
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowMsgSignArbitraryData
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupMsgSignArbitraryData
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthMsgSignArbitraryData
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthMsgSignArbitraryData = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowMsgSignArbitraryData = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupMsgSignArbitraryData = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
@ -2,18 +2,15 @@ package offchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
"fmt"
|
||||
|
||||
apisigning "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
|
||||
apitx "cosmossdk.io/api/cosmos/tx/v1beta1"
|
||||
"cosmossdk.io/client/v2/internal/account"
|
||||
"cosmossdk.io/client/v2/internal/offchain"
|
||||
txsigning "cosmossdk.io/x/tx/signing"
|
||||
clitx "cosmossdk.io/client/v2/tx"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
)
|
||||
|
||||
@ -24,58 +21,64 @@ const (
|
||||
ExpectedAccountNumber = 0
|
||||
// ExpectedSequence defines the sequence number an off-chain message must have
|
||||
ExpectedSequence = 0
|
||||
|
||||
signMode = apisigning.SignMode_SIGN_MODE_TEXTUAL
|
||||
)
|
||||
|
||||
type signerData struct {
|
||||
Address string
|
||||
ChainID string
|
||||
AccountNumber uint64
|
||||
Sequence uint64
|
||||
PubKey cryptotypes.PubKey
|
||||
var enabledSignModes = []apisigning.SignMode{
|
||||
apisigning.SignMode_SIGN_MODE_DIRECT,
|
||||
apisigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
|
||||
}
|
||||
|
||||
// Sign signs given bytes using the specified encoder and SignMode.
|
||||
func Sign(ctx client.Context, rawBytes []byte, fromName, indent, encoding, output string, emitUnpopulated bool) (string, error) {
|
||||
encoder, err := getEncoder(encoding)
|
||||
func Sign(ctx client.Context, rawBytes []byte, fromName, encoding, signMode, output string) (string, error) {
|
||||
digest, err := encodeDigest(encoding, rawBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
digest, err := encoder(rawBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tx, err := sign(ctx, fromName, digest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
txMarshaller, err := getMarshaller(output, indent, emitUnpopulated)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return marshalOffChainTx(tx, txMarshaller)
|
||||
}
|
||||
|
||||
// sign signs a digest with provided key and SignMode.
|
||||
func sign(ctx client.Context, fromName, digest string) (*apitx.Tx, error) {
|
||||
keybase, err := keyring.NewAutoCLIKeyring(ctx.Keyring, ctx.AddressCodec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
txConfig, err := clitx.NewTxConfig(clitx.ConfigOptions{
|
||||
AddressCodec: ctx.AddressCodec,
|
||||
Cdc: ctx.Codec,
|
||||
ValidatorAddressCodec: ctx.ValidatorAddressCodec,
|
||||
EnabledSignModes: enabledSignModes,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
accRetriever := account.NewAccountRetriever(ctx.AddressCodec, ctx, ctx.InterfaceRegistry)
|
||||
|
||||
sm, err := getSignMode(signMode)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
params := clitx.TxParameters{
|
||||
ChainID: ExpectedChainID,
|
||||
SignMode: sm,
|
||||
AccountConfig: clitx.AccountConfig{
|
||||
AccountNumber: ExpectedAccountNumber,
|
||||
Sequence: ExpectedSequence,
|
||||
FromName: fromName,
|
||||
},
|
||||
}
|
||||
|
||||
txf, err := clitx.NewFactory(keybase, ctx.Codec, accRetriever, txConfig, ctx.AddressCodec, ctx, params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
pubKey, err := keybase.GetPubKey(fromName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
addr, err := ctx.AddressCodec.BytesToString(pubKey.Address())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
msg := &offchain.MsgSignArbitraryData{
|
||||
@ -84,84 +87,38 @@ func sign(ctx client.Context, fromName, digest string) (*apitx.Tx, error) {
|
||||
Data: digest,
|
||||
}
|
||||
|
||||
txBuilder := newBuilder(ctx.Codec)
|
||||
err = txBuilder.setMsgs(msg)
|
||||
signedTx, err := txf.BuildsSignedTx(context.Background(), msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
signerData := signerData{
|
||||
Address: addr,
|
||||
ChainID: ExpectedChainID,
|
||||
AccountNumber: ExpectedAccountNumber,
|
||||
Sequence: ExpectedSequence,
|
||||
PubKey: pubKey,
|
||||
}
|
||||
|
||||
sigData := &SingleSignatureData{
|
||||
SignMode: signMode,
|
||||
Signature: nil,
|
||||
}
|
||||
|
||||
sig := OffchainSignature{
|
||||
PubKey: pubKey,
|
||||
Data: sigData,
|
||||
Sequence: ExpectedSequence,
|
||||
}
|
||||
|
||||
sigs := []OffchainSignature{sig}
|
||||
err = txBuilder.SetSignatures(sigs...)
|
||||
bz, err := encode(output, signedTx, txConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
bytesToSign, err := getSignBytes(
|
||||
context.Background(), ctx.TxConfig.SignModeHandler(), signerData, txBuilder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signedBytes, err := keybase.Sign(fromName, bytesToSign, signMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sigData.Signature = signedBytes
|
||||
|
||||
err = txBuilder.SetSignatures(sig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return txBuilder.GetTx(), nil
|
||||
return string(bz), nil
|
||||
}
|
||||
|
||||
// getSignBytes gets the bytes to be signed for the given Tx and SignMode.
|
||||
func getSignBytes(ctx context.Context,
|
||||
handlerMap *txsigning.HandlerMap,
|
||||
signerData signerData,
|
||||
tx *builder,
|
||||
) ([]byte, error) {
|
||||
txData, err := tx.GetSigningTxData()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func encode(output string, tx clitx.Tx, config clitx.TxConfig) ([]byte, error) {
|
||||
switch output {
|
||||
case "json":
|
||||
return config.TxJSONEncoder()(tx)
|
||||
case "text":
|
||||
return config.TxTextEncoder()(tx)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported output type: %s", output)
|
||||
}
|
||||
|
||||
anyPk, err := codectypes.NewAnyWithValue(signerData.PubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txSignerData := txsigning.SignerData{
|
||||
ChainID: signerData.ChainID,
|
||||
AccountNumber: signerData.AccountNumber,
|
||||
Sequence: signerData.Sequence,
|
||||
Address: signerData.Address,
|
||||
PubKey: &anypb.Any{
|
||||
TypeUrl: anyPk.TypeUrl,
|
||||
Value: anyPk.Value,
|
||||
},
|
||||
}
|
||||
|
||||
return handlerMap.GetSignBytes(ctx, signMode, txSignerData, txData)
|
||||
}
|
||||
|
||||
// getSignMode returns the corresponding apisigning.SignMode based on the provided mode string.
|
||||
func getSignMode(mode string) (apisigning.SignMode, error) {
|
||||
switch mode {
|
||||
case "direct":
|
||||
return apisigning.SignMode_SIGN_MODE_DIRECT, nil
|
||||
case "amino-json":
|
||||
return apisigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, nil
|
||||
}
|
||||
|
||||
return apisigning.SignMode_SIGN_MODE_UNSPECIFIED, fmt.Errorf("unsupported sign mode: %s", mode)
|
||||
}
|
||||
|
||||
@ -11,41 +11,54 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
)
|
||||
|
||||
func Test_sign(t *testing.T) {
|
||||
func TestSign(t *testing.T) {
|
||||
k := keyring.NewInMemory(getCodec())
|
||||
_, err := k.NewAccount("signVerify", mnemonic, "", "m/44'/118'/0'/0/0", hd.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := client.Context{
|
||||
Keyring: k,
|
||||
TxConfig: newTestConfig(t),
|
||||
AddressCodec: address.NewBech32Codec("cosmos"),
|
||||
}
|
||||
|
||||
type args struct {
|
||||
ctx client.Context
|
||||
fromName string
|
||||
digest string
|
||||
TxConfig: newTestConfig(t),
|
||||
Codec: getCodec(),
|
||||
AddressCodec: address.NewBech32Codec("cosmos"),
|
||||
ValidatorAddressCodec: address.NewBech32Codec("cosmosvaloper"),
|
||||
Keyring: k,
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
name string
|
||||
rawBytes []byte
|
||||
encoding string
|
||||
signMode string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Sign",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
fromName: "direct",
|
||||
digest: "Hello world!",
|
||||
},
|
||||
name: "sign direct",
|
||||
rawBytes: []byte("hello world"),
|
||||
encoding: noEncoder,
|
||||
signMode: "direct",
|
||||
},
|
||||
{
|
||||
name: "sign amino",
|
||||
rawBytes: []byte("hello world"),
|
||||
encoding: noEncoder,
|
||||
signMode: "amino-json",
|
||||
},
|
||||
{
|
||||
name: "not supported sign mode",
|
||||
rawBytes: []byte("hello world"),
|
||||
encoding: noEncoder,
|
||||
signMode: "textual",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := k.NewAccount(tt.args.fromName, mnemonic, tt.name, "m/44'/118'/0'/0/0", hd.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := sign(tt.args.ctx, tt.args.fromName, tt.args.digest)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, got)
|
||||
got, err := Sign(ctx, tt.rawBytes, "signVerify", tt.encoding, tt.signMode, "json")
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
package offchain
|
||||
|
||||
import (
|
||||
apitxsigning "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
)
|
||||
|
||||
type SignatureData interface {
|
||||
isSignatureData()
|
||||
}
|
||||
|
||||
func (m *SingleSignatureData) isSignatureData() {}
|
||||
|
||||
type SingleSignatureData struct {
|
||||
// SignMode represents the SignMode of the signature
|
||||
SignMode apitxsigning.SignMode
|
||||
|
||||
// Signature is the raw signature.
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
type OffchainSignature struct {
|
||||
// PubKey is the public key to use for verifying the signature
|
||||
PubKey cryptotypes.PubKey
|
||||
|
||||
// Data is the actual data of the signature which includes SignMode's and
|
||||
// the signatures themselves for either single or multi-signatures.
|
||||
Data SignatureData
|
||||
|
||||
// Sequence is the sequence of this account. Only populated in
|
||||
// SIGN_MODE_DIRECT.
|
||||
Sequence uint64
|
||||
}
|
||||
@ -6,12 +6,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
|
||||
apitx "cosmossdk.io/api/cosmos/tx/v1beta1"
|
||||
v2flags "cosmossdk.io/client/v2/internal/flags"
|
||||
clitx "cosmossdk.io/client/v2/tx"
|
||||
txsigning "cosmossdk.io/x/tx/signing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
@ -21,29 +18,34 @@ import (
|
||||
|
||||
// Verify verifies a digest after unmarshalling it.
|
||||
func Verify(ctx client.Context, digest []byte, fileFormat string) error {
|
||||
tx, err := unmarshal(digest, fileFormat)
|
||||
txConfig, err := clitx.NewTxConfig(clitx.ConfigOptions{
|
||||
AddressCodec: ctx.AddressCodec,
|
||||
Cdc: ctx.Codec,
|
||||
ValidatorAddressCodec: ctx.ValidatorAddressCodec,
|
||||
EnabledSignModes: enabledSignModes,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return verify(ctx, tx)
|
||||
dTx, err := unmarshal(fileFormat, digest, txConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return verify(ctx, dTx)
|
||||
}
|
||||
|
||||
// verify verifies given Tx.
|
||||
func verify(ctx client.Context, tx *apitx.Tx) error {
|
||||
sigTx := builder{
|
||||
cdc: ctx.Codec,
|
||||
tx: tx,
|
||||
}
|
||||
|
||||
func verify(ctx client.Context, dTx clitx.Tx) error {
|
||||
signModeHandler := ctx.TxConfig.SignModeHandler()
|
||||
|
||||
signers, err := sigTx.GetSigners()
|
||||
signers, err := dTx.GetSigners()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sigs, err := sigTx.GetSignatures()
|
||||
sigs, err := dTx.GetSignatures()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -79,7 +81,7 @@ func verify(ctx client.Context, tx *apitx.Tx) error {
|
||||
},
|
||||
}
|
||||
|
||||
txData, err := sigTx.GetSigningTxData()
|
||||
txData, err := dTx.GetSigningTxData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -93,18 +95,15 @@ func verify(ctx client.Context, tx *apitx.Tx) error {
|
||||
}
|
||||
|
||||
// unmarshal unmarshalls a digest to a Tx using protobuf protojson.
|
||||
func unmarshal(digest []byte, fileFormat string) (*apitx.Tx, error) {
|
||||
var err error
|
||||
tx := &apitx.Tx{}
|
||||
switch fileFormat {
|
||||
case v2flags.OutputFormatJSON:
|
||||
err = protojson.Unmarshal(digest, tx)
|
||||
case v2flags.OutputFormatText:
|
||||
err = prototext.Unmarshal(digest, tx)
|
||||
func unmarshal(format string, bz []byte, config clitx.TxConfig) (clitx.Tx, error) {
|
||||
switch format {
|
||||
case "json":
|
||||
return config.TxJSONDecoder()(bz)
|
||||
case "text":
|
||||
return config.TxTextDecoder()(bz)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported file format: %s", fileFormat)
|
||||
return nil, fmt.Errorf("unsupported format: %s", format)
|
||||
}
|
||||
return tx, err
|
||||
}
|
||||
|
||||
// verifySignature verifies a transaction signature contained in SignatureData abstracting over different signing modes.
|
||||
@ -112,12 +111,12 @@ func verifySignature(
|
||||
ctx context.Context,
|
||||
pubKey cryptotypes.PubKey,
|
||||
signerData txsigning.SignerData,
|
||||
signatureData SignatureData,
|
||||
signatureData clitx.SignatureData,
|
||||
handler *txsigning.HandlerMap,
|
||||
txData txsigning.TxData,
|
||||
) error {
|
||||
switch data := signatureData.(type) {
|
||||
case *SingleSignatureData:
|
||||
case *clitx.SingleSignatureData:
|
||||
signBytes, err := handler.GetSignBytes(ctx, data.SignMode, signerData, txData)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
_ "cosmossdk.io/api/cosmos/crypto/secp256k1"
|
||||
clitx "cosmossdk.io/client/v2/tx"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec/address"
|
||||
@ -15,9 +16,10 @@ import (
|
||||
|
||||
func Test_Verify(t *testing.T) {
|
||||
ctx := client.Context{
|
||||
TxConfig: newTestConfig(t),
|
||||
Codec: getCodec(),
|
||||
AddressCodec: address.NewBech32Codec("cosmos"),
|
||||
TxConfig: newTestConfig(t),
|
||||
Codec: getCodec(),
|
||||
AddressCodec: address.NewBech32Codec("cosmos"),
|
||||
ValidatorAddressCodec: address.NewBech32Codec("cosmosvaloper"),
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@ -29,26 +31,26 @@ func Test_Verify(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "verify json",
|
||||
digest: []byte("{\"body\":{\"messages\":[{\"@type\":\"/offchain.MsgSignArbitraryData\", \"appDomain\":\"simd\", \"signer\":\"cosmos1x33fy6rusfprkntvjsfregss7rvsvyy4lkwrqu\", \"data\":\"{\\n\\t\\\"name\\\": \\\"John\\\",\\n\\t\\\"surname\\\": \\\"Connor\\\",\\n\\t\\\"age\\\": 15\\n}\\n\"}]}, \"authInfo\":{\"signerInfos\":[{\"publicKey\":{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\", \"key\":\"A/Bfsb7grZtysreo48oB1XAXbcgHnEJyhAqzDMgbLlXw\"}, \"modeInfo\":{\"single\":{\"mode\":\"SIGN_MODE_TEXTUAL\"}}}], \"fee\":{}}, \"signatures\":[\"gRufjcmATaJ3hZSiXII3lcsLDJlHM4OhQs3O/QgAK4weQ73kmj30/gw3HwTKxGb4pnVe0iyLXrKRNeSl1O3zSQ==\"]}"),
|
||||
digest: []byte("{\"body\":{\"messages\":[{\"@type\":\"/offchain.MsgSignArbitraryData\", \"app_domain\":\"<appd>\", \"signer\":\"cosmos16877zjk85kwlap3wclpmx34e0xllg2erc7u7m4\", \"data\":\"{\\n\\t\\\"name\\\": \\\"Sarah\\\",\\n\\t\\\"surname\\\": \\\"Connor\\\",\\n\\t\\\"age\\\": 29\\n}\\n\"}], \"timeout_timestamp\":\"0001-01-01T00:00:00Z\"}, \"auth_info\":{\"signer_infos\":[{\"public_key\":{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\", \"key\":\"Ahhu3idSSUAQXtDBvBjUlCPWH3od4rXyWgb7L4scSj4m\"}, \"mode_info\":{\"single\":{\"mode\":\"SIGN_MODE_DIRECT\"}}}], \"fee\":{}}, \"signatures\":[\"tdXsO5uNqIBFSBKEA1e3Wrcb6ejriP9HwlcBTkU7EUJzuezjg6Rvr1a+Kp6umCAN7MWoBHRT2cmqzDfg6RjaYA==\"]}"),
|
||||
fileFormat: "json",
|
||||
ctx: ctx,
|
||||
},
|
||||
{
|
||||
name: "wrong signer json",
|
||||
digest: []byte("{\"body\":{\"messages\":[{\"@type\":\"/offchain.MsgSignArbitraryData\", \"appDomain\":\"simd\", \"signer\":\"cosmos1450l4uau674z55c36df0v7904rnvdk9aq8w96j\", \"data\":\"{\\n\\t\\\"name\\\": \\\"John\\\",\\n\\t\\\"surname\\\": \\\"Connor\\\",\\n\\t\\\"age\\\": 15\\n}\\n\"}]}, \"authInfo\":{\"signerInfos\":[{\"publicKey\":{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\", \"key\":\"A/Bfsb7grZtysreo48oB1XAXbcgHnEJyhAqzDMgbLlXw\"}, \"modeInfo\":{\"single\":{\"mode\":\"SIGN_MODE_TEXTUAL\"}}}], \"fee\":{}}, \"signatures\":[\"gRufjcmATaJ3hZSiXII3lcsLDJlHM4OhQs3O/QgAK4weQ73kmj30/gw3HwTKxGb4pnVe0iyLXrKRNeSl1O3zSQ==\"]}"),
|
||||
digest: []byte("{\"body\":{\"messages\":[{\"@type\":\"/offchain.MsgSignArbitraryData\", \"app_domain\":\"<appd>\", \"signer\":\"cosmos1xv9e39mkhhyg5aneu2myj82t7029sv48qu3pgj\", \"data\":\"{\\n\\t\\\"name\\\": \\\"Sarah\\\",\\n\\t\\\"surname\\\": \\\"Connor\\\",\\n\\t\\\"age\\\": 29\\n}\\n\"}], \"timeout_timestamp\":\"0001-01-01T00:00:00Z\"}, \"auth_info\":{\"signer_infos\":[{\"public_key\":{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\", \"key\":\"Ahhu3idSSUAQXtDBvBjUlCPWH3od4rXyWgb7L4scSj4m\"}, \"mode_info\":{\"single\":{\"mode\":\"SIGN_MODE_DIRECT\"}}}], \"fee\":{}}, \"signatures\":[\"tdXsO5uNqIBFSBKEA1e3Wrcb6ejriP9HwlcBTkU7EUJzuezjg6Rvr1a+Kp6umCAN7MWoBHRT2cmqzDfg6RjaYA==\"]}"),
|
||||
fileFormat: "json",
|
||||
ctx: ctx,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "verify text",
|
||||
digest: []byte("body:{messages:{[/offchain.MsgSignArbitraryData]:{app_domain:\"simd\" signer:\"cosmos1x33fy6rusfprkntvjsfregss7rvsvyy4lkwrqu\" data:\"{\\n\\t\\\"name\\\": \\\"John\\\",\\n\\t\\\"surname\\\": \\\"Connor\\\",\\n\\t\\\"age\\\": 15\\n}\\n\"}}} auth_info:{signer_infos:{public_key:{[/cosmos.crypto.secp256k1.PubKey]:{key:\"\\x03\\xf0_\\xb1\\xbe\u0B5Br\\xb2\\xb7\\xa8\\xe3\\xca\\x01\\xd5p\\x17m\\xc8\\x07\\x9cBr\\x84\\n\\xb3\\x0c\\xc8\\x1b.U\\xf0\"}} mode_info:{single:{mode:SIGN_MODE_TEXTUAL}}} fee:{}} signatures:\"\\x81\\x1b\\x9f\\x8dɀM\\xa2w\\x85\\x94\\xa2\\\\\\x827\\x95\\xcb\\x0b\\x0c\\x99G3\\x83\\xa1B\\xcd\\xce\\xfd\\x08\\x00+\\x8c\\x1eC\\xbd\\xe4\\x9a=\\xf4\\xfe\\x0c7\\x1f\\x04\\xca\\xc4f\\xf8\\xa6u^\\xd2,\\x8b^\\xb2\\x915\\xe4\\xa5\\xd4\\xed\\xf3I\"\n"),
|
||||
digest: []byte("body:{messages:{[/offchain.MsgSignArbitraryData]:{app_domain:\"<appd>\" signer:\"cosmos16877zjk85kwlap3wclpmx34e0xllg2erc7u7m4\" data:\"{\\n\\t\\\"name\\\": \\\"Sarah\\\",\\n\\t\\\"surname\\\": \\\"Connor\\\",\\n\\t\\\"age\\\": 29\\n}\\n\"}} timeout_timestamp:{seconds:-62135596800}} auth_info:{signer_infos:{public_key:{[/cosmos.crypto.secp256k1.PubKey]:{key:\"\\x02\\x18n\\xde'RI@\\x10^\\xd0\\xc1\\xbc\\x18Ԕ#\\xd6\\x1fz\\x1d\\xe2\\xb5\\xf2Z\\x06\\xfb/\\x8b\\x1cJ>&\"}} mode_info:{single:{mode:SIGN_MODE_DIRECT}}} fee:{}} signatures:\"\\xb5\\xd5\\xec;\\x9b\\x8d\\xa8\\x80EH\\x12\\x84\\x03W\\xb7Z\\xb7\\x1b\\xe9\\xe8\\xeb\\x88\\xffG\\xc2W\\x01NE;\\x11Bs\\xb9\\xecヤo\\xafV\\xbe*\\x9e\\xae\\x98 \\r\\xecŨ\\x04tS\\xd9ɪ\\xcc7\\xe0\\xe9\\x18\\xda`\"\n"),
|
||||
fileFormat: "text",
|
||||
ctx: ctx,
|
||||
},
|
||||
{
|
||||
name: "wrong signer text",
|
||||
digest: []byte("\"body:{messages:{[/offchain.MsgSignArbitraryData]:{app_domain:\\\"simd\\\" signer:\\\"cosmos1450l4uau674z55c36df0v7904rnvdk9aq8w96j\\\" data:\\\"{\\\\n\\\\t\\\\\\\"name\\\\\\\": \\\\\\\"John\\\\\\\",\\\\n\\\\t\\\\\\\"surname\\\\\\\": \\\\\\\"Connor\\\\\\\",\\\\n\\\\t\\\\\\\"age\\\\\\\": 15\\\\n}\\\\n\\\"}}} auth_info:{signer_infos:{public_key:{[/cosmos.crypto.secp256k1.PubKey]:{key:\\\"\\\\x03\\\\xf0_\\\\xb1\\\\xbe\\u0B5Br\\\\xb2\\\\xb7\\\\xa8\\\\xe3\\\\xca\\\\x01\\\\xd5p\\\\x17m\\\\xc8\\\\x07\\\\x9cBr\\\\x84\\\\n\\\\xb3\\\\x0c\\\\xc8\\\\x1b.U\\\\xf0\\\"}} mode_info:{single:{mode:SIGN_MODE_TEXTUAL}}} fee:{}} signatures:\\\"\\\\x81\\\\x1b\\\\x9f\\\\x8dɀM\\\\xa2w\\\\x85\\\\x94\\\\xa2\\\\\\\\\\\\x827\\\\x95\\\\xcb\\\\x0b\\\\x0c\\\\x99G3\\\\x83\\\\xa1B\\\\xcd\\\\xce\\\\xfd\\\\x08\\\\x00+\\\\x8c\\\\x1eC\\\\xbd\\\\xe4\\\\x9a=\\\\xf4\\\\xfe\\\\x0c7\\\\x1f\\\\x04\\\\xca\\\\xc4f\\\\xf8\\\\xa6u^\\\\xd2,\\\\x8b^\\\\xb2\\\\x915\\\\xe4\\\\xa5\\\\xd4\\\\xed\\\\xf3I\\\"\\n"),
|
||||
digest: []byte("body:{messages:{[/offchain.MsgSignArbitraryData]:{app_domain:\"<appd>\" signer:\"cosmos1xv9e39mkhhyg5aneu2myj82t7029sv48qu3pgj\" data:\"{\\n\\t\\\"name\\\": \\\"Sarah\\\",\\n\\t\\\"surname\\\": \\\"Connor\\\",\\n\\t\\\"age\\\": 29\\n}\\n\"}} timeout_timestamp:{seconds:-62135596800}} auth_info:{signer_infos:{public_key:{[/cosmos.crypto.secp256k1.PubKey]:{key:\"\\x02\\x18n\\xde'RI@\\x10^\\xd0\\xc1\\xbc\\x18Ԕ#\\xd6\\x1fz\\x1d\\xe2\\xb5\\xf2Z\\x06\\xfb/\\x8b\\x1cJ>&\"}} mode_info:{single:{mode:SIGN_MODE_DIRECT}}} fee:{}} signatures:\"\\xb5\\xd5\\xec;\\x9b\\x8d\\xa8\\x80EH\\x12\\x84\\x03W\\xb7Z\\xb7\\x1b\\xe9\\xe8\\xeb\\x88\\xffG\\xc2W\\x01NE;\\x11Bs\\xb9\\xecヤo\\xafV\\xbe*\\x9e\\xae\\x98 \\r\\xecŨ\\x04tS\\xd9ɪ\\xcc7\\xe0\\xe9\\x18\\xda`\"\n"),
|
||||
fileFormat: "text",
|
||||
ctx: ctx,
|
||||
wantErr: true,
|
||||
@ -72,20 +74,28 @@ func Test_SignVerify(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := client.Context{
|
||||
TxConfig: newTestConfig(t),
|
||||
Codec: getCodec(),
|
||||
AddressCodec: address.NewBech32Codec("cosmos"),
|
||||
Keyring: k,
|
||||
TxConfig: newTestConfig(t),
|
||||
Codec: getCodec(),
|
||||
AddressCodec: address.NewBech32Codec("cosmos"),
|
||||
ValidatorAddressCodec: address.NewBech32Codec("cosmosvaloper"),
|
||||
Keyring: k,
|
||||
}
|
||||
|
||||
tx, err := sign(ctx, "signVerify", "digest")
|
||||
tx, err := Sign(ctx, []byte("Hello World!"), "signVerify", "no-encoding", "direct", "json")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = verify(ctx, tx)
|
||||
err = Verify(ctx, []byte(tx), "json")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_unmarshal(t *testing.T) {
|
||||
txConfig, err := clitx.NewTxConfig(clitx.ConfigOptions{
|
||||
AddressCodec: address.NewBech32Codec("cosmos"),
|
||||
Cdc: getCodec(),
|
||||
ValidatorAddressCodec: address.NewBech32Codec("cosmosvaloper"),
|
||||
EnabledSignModes: enabledSignModes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
name string
|
||||
digest []byte
|
||||
@ -104,7 +114,7 @@ func Test_unmarshal(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := unmarshal(tt.digest, tt.fileFormat)
|
||||
got, err := unmarshal(tt.fileFormat, tt.digest, txConfig)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, got)
|
||||
})
|
||||
|
||||
@ -51,6 +51,10 @@ type TxEncodingConfig interface {
|
||||
TxJSONEncoder() txEncoder
|
||||
// TxJSONDecoder returns a decoder for JSON transaction decoding.
|
||||
TxJSONDecoder() txDecoder
|
||||
// TxTextEncoder returns an encoder for text transaction encoding.
|
||||
TxTextEncoder() txEncoder
|
||||
// TxTextDecoder returns a decoder for text transaction decoding.
|
||||
TxTextDecoder() txDecoder
|
||||
// Decoder returns the Decoder interface for decoding transaction bytes into a DecodedTx.
|
||||
Decoder() Decoder
|
||||
}
|
||||
@ -79,7 +83,7 @@ type ConfigOptions struct {
|
||||
CustomGetSigner map[protoreflect.FullName]signing.GetSignersFunc
|
||||
MaxRecursionDepth int
|
||||
|
||||
EnablesSignModes []apitxsigning.SignMode
|
||||
EnabledSignModes []apitxsigning.SignMode
|
||||
CustomSignModes []signing.SignModeHandler
|
||||
TextualCoinMetadataQueryFn textual.CoinMetadataQueryFn
|
||||
}
|
||||
@ -98,8 +102,8 @@ func (c *ConfigOptions) validate() error {
|
||||
}
|
||||
|
||||
// set default signModes if none are provided
|
||||
if len(c.EnablesSignModes) == 0 {
|
||||
c.EnablesSignModes = defaultEnabledSignModes
|
||||
if len(c.EnabledSignModes) == 0 {
|
||||
c.EnabledSignModes = defaultEnabledSignModes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -168,6 +172,16 @@ func (t defaultEncodingConfig) TxJSONDecoder() txDecoder {
|
||||
return decodeJsonTx(t.cdc, t.decoder)
|
||||
}
|
||||
|
||||
// TxTextEncoder returns the default text transaction encoder.
|
||||
func (t defaultEncodingConfig) TxTextEncoder() txEncoder {
|
||||
return encodeTextTx
|
||||
}
|
||||
|
||||
// TxTextDecoder returns the default text transaction decoder.
|
||||
func (t defaultEncodingConfig) TxTextDecoder() txDecoder {
|
||||
return decodeTextTx(t.cdc, t.decoder)
|
||||
}
|
||||
|
||||
// Decoder returns the Decoder instance associated with this encoding configuration.
|
||||
func (t defaultEncodingConfig) Decoder() Decoder {
|
||||
return t.decoder
|
||||
@ -294,10 +308,10 @@ func newSigningContext(opts ConfigOptions) (*signing.Context, error) {
|
||||
// newHandlerMap constructs a new HandlerMap based on the provided ConfigOptions and signing context.
|
||||
// It initializes handlers for each enabled and custom sign mode specified in the options.
|
||||
func newHandlerMap(opts ConfigOptions, signingCtx *signing.Context) (*signing.HandlerMap, error) {
|
||||
lenSignModes := len(opts.EnablesSignModes)
|
||||
lenSignModes := len(opts.EnabledSignModes)
|
||||
handlers := make([]signing.SignModeHandler, lenSignModes+len(opts.CustomSignModes))
|
||||
|
||||
for i, m := range opts.EnablesSignModes {
|
||||
for i, m := range opts.EnabledSignModes {
|
||||
var err error
|
||||
switch m {
|
||||
case apitxsigning.SignMode_SIGN_MODE_DIRECT:
|
||||
|
||||
@ -111,7 +111,7 @@ func Test_newHandlerMap(t *testing.T) {
|
||||
Decoder: decoder,
|
||||
Cdc: cdc,
|
||||
ValidatorAddressCodec: address.NewBech32Codec("cosmosvaloper"),
|
||||
EnablesSignModes: []apitxsigning.SignMode{apitxsigning.SignMode_SIGN_MODE_DIRECT},
|
||||
EnabledSignModes: []apitxsigning.SignMode{apitxsigning.SignMode_SIGN_MODE_DIRECT},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -136,7 +136,7 @@ func Test_newHandlerMap(t *testing.T) {
|
||||
handlerMap, err := newHandlerMap(tt.opts, signingCtx)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, handlerMap)
|
||||
require.Equal(t, len(handlerMap.SupportedModes()), len(tt.opts.EnablesSignModes)+len(tt.opts.CustomSignModes))
|
||||
require.Equal(t, len(handlerMap.SupportedModes()), len(tt.opts.EnabledSignModes)+len(tt.opts.CustomSignModes))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
protov2 "google.golang.org/protobuf/proto"
|
||||
|
||||
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
|
||||
@ -22,6 +23,11 @@ var (
|
||||
UseProtoNames: true,
|
||||
UseEnumNumbers: false,
|
||||
}
|
||||
|
||||
// textMarshalOptions
|
||||
textMarshalOptions = prototext.MarshalOptions{
|
||||
Indent: "",
|
||||
}
|
||||
)
|
||||
|
||||
// Decoder defines the interface for decoding transaction bytes into a DecodedTx.
|
||||
@ -100,6 +106,39 @@ func encodeJsonTx(tx Tx) ([]byte, error) {
|
||||
return jsonMarshalOptions.Marshal(wTx.Tx)
|
||||
}
|
||||
|
||||
func encodeTextTx(tx Tx) ([]byte, error) {
|
||||
wTx, ok := tx.(*wrappedTx)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected tx type: %T", tx)
|
||||
}
|
||||
return textMarshalOptions.Marshal(wTx.Tx)
|
||||
}
|
||||
|
||||
// decodeJsonTx decodes transaction bytes into an apitx.Tx structure using JSON format.
|
||||
func decodeTextTx(cdc codec.BinaryCodec, decoder Decoder) txDecoder {
|
||||
return func(txBytes []byte) (Tx, error) {
|
||||
jsonTx := new(txv1beta1.Tx)
|
||||
err := prototext.UnmarshalOptions{
|
||||
AllowPartial: false,
|
||||
DiscardUnknown: false,
|
||||
}.Unmarshal(txBytes, jsonTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pTxBytes, err := protoTxBytes(jsonTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
decodedTx, err := decoder.Decode(pTxBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWrapperTx(cdc, decodedTx), nil
|
||||
}
|
||||
}
|
||||
|
||||
func protoTxBytes(tx *txv1beta1.Tx) ([]byte, error) {
|
||||
bodyBytes, err := marshalOption.Marshal(tx.Body)
|
||||
if err != nil {
|
||||
|
||||
@ -124,22 +124,22 @@ func prepareTxParams(parameters TxParameters, accRetriever account.AccountRetrie
|
||||
return parameters, nil
|
||||
}
|
||||
|
||||
if len(parameters.address) == 0 {
|
||||
if len(parameters.Address) == 0 {
|
||||
return parameters, errors.New("missing 'from address' field")
|
||||
}
|
||||
|
||||
if parameters.accountNumber == 0 || parameters.sequence == 0 {
|
||||
num, seq, err := accRetriever.GetAccountNumberSequence(context.Background(), parameters.address)
|
||||
if parameters.AccountNumber == 0 || parameters.Sequence == 0 {
|
||||
num, seq, err := accRetriever.GetAccountNumberSequence(context.Background(), parameters.Address)
|
||||
if err != nil {
|
||||
return parameters, err
|
||||
}
|
||||
|
||||
if parameters.accountNumber == 0 {
|
||||
parameters.accountNumber = num
|
||||
if parameters.AccountNumber == 0 {
|
||||
parameters.AccountNumber = num
|
||||
}
|
||||
|
||||
if parameters.sequence == 0 {
|
||||
parameters.sequence = seq
|
||||
if parameters.Sequence == 0 {
|
||||
parameters.Sequence = seq
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,11 +328,11 @@ func (f *Factory) sign(ctx context.Context, overwriteSig bool) (Tx, error) {
|
||||
}
|
||||
|
||||
var err error
|
||||
if f.txParams.signMode == apitxsigning.SignMode_SIGN_MODE_UNSPECIFIED {
|
||||
f.txParams.signMode = f.txConfig.SignModeHandler().DefaultMode()
|
||||
if f.txParams.SignMode == apitxsigning.SignMode_SIGN_MODE_UNSPECIFIED {
|
||||
f.txParams.SignMode = f.txConfig.SignModeHandler().DefaultMode()
|
||||
}
|
||||
|
||||
pubKey, err := f.keybase.GetPubKey(f.txParams.fromName)
|
||||
pubKey, err := f.keybase.GetPubKey(f.txParams.FromName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -343,9 +343,9 @@ func (f *Factory) sign(ctx context.Context, overwriteSig bool) (Tx, error) {
|
||||
}
|
||||
|
||||
signerData := signing.SignerData{
|
||||
ChainID: f.txParams.chainID,
|
||||
AccountNumber: f.txParams.accountNumber,
|
||||
Sequence: f.txParams.sequence,
|
||||
ChainID: f.txParams.ChainID,
|
||||
AccountNumber: f.txParams.AccountNumber,
|
||||
Sequence: f.txParams.Sequence,
|
||||
PubKey: &anypb.Any{
|
||||
TypeUrl: codectypes.MsgTypeURL(pubKey),
|
||||
Value: pubKey.Bytes(),
|
||||
@ -364,13 +364,13 @@ func (f *Factory) sign(ctx context.Context, overwriteSig bool) (Tx, error) {
|
||||
// By setting the signatures here, we ensure that the correct SignerInfos
|
||||
// are in place for all subsequent operations, regardless of the sign mode.
|
||||
sigData := SingleSignatureData{
|
||||
SignMode: f.txParams.signMode,
|
||||
SignMode: f.txParams.SignMode,
|
||||
Signature: nil,
|
||||
}
|
||||
sig := Signature{
|
||||
PubKey: pubKey,
|
||||
Data: &sigData,
|
||||
Sequence: f.txParams.sequence,
|
||||
Sequence: f.txParams.Sequence,
|
||||
}
|
||||
|
||||
var prevSignatures []Signature
|
||||
@ -412,7 +412,7 @@ func (f *Factory) sign(ctx context.Context, overwriteSig bool) (Tx, error) {
|
||||
}
|
||||
|
||||
// Sign those bytes
|
||||
sigBytes, err := f.keybase.Sign(f.txParams.fromName, bytesToSign, f.txParams.signMode)
|
||||
sigBytes, err := f.keybase.Sign(f.txParams.FromName, bytesToSign, f.txParams.SignMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -425,7 +425,7 @@ func (f *Factory) sign(ctx context.Context, overwriteSig bool) (Tx, error) {
|
||||
sig = Signature{
|
||||
PubKey: pubKey,
|
||||
Data: &sigData,
|
||||
Sequence: f.txParams.sequence,
|
||||
Sequence: f.txParams.Sequence,
|
||||
}
|
||||
|
||||
if overwriteSig {
|
||||
@ -460,16 +460,16 @@ func (f *Factory) WithGas(gas uint64) {
|
||||
|
||||
// WithSequence returns a copy of the Factory with an updated sequence number.
|
||||
func (f *Factory) WithSequence(sequence uint64) {
|
||||
f.txParams.sequence = sequence
|
||||
f.txParams.Sequence = sequence
|
||||
}
|
||||
|
||||
// WithAccountNumber returns a copy of the Factory with an updated account number.
|
||||
func (f *Factory) WithAccountNumber(accnum uint64) {
|
||||
f.txParams.accountNumber = accnum
|
||||
f.txParams.AccountNumber = accnum
|
||||
}
|
||||
|
||||
// sequence returns the sequence number.
|
||||
func (f *Factory) sequence() uint64 { return f.txParams.sequence }
|
||||
func (f *Factory) sequence() uint64 { return f.txParams.Sequence }
|
||||
|
||||
// gasAdjustment returns the gas adjustment value.
|
||||
func (f *Factory) gasAdjustment() float64 { return f.txParams.gasAdjustment }
|
||||
@ -478,7 +478,7 @@ func (f *Factory) gasAdjustment() float64 { return f.txParams.gasAdjustment }
|
||||
func (f *Factory) simulateAndExecute() bool { return f.txParams.simulateAndExecute }
|
||||
|
||||
// signMode returns the sign mode.
|
||||
func (f *Factory) signMode() apitxsigning.SignMode { return f.txParams.signMode }
|
||||
func (f *Factory) signMode() apitxsigning.SignMode { return f.txParams.SignMode }
|
||||
|
||||
// getSimPK gets the public key to use for building a simulation tx.
|
||||
// Note, we should only check for keys in the keybase if we are in simulate and execute mode,
|
||||
@ -492,14 +492,14 @@ func (f *Factory) getSimPK() (cryptotypes.PubKey, error) {
|
||||
)
|
||||
|
||||
if f.txParams.simulateAndExecute && f.keybase != nil {
|
||||
pk, err = f.keybase.GetPubKey(f.txParams.fromName)
|
||||
pk, err = f.keybase.GetPubKey(f.txParams.FromName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// When in dry-run mode, attempt to retrieve the account using the provided address.
|
||||
// If the account retrieval fails, the default public key is used.
|
||||
acc, err := f.accountRetriever.GetAccount(context.Background(), f.txParams.address)
|
||||
acc, err := f.accountRetriever.GetAccount(context.Background(), f.txParams.Address)
|
||||
if err != nil {
|
||||
// If there is an error retrieving the account, return the default public key.
|
||||
return pk, nil
|
||||
@ -516,7 +516,7 @@ func (f *Factory) getSimPK() (cryptotypes.PubKey, error) {
|
||||
func (f *Factory) getSimSignatureData(pk cryptotypes.PubKey) SignatureData {
|
||||
multisigPubKey, ok := pk.(*multisig.LegacyAminoPubKey)
|
||||
if !ok {
|
||||
return &SingleSignatureData{SignMode: f.txParams.signMode}
|
||||
return &SingleSignatureData{SignMode: f.txParams.SignMode}
|
||||
}
|
||||
|
||||
multiSignatureData := make([]SignatureData, 0, multisigPubKey.Threshold)
|
||||
|
||||
@ -35,7 +35,7 @@ func TestFactory_prepareTxParams(t *testing.T) {
|
||||
name: "no error",
|
||||
txParams: TxParameters{
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -66,9 +66,9 @@ func TestFactory_BuildUnsignedTx(t *testing.T) {
|
||||
{
|
||||
name: "no error",
|
||||
txParams: TxParameters{
|
||||
chainID: "demo",
|
||||
ChainID: "demo",
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
msgs: []transaction.Msg{
|
||||
@ -81,9 +81,9 @@ func TestFactory_BuildUnsignedTx(t *testing.T) {
|
||||
{
|
||||
name: "fees and gas price provided",
|
||||
txParams: TxParameters{
|
||||
chainID: "demo",
|
||||
ChainID: "demo",
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
GasConfig: GasConfig{
|
||||
gasPrices: []*base.DecCoin{
|
||||
@ -133,9 +133,9 @@ func TestFactory_calculateGas(t *testing.T) {
|
||||
{
|
||||
name: "no error",
|
||||
txParams: TxParameters{
|
||||
chainID: "demo",
|
||||
ChainID: "demo",
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
GasConfig: GasConfig{
|
||||
gasAdjustment: 1,
|
||||
@ -175,9 +175,9 @@ func TestFactory_Simulate(t *testing.T) {
|
||||
{
|
||||
name: "no error",
|
||||
txParams: TxParameters{
|
||||
chainID: "demo",
|
||||
ChainID: "demo",
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
GasConfig: GasConfig{
|
||||
gasAdjustment: 1,
|
||||
@ -219,9 +219,9 @@ func TestFactory_BuildSimTx(t *testing.T) {
|
||||
{
|
||||
name: "no error",
|
||||
txParams: TxParameters{
|
||||
chainID: "demo",
|
||||
ChainID: "demo",
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -251,10 +251,10 @@ func TestFactory_Sign(t *testing.T) {
|
||||
{
|
||||
name: "no error",
|
||||
txParams: TxParameters{
|
||||
chainID: "demo",
|
||||
ChainID: "demo",
|
||||
AccountConfig: AccountConfig{
|
||||
fromName: "alice",
|
||||
address: addr,
|
||||
FromName: "alice",
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -299,19 +299,19 @@ func TestFactory_getSignBytesAdapter(t *testing.T) {
|
||||
{
|
||||
name: "no error",
|
||||
txParams: TxParameters{
|
||||
chainID: "demo",
|
||||
signMode: apitxsigning.SignMode_SIGN_MODE_DIRECT,
|
||||
ChainID: "demo",
|
||||
SignMode: apitxsigning.SignMode_SIGN_MODE_DIRECT,
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "signMode not specified",
|
||||
txParams: TxParameters{
|
||||
chainID: "demo",
|
||||
ChainID: "demo",
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
error: true,
|
||||
@ -341,7 +341,7 @@ func TestFactory_getSignBytesAdapter(t *testing.T) {
|
||||
|
||||
signerData := signing.SignerData{
|
||||
Address: addr,
|
||||
ChainID: f.txParams.chainID,
|
||||
ChainID: f.txParams.ChainID,
|
||||
AccountNumber: 0,
|
||||
Sequence: 0,
|
||||
PubKey: &anypb.Any{
|
||||
@ -401,7 +401,7 @@ func TestFactory_WithFunctions(t *testing.T) {
|
||||
name: "with gas",
|
||||
txParams: TxParameters{
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
withFunc: func(f *Factory) {
|
||||
@ -415,28 +415,28 @@ func TestFactory_WithFunctions(t *testing.T) {
|
||||
name: "with sequence",
|
||||
txParams: TxParameters{
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
withFunc: func(f *Factory) {
|
||||
f.WithSequence(10)
|
||||
},
|
||||
checkFunc: func(f *Factory) bool {
|
||||
return f.txParams.AccountConfig.sequence == 10
|
||||
return f.txParams.AccountConfig.Sequence == 10
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with account number",
|
||||
txParams: TxParameters{
|
||||
AccountConfig: AccountConfig{
|
||||
address: addr,
|
||||
Address: addr,
|
||||
},
|
||||
},
|
||||
withFunc: func(f *Factory) {
|
||||
f.WithAccountNumber(123)
|
||||
},
|
||||
checkFunc: func(f *Factory) bool {
|
||||
return f.txParams.AccountConfig.accountNumber == 123
|
||||
return f.txParams.AccountConfig.AccountNumber == 123
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ func newFactory(ctx client.Context, flagSet *pflag.FlagSet) (Factory, error) {
|
||||
AddressCodec: ctx.AddressCodec,
|
||||
Cdc: ctx.Codec,
|
||||
ValidatorAddressCodec: ctx.ValidatorAddressCodec,
|
||||
EnablesSignModes: ctx.TxConfig.SignModeHandler().SupportedModes(),
|
||||
EnabledSignModes: ctx.TxConfig.SignModeHandler().SupportedModes(),
|
||||
})
|
||||
if err != nil {
|
||||
return Factory{}, err
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"cosmossdk.io/client/v2/internal/coins"
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/core/transaction"
|
||||
"cosmossdk.io/x/tx/signing"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
)
|
||||
@ -28,9 +29,9 @@ type HasValidateBasic interface {
|
||||
// TxParameters defines the parameters required for constructing a transaction.
|
||||
type TxParameters struct {
|
||||
timeoutTimestamp time.Time // timeoutTimestamp indicates a timestamp after which the transaction is no longer valid.
|
||||
chainID string // chainID specifies the unique identifier of the blockchain where the transaction will be processed.
|
||||
ChainID string // ChainID specifies the unique identifier of the blockchain where the transaction will be processed.
|
||||
memo string // memo contains any arbitrary memo to be attached to the transaction.
|
||||
signMode apitxsigning.SignMode // signMode determines the signing mode to be used for the transaction.
|
||||
SignMode apitxsigning.SignMode // signMode determines the signing mode to be used for the transaction.
|
||||
|
||||
AccountConfig // AccountConfig includes information about the transaction originator's account.
|
||||
GasConfig // GasConfig specifies the gas settings for the transaction.
|
||||
@ -41,15 +42,15 @@ type TxParameters struct {
|
||||
// AccountConfig defines the 'account' related fields in a transaction.
|
||||
type AccountConfig struct {
|
||||
// accountNumber is the unique identifier for the account.
|
||||
accountNumber uint64
|
||||
AccountNumber uint64
|
||||
// sequence is the sequence number of the transaction.
|
||||
sequence uint64
|
||||
Sequence uint64
|
||||
// fromName is the name of the account sending the transaction.
|
||||
fromName string
|
||||
FromName string
|
||||
// fromAddress is the address of the account sending the transaction.
|
||||
fromAddress string
|
||||
FromAddress string
|
||||
// address is the byte representation of the account address.
|
||||
address []byte
|
||||
Address []byte
|
||||
}
|
||||
|
||||
// GasConfig defines the 'gas' related fields in a transaction.
|
||||
@ -141,6 +142,8 @@ type Tx interface {
|
||||
GetPubKeys() ([]cryptotypes.PubKey, error)
|
||||
// GetSignatures fetches the signatures attached to the transaction.
|
||||
GetSignatures() ([]Signature, error)
|
||||
// GetSigningTxData returns the signing.TxData for the transaction.
|
||||
GetSigningTxData() (signing.TxData, error)
|
||||
}
|
||||
|
||||
// txParamsFromFlagSet extracts the transaction parameters from the provided FlagSet.
|
||||
@ -192,15 +195,15 @@ func txParamsFromFlagSet(flags *pflag.FlagSet, keybase keyring2.Keyring, ac addr
|
||||
|
||||
txParams := TxParameters{
|
||||
timeoutTimestamp: timeoutTimestamp,
|
||||
chainID: chainID,
|
||||
ChainID: chainID,
|
||||
memo: memo,
|
||||
signMode: getSignMode(signMode),
|
||||
SignMode: getSignMode(signMode),
|
||||
AccountConfig: AccountConfig{
|
||||
accountNumber: accNumber,
|
||||
sequence: sequence,
|
||||
fromName: fromName,
|
||||
fromAddress: fromAddress,
|
||||
address: addr,
|
||||
AccountNumber: accNumber,
|
||||
Sequence: sequence,
|
||||
FromName: fromName,
|
||||
FromAddress: fromAddress,
|
||||
Address: addr,
|
||||
},
|
||||
GasConfig: gasConfig,
|
||||
FeeConfig: feeConfig,
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"cosmossdk.io/core/transaction"
|
||||
"cosmossdk.io/x/tx/decode"
|
||||
"cosmossdk.io/x/tx/signing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
@ -96,6 +97,16 @@ func (w wrappedTx) GetSignatures() ([]Signature, error) {
|
||||
return signatures, nil
|
||||
}
|
||||
|
||||
func (w wrappedTx) GetSigningTxData() (signing.TxData, error) {
|
||||
return signing.TxData{
|
||||
Body: w.Tx.Body,
|
||||
AuthInfo: w.Tx.AuthInfo,
|
||||
BodyBytes: w.TxRaw.BodyBytes,
|
||||
AuthInfoBytes: w.TxRaw.AuthInfoBytes,
|
||||
BodyHasUnknownNonCriticals: w.TxBodyHasUnknownNonCriticals,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// decodeAny decodes a protobuf Any message into a concrete proto.Message.
|
||||
func (w wrappedTx) decodeAny(anyPb *anypb.Any) (proto.Message, error) {
|
||||
name := anyPb.GetTypeUrl()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user