From 44e4bc9ca429d3dec0e60c35713308ad73a654cf Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 28 Jul 2020 22:50:06 +0200 Subject: [PATCH 01/41] x/ibc-transfer: ADR001 source tracing implementation --- proto/ibc/transfer/genesis.proto | 15 +- proto/ibc/transfer/transfer.proto | 15 +- x/ibc-transfer/keeper/keeper.go | 27 ++ x/ibc-transfer/types/genesis.pb.go | 383 ++++++++++++++++++++++++++-- x/ibc-transfer/types/keys.go | 15 +- x/ibc-transfer/types/trace.go | 58 +++++ x/ibc-transfer/types/transfer.pb.go | 370 ++++++++++++++++++++++++--- 7 files changed, 817 insertions(+), 66 deletions(-) create mode 100644 x/ibc-transfer/types/trace.go diff --git a/proto/ibc/transfer/genesis.proto b/proto/ibc/transfer/genesis.proto index b8e7b665d18e..607430e69df2 100644 --- a/proto/ibc/transfer/genesis.proto +++ b/proto/ibc/transfer/genesis.proto @@ -7,11 +7,22 @@ import "gogoproto/gogo.proto"; import "cosmos/cosmos.proto"; import "ibc/transfer/transfer.proto"; -// GenesisState is currently only used to ensure that the InitGenesis gets run -// by the module manager +// GenesisState defines the ibc-transfer genesis state message GenesisState{ string port_id = 1 [ (gogoproto.customname) = "PortID", (gogoproto.moretags) = "yaml:\"port_id\"" ]; + repeated GenesisDenomTrace denom_traces = 2 [(gogoproto.moretags) = "yaml:\"denom_traces\""]; } + + +// GenesisDenomTrace contains DenomTrace and the hash used for the IBC fungible denom map. +message GenesisDenomTrace { + // chain of port/channel identifiers used for tracing the source of the fungible token + string trace = 1; + // base denomination of the relayed fungible token + string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; + // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) + bytes hash = 3; +} \ No newline at end of file diff --git a/proto/ibc/transfer/transfer.proto b/proto/ibc/transfer/transfer.proto index 28672735398c..3edee632b989 100644 --- a/proto/ibc/transfer/transfer.proto +++ b/proto/ibc/transfer/transfer.proto @@ -44,10 +44,12 @@ message FungibleTokenPacketData { (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; + // coins denomination trace for tracking the source + repeated DenomTrace denom_traces = 2 [(gogoproto.moretags) = "yaml:\"denom_traces\""]; // the sender address - string sender = 2; + string sender = 3; // the recipient address on the destination chain - string receiver = 3; + string receiver = 4; } // FungibleTokenPacketAcknowledgement contains a boolean success flag and an optional error msg @@ -57,3 +59,12 @@ message FungibleTokenPacketAcknowledgement { bool success = 1; string error = 2; } + +// DenomTrace contains the base denomination for ICS20 fungible tokens and the souce tracing +// information +message DenomTrace { + // chain of port/channel identifiers used for tracing the source of the fungible token + string trace = 1; + // base denomination of the relayed fungible token + string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; +} diff --git a/x/ibc-transfer/keeper/keeper.go b/x/ibc-transfer/keeper/keeper.go index c9ede680091d..6b063603b3c2 100644 --- a/x/ibc-transfer/keeper/keeper.go +++ b/x/ibc-transfer/keeper/keeper.go @@ -6,6 +6,7 @@ import ( "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -109,6 +110,32 @@ func (k Keeper) SetPort(ctx sdk.Context, portID string) { store.Set(types.PortKey, []byte(portID)) } +// GetDenomTrace retreives the full identifiers trace and base denomination from the store. +func (k Keeper) GetDenomTrace(ctx Context, denomTraceHash []byte) (types.DenomTrace, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) + bz := store.Get(traceHash) + if bz == nil { + return &types.DenomTrace, false + } + + var denomTrace types.DenomTrace + k.cdc.MustUnmarshalBinaryBare(bz, &denomTrace) + return denomTrace, true +} + +// HasDenomTrace checks if a the key with the given denomination trace hash exists on the store. +func (k Keeper) HasDenomTrace(ctx Context, denomTraceHash []byte) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) + return store.Has(denomTraceHash) +} + +// SetDenomTrace sets a new {trace hash -> denom trace} pair to the store. +func (k Keeper) SetDenomTrace(ctx Context, denomTraceHash []byte, denomTrace types.DenomTrace) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) + bz := k.cdc.MustMarshalBinaryBare(&denomTrace) + store.Set(denomTraceHash, bz) +} + // ClaimCapability allows the transfer module that can claim a capability that IBC module // passes to it func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { diff --git a/x/ibc-transfer/types/genesis.pb.go b/x/ibc-transfer/types/genesis.pb.go index b96bd2fa3280..4d835524f316 100644 --- a/x/ibc-transfer/types/genesis.pb.go +++ b/x/ibc-transfer/types/genesis.pb.go @@ -24,8 +24,10 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// GenesisState defines the ibc-transfer genesis state type GenesisState struct { - PortID string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + PortID string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + DenomTraces []*GenesisDenomTrace `protobuf:"bytes,2,rep,name=denom_traces,json=denomTraces,proto3" json:"denom_traces,omitempty" yaml:"denom_traces"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -68,28 +70,107 @@ func (m *GenesisState) GetPortID() string { return "" } +func (m *GenesisState) GetDenomTraces() []*GenesisDenomTrace { + if m != nil { + return m.DenomTraces + } + return nil +} + +// GenesisDenomTrace contains DenomTrace and the hash used for the IBC fungible denom map. +type GenesisDenomTrace struct { + // chain of port/channel identifiers used for tracing the source of the fungible token + Trace string `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` + // base denomination of the relayed fungible token + BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty" yaml:"base_denom"` + // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) + Hash []byte `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (m *GenesisDenomTrace) Reset() { *m = GenesisDenomTrace{} } +func (m *GenesisDenomTrace) String() string { return proto.CompactTextString(m) } +func (*GenesisDenomTrace) ProtoMessage() {} +func (*GenesisDenomTrace) Descriptor() ([]byte, []int) { + return fileDescriptor_c13b8463155e05c2, []int{1} +} +func (m *GenesisDenomTrace) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisDenomTrace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisDenomTrace.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 *GenesisDenomTrace) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisDenomTrace.Merge(m, src) +} +func (m *GenesisDenomTrace) XXX_Size() int { + return m.Size() +} +func (m *GenesisDenomTrace) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisDenomTrace.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisDenomTrace proto.InternalMessageInfo + +func (m *GenesisDenomTrace) GetTrace() string { + if m != nil { + return m.Trace + } + return "" +} + +func (m *GenesisDenomTrace) GetBaseDenom() string { + if m != nil { + return m.BaseDenom + } + return "" +} + +func (m *GenesisDenomTrace) GetHash() []byte { + if m != nil { + return m.Hash + } + return nil +} + func init() { proto.RegisterType((*GenesisState)(nil), "ibc.transfer.GenesisState") + proto.RegisterType((*GenesisDenomTrace)(nil), "ibc.transfer.GenesisDenomTrace") } func init() { proto.RegisterFile("ibc/transfer/genesis.proto", fileDescriptor_c13b8463155e05c2) } var fileDescriptor_c13b8463155e05c2 = []byte{ - // 218 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xca, 0x4c, 0x4a, 0xd6, - 0x2f, 0x29, 0x4a, 0xcc, 0x2b, 0x4e, 0x4b, 0x2d, 0xd2, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, - 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xc9, 0x4c, 0x4a, 0xd6, 0x83, 0xc9, 0x49, 0x89, - 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf4, 0x41, 0x2c, 0x88, 0x1a, 0x29, 0xe1, 0xe4, 0xfc, 0xe2, - 0xdc, 0xfc, 0x62, 0x7d, 0x08, 0x05, 0x15, 0x94, 0x46, 0x31, 0x14, 0xc6, 0x80, 0x48, 0x2a, 0xb9, - 0x72, 0xf1, 0xb8, 0x43, 0xac, 0x09, 0x2e, 0x49, 0x2c, 0x49, 0x15, 0x32, 0xe5, 0x62, 0x2f, 0xc8, - 0x2f, 0x2a, 0x89, 0xcf, 0x4c, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x74, 0x92, 0x79, 0x74, 0x4f, - 0x9e, 0x2d, 0x20, 0xbf, 0xa8, 0xc4, 0xd3, 0xe5, 0xd3, 0x3d, 0x79, 0xbe, 0xca, 0xc4, 0xdc, 0x1c, - 0x2b, 0x25, 0xa8, 0x12, 0xa5, 0x20, 0x36, 0x10, 0xcb, 0x33, 0xc5, 0xc9, 0xfb, 0xc4, 0x23, 0x39, - 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, - 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x0c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, - 0xf3, 0x73, 0xf5, 0x51, 0x5c, 0xa7, 0x5b, 0x9c, 0x92, 0xad, 0x5f, 0xa1, 0x9f, 0x99, 0x94, 0xac, - 0x8b, 0x70, 0x5c, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, 0x69, 0xc6, 0x80, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x7a, 0xfc, 0xa4, 0xfa, 0x0e, 0x01, 0x00, 0x00, + // 336 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xcb, 0x4e, 0xc2, 0x40, + 0x14, 0x86, 0x19, 0x50, 0x0c, 0x43, 0x63, 0xc2, 0x80, 0xb1, 0x41, 0xd3, 0x92, 0xae, 0xd8, 0xd0, + 0x89, 0xb7, 0x8d, 0x4b, 0x42, 0x62, 0x88, 0x1b, 0x53, 0x5d, 0xe9, 0x82, 0xf4, 0x32, 0x96, 0x46, + 0xcb, 0x90, 0x39, 0x63, 0x22, 0x6f, 0xe1, 0x33, 0xf8, 0x34, 0x2e, 0x59, 0xba, 0x6a, 0x4c, 0x79, + 0x03, 0x9e, 0xc0, 0x74, 0x06, 0x04, 0xe2, 0xaa, 0xff, 0xe9, 0xff, 0x9d, 0xcb, 0xfc, 0xb8, 0x9d, + 0x04, 0x21, 0x95, 0xc2, 0x9f, 0xc0, 0x33, 0x13, 0x34, 0x66, 0x13, 0x06, 0x09, 0xb8, 0x53, 0xc1, + 0x25, 0x27, 0x46, 0x12, 0x84, 0xee, 0xda, 0x6b, 0xb7, 0x62, 0x1e, 0x73, 0x65, 0xd0, 0x42, 0x69, + 0xa6, 0xdd, 0x0c, 0x39, 0xa4, 0x1c, 0xa8, 0xfe, 0xac, 0x7e, 0x9e, 0xec, 0x0c, 0x5d, 0x0b, 0x6d, + 0x3a, 0x9f, 0x08, 0x1b, 0x37, 0x7a, 0xcf, 0xbd, 0xf4, 0x25, 0x23, 0x57, 0xf8, 0x60, 0xca, 0x85, + 0x1c, 0x25, 0x91, 0x89, 0x3a, 0xa8, 0x5b, 0xeb, 0x9f, 0xe6, 0x99, 0x5d, 0xbd, 0xe3, 0x42, 0x0e, + 0x07, 0xcb, 0xcc, 0x3e, 0x9c, 0xf9, 0xe9, 0xeb, 0xb5, 0xb3, 0x42, 0x1c, 0xaf, 0x5a, 0xa8, 0x61, + 0x44, 0x9e, 0xb0, 0x11, 0xb1, 0x09, 0x4f, 0x47, 0x52, 0xf8, 0x21, 0x03, 0xb3, 0xdc, 0xa9, 0x74, + 0xeb, 0xe7, 0xb6, 0xbb, 0x7d, 0xb4, 0xbb, 0x5a, 0x34, 0x28, 0xc0, 0x87, 0x82, 0xeb, 0x1f, 0x2f, + 0x33, 0xbb, 0xa9, 0x47, 0x6e, 0xb7, 0x3b, 0x5e, 0x3d, 0xfa, 0x83, 0xc0, 0x01, 0xdc, 0xf8, 0xd7, + 0x4a, 0x5a, 0x78, 0x5f, 0xc1, 0xfa, 0x4c, 0x4f, 0x17, 0xe4, 0x12, 0xe3, 0xc0, 0x07, 0x36, 0x52, + 0xed, 0x66, 0x59, 0xbd, 0xe0, 0x68, 0x99, 0xd9, 0x0d, 0xbd, 0x64, 0xe3, 0x39, 0x5e, 0xad, 0x28, + 0xd4, 0x40, 0x42, 0xf0, 0xde, 0xd8, 0x87, 0xb1, 0x59, 0xe9, 0xa0, 0xae, 0xe1, 0x29, 0xdd, 0xbf, + 0xfd, 0xca, 0x2d, 0x34, 0xcf, 0x2d, 0xf4, 0x93, 0x5b, 0xe8, 0x63, 0x61, 0x95, 0xe6, 0x0b, 0xab, + 0xf4, 0xbd, 0xb0, 0x4a, 0x8f, 0x67, 0x71, 0x22, 0xc7, 0x6f, 0x81, 0x1b, 0xf2, 0x94, 0xee, 0x04, + 0xde, 0x83, 0xe8, 0x85, 0xbe, 0xd3, 0x24, 0x08, 0x7b, 0x9b, 0xbc, 0x67, 0x53, 0x06, 0x41, 0x55, + 0xa5, 0x7d, 0xf1, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x9d, 0xec, 0x92, 0xe1, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -112,6 +193,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.DenomTraces) > 0 { + for iNdEx := len(m.DenomTraces) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DenomTraces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } if len(m.PortID) > 0 { i -= len(m.PortID) copy(dAtA[i:], m.PortID) @@ -122,6 +217,50 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *GenesisDenomTrace) 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 *GenesisDenomTrace) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisDenomTrace) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0x1a + } + if len(m.BaseDenom) > 0 { + i -= len(m.BaseDenom) + copy(dAtA[i:], m.BaseDenom) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.BaseDenom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Trace) > 0 { + i -= len(m.Trace) + copy(dAtA[i:], m.Trace) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Trace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -143,6 +282,33 @@ func (m *GenesisState) Size() (n int) { if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } + if len(m.DenomTraces) > 0 { + for _, e := range m.DenomTraces { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *GenesisDenomTrace) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Trace) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.BaseDenom) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } return n } @@ -213,6 +379,191 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } m.PortID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomTraces", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DenomTraces = append(m.DenomTraces, &GenesisDenomTrace{}) + if err := m.DenomTraces[len(m.DenomTraces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisDenomTrace) 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 ErrIntOverflowGenesis + } + 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: GenesisDenomTrace: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisDenomTrace: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Trace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BaseDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/ibc-transfer/types/keys.go b/x/ibc-transfer/types/keys.go index bc66ebcad15e..094dcc0d4e16 100644 --- a/x/ibc-transfer/types/keys.go +++ b/x/ibc-transfer/types/keys.go @@ -1,8 +1,6 @@ package types import ( - "fmt" - "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" @@ -29,8 +27,12 @@ const ( QuerierRoute = ModuleName ) -// PortKey defines the key to store the port ID in store -var PortKey = []byte{0x01} +var ( + // PortKey defines the key to store the port ID in store + PortKey = []byte{0x01} + // DenomTraceKey defines the key to store the denomination trace info in store + DenomTraceKey = []byte{0x02} +) // GetEscrowAddress returns the escrow address for the specified channel // @@ -41,11 +43,6 @@ func GetEscrowAddress(portID, channelID string) sdk.AccAddress { return sdk.AccAddress(crypto.AddressHash([]byte(portID + channelID))) } -// GetDenomPrefix returns the receiving denomination prefix -func GetDenomPrefix(portID, channelID string) string { - return fmt.Sprintf("%s/%s/", portID, channelID) -} - // GetPrefixedCoins creates a copy of the given coins with the denom updated with the prefix. func GetPrefixedCoins(portID, channelID string, coins ...sdk.Coin) sdk.Coins { prefixedCoins := make(sdk.Coins, len(coins)) diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go new file mode 100644 index 000000000000..9c61de1d805b --- /dev/null +++ b/x/ibc-transfer/types/trace.go @@ -0,0 +1,58 @@ +package types + +import ( + fmt "fmt" + "strings" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula: +// +// hash = sha256(trace + "/" + baseDenom) +func (dt DenomTrace) Hash() tmbytes.HexBytes { + return tmhash.Sum(dt.GetDenomPrefix() + dt.BaseDenom) +} + +// GetPrefix returns the receiving denomination prefix composed by the trace info and a separator. +func (dt DenomTrace) GetPrefix() string { + return dt.Trace + "/" +} + +// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + "/" + baseDenom)}'. If the trace is empty, it will return the base denomination. +func (dt DenomTrace) IBCDenom() string { + if dt.Trace != "" { + return fmt.Sprintf("ibc/%s", dt.Hash()) + } + return dt.BaseDenom +} + +// RemovePrefix trims the first portID/channelID pair from the trace info. If the trace is already empty it will perform a no-op. If the trace is incorrectly constructed or doesn't have separators it will return an error. +func (dt *DenomTrace) RemovePrefix() error { + if dt.Trace == "" { + return nil + } + + traceSplit := strings.SplitN(dt.Trace, "/", 3) + + var err error + switch { + case len(traceSplit) == 0, traceSplit[0] == dt.Trace: + err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "trace info %s must contain '/' separators", dt.Trace) + case len(traceSplit) == 1: + err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "trace info %s must come in pairs of '{portID}/channelID}'", dt.Trace) + case len(traceSplit) == 2: + dt.Trace = "" + case len(traceSplit) == 3: + dt.Trace = traceSplit[2] + } + + if err != nil { + return err + } + + return nil +} diff --git a/x/ibc-transfer/types/transfer.pb.go b/x/ibc-transfer/types/transfer.pb.go index 6df49844dac7..e015743e27db 100644 --- a/x/ibc-transfer/types/transfer.pb.go +++ b/x/ibc-transfer/types/transfer.pb.go @@ -133,10 +133,12 @@ func (m *MsgTransfer) GetTimeoutTimestamp() uint64 { type FungibleTokenPacketData struct { // the tokens to be transferred Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` + // coins denomination trace for tracking the source + DenomTraces []*DenomTrace `protobuf:"bytes,2,rep,name=denom_traces,json=denomTraces,proto3" json:"denom_traces,omitempty" yaml:"denom_traces"` // the sender address - Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` + Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` // the recipient address on the destination chain - Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` + Receiver string `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"` } func (m *FungibleTokenPacketData) Reset() { *m = FungibleTokenPacketData{} } @@ -179,6 +181,13 @@ func (m *FungibleTokenPacketData) GetAmount() github_com_cosmos_cosmos_sdk_types return nil } +func (m *FungibleTokenPacketData) GetDenomTraces() []*DenomTrace { + if m != nil { + return m.DenomTraces + } + return nil +} + func (m *FungibleTokenPacketData) GetSender() string { if m != nil { return m.Sender @@ -248,47 +257,109 @@ func (m *FungibleTokenPacketAcknowledgement) GetError() string { return "" } +// DenomTrace contains the base denomination for ICS20 fungible tokens and the souce tracing +// information +type DenomTrace struct { + // chain of port/channel identifiers used for tracing the source of the fungible token + Trace string `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` + // base denomination of the relayed fungible token + BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty" yaml:"base_denom"` +} + +func (m *DenomTrace) Reset() { *m = DenomTrace{} } +func (m *DenomTrace) String() string { return proto.CompactTextString(m) } +func (*DenomTrace) ProtoMessage() {} +func (*DenomTrace) Descriptor() ([]byte, []int) { + return fileDescriptor_08134a70fd29e656, []int{3} +} +func (m *DenomTrace) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DenomTrace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DenomTrace.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 *DenomTrace) XXX_Merge(src proto.Message) { + xxx_messageInfo_DenomTrace.Merge(m, src) +} +func (m *DenomTrace) XXX_Size() int { + return m.Size() +} +func (m *DenomTrace) XXX_DiscardUnknown() { + xxx_messageInfo_DenomTrace.DiscardUnknown(m) +} + +var xxx_messageInfo_DenomTrace proto.InternalMessageInfo + +func (m *DenomTrace) GetTrace() string { + if m != nil { + return m.Trace + } + return "" +} + +func (m *DenomTrace) GetBaseDenom() string { + if m != nil { + return m.BaseDenom + } + return "" +} + func init() { proto.RegisterType((*MsgTransfer)(nil), "ibc.transfer.MsgTransfer") proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.transfer.FungibleTokenPacketData") proto.RegisterType((*FungibleTokenPacketAcknowledgement)(nil), "ibc.transfer.FungibleTokenPacketAcknowledgement") + proto.RegisterType((*DenomTrace)(nil), "ibc.transfer.DenomTrace") } func init() { proto.RegisterFile("ibc/transfer/transfer.proto", fileDescriptor_08134a70fd29e656) } var fileDescriptor_08134a70fd29e656 = []byte{ - // 484 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0x3f, 0x6f, 0xd3, 0x40, - 0x1c, 0x8d, 0x49, 0x9b, 0x96, 0x4b, 0x8a, 0xe0, 0x28, 0xe5, 0x08, 0xc8, 0x8e, 0x3c, 0x79, 0x49, - 0x4c, 0x61, 0x40, 0x62, 0x22, 0x29, 0x42, 0x54, 0x08, 0xa9, 0xb2, 0x22, 0x06, 0x96, 0xca, 0x3e, - 0xff, 0x70, 0x4e, 0x89, 0xef, 0xa2, 0xbb, 0x33, 0xd0, 0x6f, 0xc1, 0x97, 0x60, 0xe1, 0x93, 0x74, - 0xec, 0xc0, 0xc0, 0x64, 0x50, 0xf2, 0x0d, 0x32, 0x32, 0x21, 0xff, 0x89, 0x89, 0xa5, 0x08, 0x31, - 0x74, 0xba, 0x7b, 0xef, 0xfd, 0x7e, 0xcf, 0xf7, 0x7b, 0xbe, 0x43, 0x0f, 0x59, 0x40, 0x5d, 0x2d, - 0x7d, 0xae, 0x3e, 0x80, 0xac, 0x36, 0x83, 0xb9, 0x14, 0x5a, 0xe0, 0x0e, 0x0b, 0xe8, 0x60, 0xcd, - 0x75, 0x0f, 0x23, 0x11, 0x89, 0x5c, 0x70, 0xb3, 0x5d, 0x51, 0xd3, 0xbd, 0x4b, 0x85, 0x8a, 0x85, - 0x72, 0x8b, 0xa5, 0x20, 0xed, 0xef, 0x4d, 0xd4, 0x7e, 0xab, 0xa2, 0x71, 0xd9, 0x8a, 0x9f, 0xa1, - 0xb6, 0x12, 0x89, 0xa4, 0x70, 0x3e, 0x17, 0x52, 0x13, 0xa3, 0x67, 0x38, 0x37, 0x47, 0x47, 0xab, - 0xd4, 0xc2, 0x17, 0x7e, 0x3c, 0x7b, 0x6e, 0x6f, 0x88, 0xb6, 0x87, 0x0a, 0x74, 0x26, 0xa4, 0xc6, - 0x2f, 0xd0, 0xad, 0x52, 0xa3, 0x13, 0x9f, 0x73, 0x98, 0x91, 0x1b, 0x79, 0xef, 0x83, 0x55, 0x6a, - 0xdd, 0xab, 0xf5, 0x96, 0xba, 0xed, 0x1d, 0x14, 0xc4, 0x49, 0x81, 0xf1, 0x3b, 0xd4, 0xf2, 0x63, - 0x91, 0x70, 0x4d, 0x9a, 0xbd, 0xa6, 0xd3, 0x7e, 0xd2, 0x19, 0x94, 0x27, 0x3d, 0x11, 0x8c, 0x8f, - 0x1e, 0x5f, 0xa6, 0x56, 0xe3, 0xdb, 0x4f, 0xcb, 0x89, 0x98, 0x9e, 0x24, 0xc1, 0x80, 0x8a, 0xd8, - 0xad, 0x0d, 0xd4, 0x57, 0xe1, 0xd4, 0xd5, 0x17, 0x73, 0x28, 0x1a, 0x94, 0x57, 0xba, 0xe1, 0x53, - 0xd4, 0x52, 0xc0, 0x43, 0x90, 0x64, 0xa7, 0x67, 0x38, 0x9d, 0xd1, 0xf1, 0xef, 0xd4, 0xea, 0xff, - 0x87, 0xcb, 0x90, 0xd2, 0x61, 0x18, 0x4a, 0x50, 0xca, 0x2b, 0x0d, 0x70, 0x17, 0xed, 0x4b, 0xa0, - 0xc0, 0x3e, 0x82, 0x24, 0xbb, 0xd9, 0x78, 0x5e, 0x85, 0xb3, 0x00, 0x34, 0x8b, 0x41, 0x24, 0xfa, - 0x7c, 0x02, 0x2c, 0x9a, 0x68, 0xd2, 0xea, 0x19, 0xce, 0xce, 0x66, 0x00, 0x75, 0xdd, 0xf6, 0x0e, - 0x4a, 0xe2, 0x75, 0x8e, 0xf1, 0x29, 0xba, 0xb3, 0xae, 0xc8, 0x56, 0xa5, 0xfd, 0x78, 0x4e, 0xf6, - 0x72, 0x93, 0x47, 0xab, 0xd4, 0x22, 0x75, 0x93, 0xaa, 0xc4, 0xf6, 0x6e, 0x97, 0xdc, 0xb8, 0xa2, - 0xbe, 0x1a, 0xe8, 0xfe, 0xab, 0x84, 0x47, 0x2c, 0x98, 0xc1, 0x58, 0x4c, 0x81, 0x9f, 0xf9, 0x74, - 0x0a, 0xfa, 0xa5, 0xaf, 0xfd, 0x8d, 0x9c, 0x8d, 0x6b, 0xcd, 0xf9, 0xa8, 0xca, 0x39, 0xff, 0xf3, - 0x5b, 0x43, 0x6b, 0xd6, 0x43, 0xb3, 0xc7, 0xc8, 0xde, 0x72, 0xcc, 0x21, 0x9d, 0x72, 0xf1, 0x69, - 0x06, 0x61, 0x04, 0x31, 0x70, 0x8d, 0x09, 0xda, 0x53, 0x09, 0xa5, 0xa0, 0x54, 0x7e, 0x21, 0xf7, - 0xbd, 0x35, 0xc4, 0x87, 0x68, 0x17, 0xa4, 0x14, 0xeb, 0x4f, 0x16, 0x60, 0xf4, 0xe6, 0x72, 0x61, - 0x1a, 0x57, 0x0b, 0xd3, 0xf8, 0xb5, 0x30, 0x8d, 0x2f, 0x4b, 0xb3, 0x71, 0xb5, 0x34, 0x1b, 0x3f, - 0x96, 0x66, 0xe3, 0xfd, 0xf1, 0x3f, 0xa7, 0xfa, 0xec, 0xb2, 0x80, 0xf6, 0xff, 0xbe, 0xb1, 0x6c, - 0xc8, 0xa0, 0x95, 0x3f, 0x94, 0xa7, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x95, 0x43, 0xad, - 0x80, 0x03, 0x00, 0x00, + // 567 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x6e, 0xd3, 0x4e, + 0x10, 0x8e, 0x9b, 0x36, 0x6d, 0x37, 0xe9, 0x4f, 0xbf, 0x6e, 0xff, 0x99, 0x82, 0xec, 0xc8, 0xa7, + 0x5c, 0x62, 0x53, 0x40, 0x42, 0xe2, 0x44, 0xd2, 0x0a, 0x51, 0x21, 0xa4, 0x6a, 0x65, 0x21, 0xc4, + 0x25, 0xb2, 0xd7, 0x83, 0x63, 0x25, 0xf6, 0x46, 0xbb, 0x6b, 0xa0, 0x6f, 0xc1, 0x73, 0xf0, 0x24, + 0x3d, 0xf6, 0xc0, 0x81, 0x93, 0x41, 0xc9, 0x1b, 0xe4, 0x08, 0x17, 0x64, 0xaf, 0xe3, 0x24, 0x52, + 0x85, 0x38, 0x70, 0xf2, 0x7e, 0x33, 0xdf, 0x7c, 0xda, 0x6f, 0x66, 0xc7, 0xe8, 0x7e, 0xe4, 0x53, + 0x47, 0x72, 0x2f, 0x11, 0xef, 0x81, 0x57, 0x07, 0x7b, 0xc2, 0x99, 0x64, 0xb8, 0x15, 0xf9, 0xd4, + 0x5e, 0xc4, 0x4e, 0x0f, 0x43, 0x16, 0xb2, 0x22, 0xe1, 0xe4, 0x27, 0xc5, 0x39, 0x3d, 0xa0, 0x4c, + 0xc4, 0x4c, 0x38, 0xea, 0xa3, 0x82, 0xd6, 0xd7, 0x3a, 0x6a, 0xbe, 0x16, 0xa1, 0x5b, 0x96, 0xe2, + 0xa7, 0xa8, 0x29, 0x58, 0xca, 0x29, 0x0c, 0x26, 0x8c, 0x4b, 0x5d, 0x6b, 0x6b, 0x9d, 0xdd, 0xfe, + 0xf1, 0x3c, 0x33, 0xf1, 0xb5, 0x17, 0x8f, 0x9f, 0x59, 0x2b, 0x49, 0x8b, 0x20, 0x85, 0xae, 0x18, + 0x97, 0xf8, 0x39, 0xfa, 0xaf, 0xcc, 0xd1, 0xa1, 0x97, 0x24, 0x30, 0xd6, 0x37, 0x8a, 0xda, 0x7b, + 0xf3, 0xcc, 0x3c, 0x5a, 0xab, 0x2d, 0xf3, 0x16, 0xd9, 0x53, 0x81, 0x73, 0x85, 0xf1, 0x1b, 0xd4, + 0xf0, 0x62, 0x96, 0x26, 0x52, 0xaf, 0xb7, 0xeb, 0x9d, 0xe6, 0xa3, 0x96, 0x5d, 0xde, 0xf4, 0x9c, + 0x45, 0x49, 0xff, 0xe1, 0x4d, 0x66, 0xd6, 0xbe, 0x7c, 0x37, 0x3b, 0x61, 0x24, 0x87, 0xa9, 0x6f, + 0x53, 0x16, 0x3b, 0x6b, 0x86, 0xba, 0x22, 0x18, 0x39, 0xf2, 0x7a, 0x02, 0xaa, 0x40, 0x90, 0x52, + 0x0d, 0x5f, 0xa2, 0x86, 0x80, 0x24, 0x00, 0xae, 0x6f, 0xb6, 0xb5, 0x4e, 0xab, 0x7f, 0xf6, 0x33, + 0x33, 0xbb, 0x7f, 0xa1, 0xd2, 0xa3, 0xb4, 0x17, 0x04, 0x1c, 0x84, 0x20, 0xa5, 0x00, 0x3e, 0x45, + 0x3b, 0x1c, 0x28, 0x44, 0x1f, 0x80, 0xeb, 0x5b, 0xb9, 0x3d, 0x52, 0xe1, 0xbc, 0x01, 0x32, 0x8a, + 0x81, 0xa5, 0x72, 0x30, 0x84, 0x28, 0x1c, 0x4a, 0xbd, 0xd1, 0xd6, 0x3a, 0x9b, 0xab, 0x0d, 0x58, + 0xcf, 0x5b, 0x64, 0xaf, 0x0c, 0xbc, 0x2c, 0x30, 0xbe, 0x44, 0xfb, 0x0b, 0x46, 0xfe, 0x15, 0xd2, + 0x8b, 0x27, 0xfa, 0x76, 0x21, 0xf2, 0x60, 0x9e, 0x99, 0xfa, 0xba, 0x48, 0x45, 0xb1, 0xc8, 0xff, + 0x65, 0xcc, 0xad, 0x42, 0xbf, 0x34, 0x74, 0xf2, 0x22, 0x4d, 0xc2, 0xc8, 0x1f, 0x83, 0xcb, 0x46, + 0x90, 0x5c, 0x79, 0x74, 0x04, 0xf2, 0xc2, 0x93, 0xde, 0x4a, 0x9f, 0xb5, 0x7f, 0xda, 0x67, 0x17, + 0xb5, 0x02, 0x48, 0x58, 0x3c, 0x90, 0xdc, 0xa3, 0x20, 0xf4, 0x8d, 0x42, 0x5d, 0xb7, 0x57, 0x9f, + 0xa6, 0x7d, 0x91, 0x33, 0xdc, 0x9c, 0xd0, 0x3f, 0x99, 0x67, 0xe6, 0x81, 0xf2, 0xb4, 0x5a, 0x67, + 0x91, 0x66, 0x50, 0x91, 0x04, 0x3e, 0xae, 0xa6, 0x57, 0x2f, 0x1a, 0x7e, 0xd7, 0x28, 0x36, 0xd7, + 0x47, 0x61, 0xb9, 0xc8, 0xba, 0xc3, 0x7c, 0x8f, 0x8e, 0x12, 0xf6, 0x71, 0x0c, 0x41, 0x08, 0x31, + 0x24, 0x12, 0xeb, 0x68, 0x5b, 0xa4, 0x94, 0x82, 0x10, 0xc5, 0x33, 0xdf, 0x21, 0x0b, 0x88, 0x0f, + 0xd1, 0x16, 0x70, 0xce, 0xb8, 0x7a, 0xc2, 0x44, 0x01, 0xeb, 0x2d, 0x42, 0xcb, 0xdb, 0xe7, 0x9c, + 0xe2, 0xbe, 0x6a, 0x45, 0x88, 0x02, 0xf8, 0x09, 0x42, 0xbe, 0x27, 0x60, 0x50, 0x38, 0x28, 0x37, + 0xe0, 0x68, 0x9e, 0x99, 0xfb, 0xca, 0xe7, 0x32, 0x67, 0x91, 0xdd, 0x1c, 0x14, 0x82, 0xfd, 0x57, + 0x37, 0x53, 0x43, 0xbb, 0x9d, 0x1a, 0xda, 0x8f, 0xa9, 0xa1, 0x7d, 0x9e, 0x19, 0xb5, 0xdb, 0x99, + 0x51, 0xfb, 0x36, 0x33, 0x6a, 0xef, 0xce, 0xfe, 0x38, 0x85, 0x4f, 0x4e, 0xe4, 0xd3, 0xee, 0xf2, + 0x9f, 0x90, 0x0f, 0xc5, 0x6f, 0x14, 0x8b, 0xfd, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x85, + 0xa3, 0xa5, 0x23, 0x30, 0x04, 0x00, 0x00, } func (m *MsgTransfer) Marshal() (dAtA []byte, err error) { @@ -391,14 +462,28 @@ func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) copy(dAtA[i:], m.Receiver) i = encodeVarintTransfer(dAtA, i, uint64(len(m.Receiver))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 } if len(m.Sender) > 0 { i -= len(m.Sender) copy(dAtA[i:], m.Sender) i = encodeVarintTransfer(dAtA, i, uint64(len(m.Sender))) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a + } + if len(m.DenomTraces) > 0 { + for iNdEx := len(m.DenomTraces) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DenomTraces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTransfer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } } if len(m.Amount) > 0 { for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { @@ -457,6 +542,43 @@ func (m *FungibleTokenPacketAcknowledgement) MarshalToSizedBuffer(dAtA []byte) ( return len(dAtA) - i, nil } +func (m *DenomTrace) 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 *DenomTrace) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DenomTrace) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BaseDenom) > 0 { + i -= len(m.BaseDenom) + copy(dAtA[i:], m.BaseDenom) + i = encodeVarintTransfer(dAtA, i, uint64(len(m.BaseDenom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Trace) > 0 { + i -= len(m.Trace) + copy(dAtA[i:], m.Trace) + i = encodeVarintTransfer(dAtA, i, uint64(len(m.Trace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintTransfer(dAtA []byte, offset int, v uint64) int { offset -= sovTransfer(v) base := offset @@ -517,6 +639,12 @@ func (m *FungibleTokenPacketData) Size() (n int) { n += 1 + l + sovTransfer(uint64(l)) } } + if len(m.DenomTraces) > 0 { + for _, e := range m.DenomTraces { + l = e.Size() + n += 1 + l + sovTransfer(uint64(l)) + } + } l = len(m.Sender) if l > 0 { n += 1 + l + sovTransfer(uint64(l)) @@ -544,6 +672,23 @@ func (m *FungibleTokenPacketAcknowledgement) Size() (n int) { return n } +func (m *DenomTrace) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Trace) + if l > 0 { + n += 1 + l + sovTransfer(uint64(l)) + } + l = len(m.BaseDenom) + if l > 0 { + n += 1 + l + sovTransfer(uint64(l)) + } + return n +} + func sovTransfer(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -869,6 +1014,40 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomTraces", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTransfer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DenomTraces = append(m.DenomTraces, &DenomTrace{}) + if err := m.DenomTraces[len(m.DenomTraces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) } @@ -900,7 +1079,7 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { } m.Sender = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) } @@ -1061,6 +1240,123 @@ func (m *FungibleTokenPacketAcknowledgement) Unmarshal(dAtA []byte) error { } return nil } +func (m *DenomTrace) 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 ErrIntOverflowTransfer + } + 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: DenomTrace: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DenomTrace: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + 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 ErrInvalidLengthTransfer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Trace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + 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 ErrInvalidLengthTransfer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BaseDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTransfer(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTransfer + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTransfer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTransfer(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 2c0529faf92648002a52150dd0d2cb3022e7c14e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 28 Jul 2020 23:02:50 +0200 Subject: [PATCH 02/41] gRPC proto file --- proto/ibc/transfer/genesis.proto | 14 +- proto/ibc/transfer/query.proto | 41 + proto/ibc/transfer/transfer.proto | 11 + x/ibc-transfer/types/genesis.pb.go | 331 +-------- x/ibc-transfer/types/query.pb.go | 1072 +++++++++++++++++++++++++++ x/ibc-transfer/types/transfer.pb.go | 356 ++++++++- 6 files changed, 1467 insertions(+), 358 deletions(-) create mode 100644 proto/ibc/transfer/query.proto create mode 100644 x/ibc-transfer/types/query.pb.go diff --git a/proto/ibc/transfer/genesis.proto b/proto/ibc/transfer/genesis.proto index 607430e69df2..ce703119b8bd 100644 --- a/proto/ibc/transfer/genesis.proto +++ b/proto/ibc/transfer/genesis.proto @@ -4,7 +4,6 @@ package ibc.transfer; option go_package = "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"; import "gogoproto/gogo.proto"; -import "cosmos/cosmos.proto"; import "ibc/transfer/transfer.proto"; // GenesisState defines the ibc-transfer genesis state @@ -13,16 +12,5 @@ message GenesisState{ (gogoproto.customname) = "PortID", (gogoproto.moretags) = "yaml:\"port_id\"" ]; - repeated GenesisDenomTrace denom_traces = 2 [(gogoproto.moretags) = "yaml:\"denom_traces\""]; + repeated IdentifiedDenomTrace denom_traces = 2 [(gogoproto.moretags) = "yaml:\"denom_traces\""]; } - - -// GenesisDenomTrace contains DenomTrace and the hash used for the IBC fungible denom map. -message GenesisDenomTrace { - // chain of port/channel identifiers used for tracing the source of the fungible token - string trace = 1; - // base denomination of the relayed fungible token - string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; - // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) - bytes hash = 3; -} \ No newline at end of file diff --git a/proto/ibc/transfer/query.proto b/proto/ibc/transfer/query.proto new file mode 100644 index 000000000000..f3d33ccee29c --- /dev/null +++ b/proto/ibc/transfer/query.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; +package ibc.transfer; + +import "cosmos/query/pagination.proto"; +import "ibc/transfer/transfer.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"; + +// Query provides defines the gRPC querier service +service Query { + // DenomTrace queries an IBC connection end. + rpc DenomTrace(QueryDenomTraceRequest) returns (QueryDenomTraceResponse) {} + + // DenomTraces queries all the IBC connections of a chain. + rpc DenomTraces(QueryDenomTracesRequest) returns (QueryDenomTracesResponse) {} +} + +// QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC method +message QueryDenomTraceRequest { + // hex hash of the denomination trace info + string hash = 1; +} + +// QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC method. +message QueryDenomTraceResponse { + // denomination trace associated with the request hash + ibc.transfer.DenomTrace denom_trace = 1; +} + +// QueryConnectionsRequest is the request type for the Query/Connections RPC method +message QueryDenomTracesRequest { + cosmos.query.PageRequest pagination = 1; +} + +// QueryConnectionsResponse is the response type for the Query/Connections RPC method. +message QueryDenomTracesResponse { + // list of stored connections of the chain. + repeated ibc.transfer.IdentifiedDenomTrace denom_traces = 1; + // pagination response + cosmos.query.PageResponse pagination = 2; +} diff --git a/proto/ibc/transfer/transfer.proto b/proto/ibc/transfer/transfer.proto index 3edee632b989..91c4f12155e4 100644 --- a/proto/ibc/transfer/transfer.proto +++ b/proto/ibc/transfer/transfer.proto @@ -68,3 +68,14 @@ message DenomTrace { // base denomination of the relayed fungible token string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; } + + +// IdentifiedDenomTrace contains DenomTrace and the hash used for the IBC fungible denom map. +message IdentifiedDenomTrace { + // chain of port/channel identifiers used for tracing the source of the fungible token + string trace = 1; + // base denomination of the relayed fungible token + string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; + // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) + bytes hash = 3; +} \ No newline at end of file diff --git a/x/ibc-transfer/types/genesis.pb.go b/x/ibc-transfer/types/genesis.pb.go index 4d835524f316..8b3e76fcaec3 100644 --- a/x/ibc-transfer/types/genesis.pb.go +++ b/x/ibc-transfer/types/genesis.pb.go @@ -5,7 +5,6 @@ package types import ( fmt "fmt" - _ "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -26,8 +25,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the ibc-transfer genesis state type GenesisState struct { - PortID string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` - DenomTraces []*GenesisDenomTrace `protobuf:"bytes,2,rep,name=denom_traces,json=denomTraces,proto3" json:"denom_traces,omitempty" yaml:"denom_traces"` + PortID string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + DenomTraces []*IdentifiedDenomTrace `protobuf:"bytes,2,rep,name=denom_traces,json=denomTraces,proto3" json:"denom_traces,omitempty" yaml:"denom_traces"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -70,107 +69,39 @@ func (m *GenesisState) GetPortID() string { return "" } -func (m *GenesisState) GetDenomTraces() []*GenesisDenomTrace { +func (m *GenesisState) GetDenomTraces() []*IdentifiedDenomTrace { if m != nil { return m.DenomTraces } return nil } -// GenesisDenomTrace contains DenomTrace and the hash used for the IBC fungible denom map. -type GenesisDenomTrace struct { - // chain of port/channel identifiers used for tracing the source of the fungible token - Trace string `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` - // base denomination of the relayed fungible token - BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty" yaml:"base_denom"` - // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) - Hash []byte `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` -} - -func (m *GenesisDenomTrace) Reset() { *m = GenesisDenomTrace{} } -func (m *GenesisDenomTrace) String() string { return proto.CompactTextString(m) } -func (*GenesisDenomTrace) ProtoMessage() {} -func (*GenesisDenomTrace) Descriptor() ([]byte, []int) { - return fileDescriptor_c13b8463155e05c2, []int{1} -} -func (m *GenesisDenomTrace) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *GenesisDenomTrace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_GenesisDenomTrace.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 *GenesisDenomTrace) XXX_Merge(src proto.Message) { - xxx_messageInfo_GenesisDenomTrace.Merge(m, src) -} -func (m *GenesisDenomTrace) XXX_Size() int { - return m.Size() -} -func (m *GenesisDenomTrace) XXX_DiscardUnknown() { - xxx_messageInfo_GenesisDenomTrace.DiscardUnknown(m) -} - -var xxx_messageInfo_GenesisDenomTrace proto.InternalMessageInfo - -func (m *GenesisDenomTrace) GetTrace() string { - if m != nil { - return m.Trace - } - return "" -} - -func (m *GenesisDenomTrace) GetBaseDenom() string { - if m != nil { - return m.BaseDenom - } - return "" -} - -func (m *GenesisDenomTrace) GetHash() []byte { - if m != nil { - return m.Hash - } - return nil -} - func init() { proto.RegisterType((*GenesisState)(nil), "ibc.transfer.GenesisState") - proto.RegisterType((*GenesisDenomTrace)(nil), "ibc.transfer.GenesisDenomTrace") } func init() { proto.RegisterFile("ibc/transfer/genesis.proto", fileDescriptor_c13b8463155e05c2) } var fileDescriptor_c13b8463155e05c2 = []byte{ - // 336 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xcb, 0x4e, 0xc2, 0x40, - 0x14, 0x86, 0x19, 0x50, 0x0c, 0x43, 0x63, 0xc2, 0x80, 0xb1, 0x41, 0xd3, 0x92, 0xae, 0xd8, 0xd0, - 0x89, 0xb7, 0x8d, 0x4b, 0x42, 0x62, 0x88, 0x1b, 0x53, 0x5d, 0xe9, 0x82, 0xf4, 0x32, 0x96, 0x46, - 0xcb, 0x90, 0x39, 0x63, 0x22, 0x6f, 0xe1, 0x33, 0xf8, 0x34, 0x2e, 0x59, 0xba, 0x6a, 0x4c, 0x79, - 0x03, 0x9e, 0xc0, 0x74, 0x06, 0x04, 0xe2, 0xaa, 0xff, 0xe9, 0xff, 0x9d, 0xcb, 0xfc, 0xb8, 0x9d, - 0x04, 0x21, 0x95, 0xc2, 0x9f, 0xc0, 0x33, 0x13, 0x34, 0x66, 0x13, 0x06, 0x09, 0xb8, 0x53, 0xc1, - 0x25, 0x27, 0x46, 0x12, 0x84, 0xee, 0xda, 0x6b, 0xb7, 0x62, 0x1e, 0x73, 0x65, 0xd0, 0x42, 0x69, - 0xa6, 0xdd, 0x0c, 0x39, 0xa4, 0x1c, 0xa8, 0xfe, 0xac, 0x7e, 0x9e, 0xec, 0x0c, 0x5d, 0x0b, 0x6d, - 0x3a, 0x9f, 0x08, 0x1b, 0x37, 0x7a, 0xcf, 0xbd, 0xf4, 0x25, 0x23, 0x57, 0xf8, 0x60, 0xca, 0x85, - 0x1c, 0x25, 0x91, 0x89, 0x3a, 0xa8, 0x5b, 0xeb, 0x9f, 0xe6, 0x99, 0x5d, 0xbd, 0xe3, 0x42, 0x0e, - 0x07, 0xcb, 0xcc, 0x3e, 0x9c, 0xf9, 0xe9, 0xeb, 0xb5, 0xb3, 0x42, 0x1c, 0xaf, 0x5a, 0xa8, 0x61, - 0x44, 0x9e, 0xb0, 0x11, 0xb1, 0x09, 0x4f, 0x47, 0x52, 0xf8, 0x21, 0x03, 0xb3, 0xdc, 0xa9, 0x74, - 0xeb, 0xe7, 0xb6, 0xbb, 0x7d, 0xb4, 0xbb, 0x5a, 0x34, 0x28, 0xc0, 0x87, 0x82, 0xeb, 0x1f, 0x2f, - 0x33, 0xbb, 0xa9, 0x47, 0x6e, 0xb7, 0x3b, 0x5e, 0x3d, 0xfa, 0x83, 0xc0, 0x01, 0xdc, 0xf8, 0xd7, - 0x4a, 0x5a, 0x78, 0x5f, 0xc1, 0xfa, 0x4c, 0x4f, 0x17, 0xe4, 0x12, 0xe3, 0xc0, 0x07, 0x36, 0x52, - 0xed, 0x66, 0x59, 0xbd, 0xe0, 0x68, 0x99, 0xd9, 0x0d, 0xbd, 0x64, 0xe3, 0x39, 0x5e, 0xad, 0x28, - 0xd4, 0x40, 0x42, 0xf0, 0xde, 0xd8, 0x87, 0xb1, 0x59, 0xe9, 0xa0, 0xae, 0xe1, 0x29, 0xdd, 0xbf, - 0xfd, 0xca, 0x2d, 0x34, 0xcf, 0x2d, 0xf4, 0x93, 0x5b, 0xe8, 0x63, 0x61, 0x95, 0xe6, 0x0b, 0xab, - 0xf4, 0xbd, 0xb0, 0x4a, 0x8f, 0x67, 0x71, 0x22, 0xc7, 0x6f, 0x81, 0x1b, 0xf2, 0x94, 0xee, 0x04, - 0xde, 0x83, 0xe8, 0x85, 0xbe, 0xd3, 0x24, 0x08, 0x7b, 0x9b, 0xbc, 0x67, 0x53, 0x06, 0x41, 0x55, - 0xa5, 0x7d, 0xf1, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x9d, 0xec, 0x92, 0xe1, 0x01, 0x00, 0x00, + // 274 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xca, 0x4c, 0x4a, 0xd6, + 0x2f, 0x29, 0x4a, 0xcc, 0x2b, 0x4e, 0x4b, 0x2d, 0xd2, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, + 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xc9, 0x4c, 0x4a, 0xd6, 0x83, 0xc9, 0x49, 0x89, + 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf4, 0x41, 0x2c, 0x88, 0x1a, 0x29, 0x69, 0x14, 0xfd, 0x30, + 0x06, 0x44, 0x52, 0x69, 0x29, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xc8, 0xe0, 0x92, 0xc4, 0x92, 0x54, + 0x21, 0x53, 0x2e, 0xf6, 0x82, 0xfc, 0xa2, 0x92, 0xf8, 0xcc, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, + 0x4e, 0x27, 0x99, 0x47, 0xf7, 0xe4, 0xd9, 0x02, 0xf2, 0x8b, 0x4a, 0x3c, 0x5d, 0x3e, 0xdd, 0x93, + 0xe7, 0xab, 0x4c, 0xcc, 0xcd, 0xb1, 0x52, 0x82, 0x2a, 0x51, 0x0a, 0x62, 0x03, 0xb1, 0x3c, 0x53, + 0x84, 0xe2, 0xb8, 0x78, 0x52, 0x52, 0xf3, 0xf2, 0x73, 0xe3, 0x4b, 0x8a, 0x12, 0x93, 0x53, 0x8b, + 0x25, 0x98, 0x14, 0x98, 0x35, 0xb8, 0x8d, 0x94, 0xf4, 0x90, 0xdd, 0xa7, 0xe7, 0x99, 0x92, 0x9a, + 0x57, 0x92, 0x99, 0x96, 0x99, 0x9a, 0xe2, 0x02, 0x52, 0x1b, 0x02, 0x52, 0xea, 0x24, 0xfe, 0xe9, + 0x9e, 0xbc, 0x30, 0xc4, 0x54, 0x64, 0x13, 0x94, 0x82, 0xb8, 0x53, 0xe0, 0x8a, 0x8a, 0x9d, 0xbc, + 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, + 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x30, 0x3d, 0xb3, 0x24, 0xa3, + 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x3f, 0x39, 0xbf, 0x38, 0x37, 0xbf, 0x18, 0x4a, 0xe9, 0x16, + 0xa7, 0x64, 0xeb, 0x57, 0xe8, 0x67, 0x26, 0x25, 0xeb, 0x22, 0x7c, 0x5f, 0x59, 0x90, 0x5a, 0x9c, + 0xc4, 0x06, 0xf6, 0xbb, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x03, 0xe9, 0xd6, 0x5a, 0x01, + 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -217,50 +148,6 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *GenesisDenomTrace) 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 *GenesisDenomTrace) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *GenesisDenomTrace) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Hash) > 0 { - i -= len(m.Hash) - copy(dAtA[i:], m.Hash) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.Hash))) - i-- - dAtA[i] = 0x1a - } - if len(m.BaseDenom) > 0 { - i -= len(m.BaseDenom) - copy(dAtA[i:], m.BaseDenom) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.BaseDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.Trace) > 0 { - i -= len(m.Trace) - copy(dAtA[i:], m.Trace) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.Trace))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -291,27 +178,6 @@ func (m *GenesisState) Size() (n int) { return n } -func (m *GenesisDenomTrace) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Trace) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - l = len(m.BaseDenom) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - l = len(m.Hash) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - return n -} - func sovGenesis(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -408,7 +274,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DenomTraces = append(m.DenomTraces, &GenesisDenomTrace{}) + m.DenomTraces = append(m.DenomTraces, &IdentifiedDenomTrace{}) if err := m.DenomTraces[len(m.DenomTraces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -437,157 +303,6 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } return nil } -func (m *GenesisDenomTrace) 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 ErrIntOverflowGenesis - } - 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: GenesisDenomTrace: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: GenesisDenomTrace: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - 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 ErrInvalidLengthGenesis - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Trace = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BaseDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - 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 ErrInvalidLengthGenesis - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.BaseDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) - if m.Hash == nil { - m.Hash = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipGenesis(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ibc-transfer/types/query.pb.go b/x/ibc-transfer/types/query.pb.go new file mode 100644 index 000000000000..60dd8c808d4e --- /dev/null +++ b/x/ibc-transfer/types/query.pb.go @@ -0,0 +1,1072 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/transfer/query.proto + +package types + +import ( + context "context" + fmt "fmt" + query "github.com/cosmos/cosmos-sdk/types/query" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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 + +// QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC method +type QueryDenomTraceRequest struct { + // hex hash of the denomination trace info + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (m *QueryDenomTraceRequest) Reset() { *m = QueryDenomTraceRequest{} } +func (m *QueryDenomTraceRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDenomTraceRequest) ProtoMessage() {} +func (*QueryDenomTraceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_26b3e8b4e9dff1c1, []int{0} +} +func (m *QueryDenomTraceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomTraceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomTraceRequest.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 *QueryDenomTraceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomTraceRequest.Merge(m, src) +} +func (m *QueryDenomTraceRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomTraceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomTraceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomTraceRequest proto.InternalMessageInfo + +func (m *QueryDenomTraceRequest) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + +// QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC method. +type QueryDenomTraceResponse struct { + // denomination trace associated with the request hash + DenomTrace *DenomTrace `protobuf:"bytes,1,opt,name=denom_trace,json=denomTrace,proto3" json:"denom_trace,omitempty"` +} + +func (m *QueryDenomTraceResponse) Reset() { *m = QueryDenomTraceResponse{} } +func (m *QueryDenomTraceResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDenomTraceResponse) ProtoMessage() {} +func (*QueryDenomTraceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_26b3e8b4e9dff1c1, []int{1} +} +func (m *QueryDenomTraceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomTraceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomTraceResponse.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 *QueryDenomTraceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomTraceResponse.Merge(m, src) +} +func (m *QueryDenomTraceResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomTraceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomTraceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomTraceResponse proto.InternalMessageInfo + +func (m *QueryDenomTraceResponse) GetDenomTrace() *DenomTrace { + if m != nil { + return m.DenomTrace + } + return nil +} + +// QueryConnectionsRequest is the request type for the Query/Connections RPC method +type QueryDenomTracesRequest struct { + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryDenomTracesRequest) Reset() { *m = QueryDenomTracesRequest{} } +func (m *QueryDenomTracesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDenomTracesRequest) ProtoMessage() {} +func (*QueryDenomTracesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_26b3e8b4e9dff1c1, []int{2} +} +func (m *QueryDenomTracesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomTracesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomTracesRequest.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 *QueryDenomTracesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomTracesRequest.Merge(m, src) +} +func (m *QueryDenomTracesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomTracesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomTracesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomTracesRequest proto.InternalMessageInfo + +func (m *QueryDenomTracesRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryConnectionsResponse is the response type for the Query/Connections RPC method. +type QueryDenomTracesResponse struct { + // list of stored connections of the chain. + DenomTraces []*IdentifiedDenomTrace `protobuf:"bytes,1,rep,name=denom_traces,json=denomTraces,proto3" json:"denom_traces,omitempty"` + // pagination response + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryDenomTracesResponse) Reset() { *m = QueryDenomTracesResponse{} } +func (m *QueryDenomTracesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDenomTracesResponse) ProtoMessage() {} +func (*QueryDenomTracesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_26b3e8b4e9dff1c1, []int{3} +} +func (m *QueryDenomTracesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomTracesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomTracesResponse.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 *QueryDenomTracesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomTracesResponse.Merge(m, src) +} +func (m *QueryDenomTracesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomTracesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomTracesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomTracesResponse proto.InternalMessageInfo + +func (m *QueryDenomTracesResponse) GetDenomTraces() []*IdentifiedDenomTrace { + if m != nil { + return m.DenomTraces + } + return nil +} + +func (m *QueryDenomTracesResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +func init() { + proto.RegisterType((*QueryDenomTraceRequest)(nil), "ibc.transfer.QueryDenomTraceRequest") + proto.RegisterType((*QueryDenomTraceResponse)(nil), "ibc.transfer.QueryDenomTraceResponse") + proto.RegisterType((*QueryDenomTracesRequest)(nil), "ibc.transfer.QueryDenomTracesRequest") + proto.RegisterType((*QueryDenomTracesResponse)(nil), "ibc.transfer.QueryDenomTracesResponse") +} + +func init() { proto.RegisterFile("ibc/transfer/query.proto", fileDescriptor_26b3e8b4e9dff1c1) } + +var fileDescriptor_26b3e8b4e9dff1c1 = []byte{ + // 364 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xbd, 0x4e, 0xc3, 0x30, + 0x14, 0x85, 0x63, 0xfe, 0x24, 0x6e, 0x3a, 0x79, 0x80, 0x10, 0x44, 0x54, 0x45, 0x80, 0x3a, 0x50, + 0x47, 0x94, 0xa9, 0x8c, 0x08, 0x06, 0xc4, 0x02, 0x55, 0x27, 0x90, 0x40, 0xf9, 0x71, 0x5b, 0x0b, + 0x35, 0x4e, 0x63, 0x57, 0xa2, 0x6f, 0xc1, 0x0b, 0xf0, 0x36, 0x0c, 0x8c, 0x1d, 0x19, 0x51, 0xfb, + 0x22, 0xa8, 0x71, 0x43, 0x1c, 0x35, 0xa2, 0x53, 0xae, 0xec, 0x73, 0xce, 0xfd, 0x7c, 0x73, 0xc1, + 0x62, 0x41, 0xe8, 0xc9, 0xd4, 0x8f, 0x45, 0x8f, 0xa6, 0xde, 0x68, 0x4c, 0xd3, 0x09, 0x49, 0x52, + 0x2e, 0x39, 0xae, 0xb1, 0x20, 0x24, 0xf9, 0x8d, 0x7d, 0x14, 0x72, 0x31, 0xe4, 0x42, 0x29, 0xbc, + 0xc4, 0xef, 0xb3, 0xd8, 0x97, 0x8c, 0xc7, 0x4a, 0x6c, 0x1f, 0x96, 0x62, 0xf2, 0x42, 0x5d, 0xba, + 0x67, 0xb0, 0xf7, 0xb0, 0xb0, 0x5d, 0xd3, 0x98, 0x0f, 0xbb, 0xa9, 0x1f, 0xd2, 0x0e, 0x1d, 0x8d, + 0xa9, 0x90, 0x18, 0xc3, 0xd6, 0xc0, 0x17, 0x03, 0x0b, 0xd5, 0x51, 0x63, 0xb7, 0x93, 0xd5, 0x6e, + 0x17, 0xf6, 0x57, 0xd4, 0x22, 0xe1, 0xb1, 0xa0, 0xb8, 0x0d, 0x66, 0xb4, 0x38, 0x7d, 0x91, 0x8b, + 0xe3, 0xcc, 0x65, 0xb6, 0x2c, 0xa2, 0x83, 0x12, 0xcd, 0x06, 0xd1, 0x5f, 0x5d, 0x91, 0x2a, 0x72, + 0x88, 0x36, 0x40, 0xf1, 0x9e, 0x65, 0xe8, 0x01, 0x51, 0xef, 0x25, 0x6a, 0x22, 0xf7, 0x7e, 0x3f, + 0x67, 0xee, 0x68, 0x62, 0xf7, 0x03, 0x81, 0xb5, 0x1a, 0xbb, 0xa4, 0xbd, 0x81, 0x9a, 0x46, 0x2b, + 0x2c, 0x54, 0xdf, 0x6c, 0x98, 0x2d, 0xb7, 0x8c, 0x7b, 0x1b, 0xd1, 0x58, 0xb2, 0x1e, 0xa3, 0x91, + 0x06, 0x6e, 0x16, 0xe0, 0x02, 0x5f, 0x96, 0xf0, 0x36, 0x32, 0x3c, 0xbb, 0x0a, 0x4f, 0xb5, 0xd5, + 0xf9, 0x5a, 0x9f, 0x08, 0xb6, 0x33, 0x3e, 0xfc, 0x04, 0x50, 0x34, 0xc0, 0xc7, 0x65, 0x88, 0xea, + 0xbf, 0x63, 0x9f, 0xac, 0x51, 0xa9, 0x86, 0xae, 0x81, 0x9f, 0xc1, 0xd4, 0x06, 0x80, 0xff, 0xf7, + 0xe5, 0x73, 0xb7, 0x4f, 0xd7, 0xc9, 0xf2, 0xfc, 0xab, 0xbb, 0xaf, 0x99, 0x83, 0xa6, 0x33, 0x07, + 0xfd, 0xcc, 0x1c, 0xf4, 0x3e, 0x77, 0x8c, 0xe9, 0xdc, 0x31, 0xbe, 0xe7, 0x8e, 0xf1, 0x78, 0xde, + 0x67, 0x72, 0x30, 0x0e, 0x48, 0xc8, 0x87, 0xde, 0x72, 0x43, 0xd5, 0xa7, 0x29, 0xa2, 0x57, 0xef, + 0xcd, 0x63, 0x41, 0xd8, 0x2c, 0xd6, 0x72, 0x92, 0x50, 0x11, 0xec, 0x64, 0x4b, 0x79, 0xf1, 0x1b, + 0x00, 0x00, 0xff, 0xff, 0xbc, 0xb2, 0x05, 0x8d, 0xfa, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // DenomTrace queries an IBC connection end. + DenomTrace(ctx context.Context, in *QueryDenomTraceRequest, opts ...grpc.CallOption) (*QueryDenomTraceResponse, error) + // DenomTraces queries all the IBC connections of a chain. + DenomTraces(ctx context.Context, in *QueryDenomTracesRequest, opts ...grpc.CallOption) (*QueryDenomTracesResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) DenomTrace(ctx context.Context, in *QueryDenomTraceRequest, opts ...grpc.CallOption) (*QueryDenomTraceResponse, error) { + out := new(QueryDenomTraceResponse) + err := c.cc.Invoke(ctx, "/ibc.transfer.Query/DenomTrace", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) DenomTraces(ctx context.Context, in *QueryDenomTracesRequest, opts ...grpc.CallOption) (*QueryDenomTracesResponse, error) { + out := new(QueryDenomTracesResponse) + err := c.cc.Invoke(ctx, "/ibc.transfer.Query/DenomTraces", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // DenomTrace queries an IBC connection end. + DenomTrace(context.Context, *QueryDenomTraceRequest) (*QueryDenomTraceResponse, error) + // DenomTraces queries all the IBC connections of a chain. + DenomTraces(context.Context, *QueryDenomTracesRequest) (*QueryDenomTracesResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) DenomTrace(ctx context.Context, req *QueryDenomTraceRequest) (*QueryDenomTraceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomTrace not implemented") +} +func (*UnimplementedQueryServer) DenomTraces(ctx context.Context, req *QueryDenomTracesRequest) (*QueryDenomTracesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomTraces not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_DenomTrace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDenomTraceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomTrace(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.transfer.Query/DenomTrace", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomTrace(ctx, req.(*QueryDenomTraceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_DenomTraces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDenomTracesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomTraces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.transfer.Query/DenomTraces", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomTraces(ctx, req.(*QueryDenomTracesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.transfer.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "DenomTrace", + Handler: _Query_DenomTrace_Handler, + }, + { + MethodName: "DenomTraces", + Handler: _Query_DenomTraces_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ibc/transfer/query.proto", +} + +func (m *QueryDenomTraceRequest) 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 *QueryDenomTraceRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomTraceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomTraceResponse) 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 *QueryDenomTraceResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomTraceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DenomTrace != nil { + { + size, err := m.DenomTrace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomTracesRequest) 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 *QueryDenomTracesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomTracesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomTracesResponse) 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 *QueryDenomTracesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomTracesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.DenomTraces) > 0 { + for iNdEx := len(m.DenomTraces) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DenomTraces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryDenomTraceRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomTraceResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DenomTrace != nil { + l = m.DenomTrace.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomTracesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomTracesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.DenomTraces) > 0 { + for _, e := range m.DenomTraces { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryDenomTraceRequest) 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 ErrIntOverflowQuery + } + 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: QueryDenomTraceRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomTraceRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomTraceResponse) 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 ErrIntOverflowQuery + } + 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: QueryDenomTraceResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomTraceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomTrace", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.DenomTrace == nil { + m.DenomTrace = &DenomTrace{} + } + if err := m.DenomTrace.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomTracesRequest) 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 ErrIntOverflowQuery + } + 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: QueryDenomTracesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomTracesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomTracesResponse) 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 ErrIntOverflowQuery + } + 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: QueryDenomTracesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomTracesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomTraces", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DenomTraces = append(m.DenomTraces, &IdentifiedDenomTrace{}) + if err := m.DenomTraces[len(m.DenomTraces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ibc-transfer/types/transfer.pb.go b/x/ibc-transfer/types/transfer.pb.go index e015743e27db..a8f5a3dfe174 100644 --- a/x/ibc-transfer/types/transfer.pb.go +++ b/x/ibc-transfer/types/transfer.pb.go @@ -313,53 +313,119 @@ func (m *DenomTrace) GetBaseDenom() string { return "" } +// IdentifiedDenomTrace contains DenomTrace and the hash used for the IBC fungible denom map. +type IdentifiedDenomTrace struct { + // chain of port/channel identifiers used for tracing the source of the fungible token + Trace string `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` + // base denomination of the relayed fungible token + BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty" yaml:"base_denom"` + // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) + Hash []byte `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (m *IdentifiedDenomTrace) Reset() { *m = IdentifiedDenomTrace{} } +func (m *IdentifiedDenomTrace) String() string { return proto.CompactTextString(m) } +func (*IdentifiedDenomTrace) ProtoMessage() {} +func (*IdentifiedDenomTrace) Descriptor() ([]byte, []int) { + return fileDescriptor_08134a70fd29e656, []int{4} +} +func (m *IdentifiedDenomTrace) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IdentifiedDenomTrace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IdentifiedDenomTrace.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 *IdentifiedDenomTrace) XXX_Merge(src proto.Message) { + xxx_messageInfo_IdentifiedDenomTrace.Merge(m, src) +} +func (m *IdentifiedDenomTrace) XXX_Size() int { + return m.Size() +} +func (m *IdentifiedDenomTrace) XXX_DiscardUnknown() { + xxx_messageInfo_IdentifiedDenomTrace.DiscardUnknown(m) +} + +var xxx_messageInfo_IdentifiedDenomTrace proto.InternalMessageInfo + +func (m *IdentifiedDenomTrace) GetTrace() string { + if m != nil { + return m.Trace + } + return "" +} + +func (m *IdentifiedDenomTrace) GetBaseDenom() string { + if m != nil { + return m.BaseDenom + } + return "" +} + +func (m *IdentifiedDenomTrace) GetHash() []byte { + if m != nil { + return m.Hash + } + return nil +} + func init() { proto.RegisterType((*MsgTransfer)(nil), "ibc.transfer.MsgTransfer") proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.transfer.FungibleTokenPacketData") proto.RegisterType((*FungibleTokenPacketAcknowledgement)(nil), "ibc.transfer.FungibleTokenPacketAcknowledgement") proto.RegisterType((*DenomTrace)(nil), "ibc.transfer.DenomTrace") + proto.RegisterType((*IdentifiedDenomTrace)(nil), "ibc.transfer.IdentifiedDenomTrace") } func init() { proto.RegisterFile("ibc/transfer/transfer.proto", fileDescriptor_08134a70fd29e656) } var fileDescriptor_08134a70fd29e656 = []byte{ - // 567 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x6e, 0xd3, 0x4e, - 0x10, 0x8e, 0x9b, 0x36, 0x6d, 0x37, 0xe9, 0x4f, 0xbf, 0x6e, 0xff, 0x99, 0x82, 0xec, 0xc8, 0xa7, - 0x5c, 0x62, 0x53, 0x40, 0x42, 0xe2, 0x44, 0xd2, 0x0a, 0x51, 0x21, 0xa4, 0x6a, 0x65, 0x21, 0xc4, - 0x25, 0xb2, 0xd7, 0x83, 0x63, 0x25, 0xf6, 0x46, 0xbb, 0x6b, 0xa0, 0x6f, 0xc1, 0x73, 0xf0, 0x24, - 0x3d, 0xf6, 0xc0, 0x81, 0x93, 0x41, 0xc9, 0x1b, 0xe4, 0x08, 0x17, 0x64, 0xaf, 0xe3, 0x24, 0x52, - 0x85, 0x38, 0x70, 0xf2, 0x7e, 0x33, 0xdf, 0x7c, 0xda, 0x6f, 0x66, 0xc7, 0xe8, 0x7e, 0xe4, 0x53, - 0x47, 0x72, 0x2f, 0x11, 0xef, 0x81, 0x57, 0x07, 0x7b, 0xc2, 0x99, 0x64, 0xb8, 0x15, 0xf9, 0xd4, - 0x5e, 0xc4, 0x4e, 0x0f, 0x43, 0x16, 0xb2, 0x22, 0xe1, 0xe4, 0x27, 0xc5, 0x39, 0x3d, 0xa0, 0x4c, - 0xc4, 0x4c, 0x38, 0xea, 0xa3, 0x82, 0xd6, 0xd7, 0x3a, 0x6a, 0xbe, 0x16, 0xa1, 0x5b, 0x96, 0xe2, - 0xa7, 0xa8, 0x29, 0x58, 0xca, 0x29, 0x0c, 0x26, 0x8c, 0x4b, 0x5d, 0x6b, 0x6b, 0x9d, 0xdd, 0xfe, - 0xf1, 0x3c, 0x33, 0xf1, 0xb5, 0x17, 0x8f, 0x9f, 0x59, 0x2b, 0x49, 0x8b, 0x20, 0x85, 0xae, 0x18, - 0x97, 0xf8, 0x39, 0xfa, 0xaf, 0xcc, 0xd1, 0xa1, 0x97, 0x24, 0x30, 0xd6, 0x37, 0x8a, 0xda, 0x7b, - 0xf3, 0xcc, 0x3c, 0x5a, 0xab, 0x2d, 0xf3, 0x16, 0xd9, 0x53, 0x81, 0x73, 0x85, 0xf1, 0x1b, 0xd4, - 0xf0, 0x62, 0x96, 0x26, 0x52, 0xaf, 0xb7, 0xeb, 0x9d, 0xe6, 0xa3, 0x96, 0x5d, 0xde, 0xf4, 0x9c, - 0x45, 0x49, 0xff, 0xe1, 0x4d, 0x66, 0xd6, 0xbe, 0x7c, 0x37, 0x3b, 0x61, 0x24, 0x87, 0xa9, 0x6f, - 0x53, 0x16, 0x3b, 0x6b, 0x86, 0xba, 0x22, 0x18, 0x39, 0xf2, 0x7a, 0x02, 0xaa, 0x40, 0x90, 0x52, - 0x0d, 0x5f, 0xa2, 0x86, 0x80, 0x24, 0x00, 0xae, 0x6f, 0xb6, 0xb5, 0x4e, 0xab, 0x7f, 0xf6, 0x33, - 0x33, 0xbb, 0x7f, 0xa1, 0xd2, 0xa3, 0xb4, 0x17, 0x04, 0x1c, 0x84, 0x20, 0xa5, 0x00, 0x3e, 0x45, - 0x3b, 0x1c, 0x28, 0x44, 0x1f, 0x80, 0xeb, 0x5b, 0xb9, 0x3d, 0x52, 0xe1, 0xbc, 0x01, 0x32, 0x8a, - 0x81, 0xa5, 0x72, 0x30, 0x84, 0x28, 0x1c, 0x4a, 0xbd, 0xd1, 0xd6, 0x3a, 0x9b, 0xab, 0x0d, 0x58, - 0xcf, 0x5b, 0x64, 0xaf, 0x0c, 0xbc, 0x2c, 0x30, 0xbe, 0x44, 0xfb, 0x0b, 0x46, 0xfe, 0x15, 0xd2, - 0x8b, 0x27, 0xfa, 0x76, 0x21, 0xf2, 0x60, 0x9e, 0x99, 0xfa, 0xba, 0x48, 0x45, 0xb1, 0xc8, 0xff, - 0x65, 0xcc, 0xad, 0x42, 0xbf, 0x34, 0x74, 0xf2, 0x22, 0x4d, 0xc2, 0xc8, 0x1f, 0x83, 0xcb, 0x46, - 0x90, 0x5c, 0x79, 0x74, 0x04, 0xf2, 0xc2, 0x93, 0xde, 0x4a, 0x9f, 0xb5, 0x7f, 0xda, 0x67, 0x17, - 0xb5, 0x02, 0x48, 0x58, 0x3c, 0x90, 0xdc, 0xa3, 0x20, 0xf4, 0x8d, 0x42, 0x5d, 0xb7, 0x57, 0x9f, - 0xa6, 0x7d, 0x91, 0x33, 0xdc, 0x9c, 0xd0, 0x3f, 0x99, 0x67, 0xe6, 0x81, 0xf2, 0xb4, 0x5a, 0x67, - 0x91, 0x66, 0x50, 0x91, 0x04, 0x3e, 0xae, 0xa6, 0x57, 0x2f, 0x1a, 0x7e, 0xd7, 0x28, 0x36, 0xd7, - 0x47, 0x61, 0xb9, 0xc8, 0xba, 0xc3, 0x7c, 0x8f, 0x8e, 0x12, 0xf6, 0x71, 0x0c, 0x41, 0x08, 0x31, - 0x24, 0x12, 0xeb, 0x68, 0x5b, 0xa4, 0x94, 0x82, 0x10, 0xc5, 0x33, 0xdf, 0x21, 0x0b, 0x88, 0x0f, - 0xd1, 0x16, 0x70, 0xce, 0xb8, 0x7a, 0xc2, 0x44, 0x01, 0xeb, 0x2d, 0x42, 0xcb, 0xdb, 0xe7, 0x9c, - 0xe2, 0xbe, 0x6a, 0x45, 0x88, 0x02, 0xf8, 0x09, 0x42, 0xbe, 0x27, 0x60, 0x50, 0x38, 0x28, 0x37, - 0xe0, 0x68, 0x9e, 0x99, 0xfb, 0xca, 0xe7, 0x32, 0x67, 0x91, 0xdd, 0x1c, 0x14, 0x82, 0xfd, 0x57, - 0x37, 0x53, 0x43, 0xbb, 0x9d, 0x1a, 0xda, 0x8f, 0xa9, 0xa1, 0x7d, 0x9e, 0x19, 0xb5, 0xdb, 0x99, - 0x51, 0xfb, 0x36, 0x33, 0x6a, 0xef, 0xce, 0xfe, 0x38, 0x85, 0x4f, 0x4e, 0xe4, 0xd3, 0xee, 0xf2, - 0x9f, 0x90, 0x0f, 0xc5, 0x6f, 0x14, 0x8b, 0xfd, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x85, - 0xa3, 0xa5, 0x23, 0x30, 0x04, 0x00, 0x00, + // 590 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0x4f, 0x6f, 0xd3, 0x30, + 0x14, 0x6f, 0xd6, 0xae, 0xdb, 0xdc, 0x0e, 0x31, 0xef, 0x5f, 0x18, 0xa8, 0xa9, 0x7c, 0xea, 0x65, + 0x2d, 0x03, 0x24, 0x24, 0x4e, 0xac, 0x9b, 0x10, 0x13, 0x42, 0x9a, 0xac, 0x0a, 0x21, 0x2e, 0x55, + 0xe2, 0xbc, 0xa5, 0x51, 0x1b, 0xbb, 0xb2, 0xdd, 0xc1, 0xbe, 0x05, 0x9f, 0x83, 0x4f, 0xb2, 0xe3, + 0x0e, 0x1c, 0x38, 0x05, 0xb4, 0x7d, 0x83, 0x1e, 0xe1, 0x82, 0x62, 0x67, 0x69, 0x2b, 0x4d, 0x88, + 0x03, 0x9c, 0xe2, 0xdf, 0x7b, 0xbf, 0xf7, 0xcb, 0xfb, 0x67, 0xa3, 0x87, 0x71, 0xc0, 0x3a, 0x5a, + 0xfa, 0x5c, 0x9d, 0x81, 0x2c, 0x0e, 0xed, 0xb1, 0x14, 0x5a, 0xe0, 0x7a, 0x1c, 0xb0, 0xf6, 0xad, + 0x6d, 0x6f, 0x2b, 0x12, 0x91, 0x30, 0x8e, 0x4e, 0x76, 0xb2, 0x9c, 0xbd, 0x4d, 0x26, 0x54, 0x22, + 0x54, 0xc7, 0x7e, 0xac, 0x91, 0x7c, 0x2d, 0xa3, 0xda, 0x5b, 0x15, 0xf5, 0xf2, 0x50, 0xfc, 0x1c, + 0xd5, 0x94, 0x98, 0x48, 0x06, 0xfd, 0xb1, 0x90, 0xda, 0x75, 0x9a, 0x4e, 0x6b, 0xad, 0xbb, 0x33, + 0x4d, 0x3d, 0x7c, 0xe1, 0x27, 0xa3, 0x17, 0x64, 0xce, 0x49, 0x28, 0xb2, 0xe8, 0x54, 0x48, 0x8d, + 0x5f, 0xa2, 0x7b, 0xb9, 0x8f, 0x0d, 0x7c, 0xce, 0x61, 0xe4, 0x2e, 0x99, 0xd8, 0x07, 0xd3, 0xd4, + 0xdb, 0x5e, 0x88, 0xcd, 0xfd, 0x84, 0xae, 0x5b, 0xc3, 0x91, 0xc5, 0xf8, 0x1d, 0xaa, 0xfa, 0x89, + 0x98, 0x70, 0xed, 0x96, 0x9b, 0xe5, 0x56, 0xed, 0x49, 0xbd, 0x9d, 0x67, 0x7a, 0x24, 0x62, 0xde, + 0x7d, 0x7c, 0x99, 0x7a, 0xa5, 0x2f, 0xdf, 0xbd, 0x56, 0x14, 0xeb, 0xc1, 0x24, 0x68, 0x33, 0x91, + 0x74, 0x16, 0x0a, 0xda, 0x57, 0xe1, 0xb0, 0xa3, 0x2f, 0xc6, 0x60, 0x03, 0x14, 0xcd, 0xd5, 0xf0, + 0x09, 0xaa, 0x2a, 0xe0, 0x21, 0x48, 0xb7, 0xd2, 0x74, 0x5a, 0xf5, 0xee, 0xc1, 0xcf, 0xd4, 0xdb, + 0xff, 0x0b, 0x95, 0x43, 0xc6, 0x0e, 0xc3, 0x50, 0x82, 0x52, 0x34, 0x17, 0xc0, 0x7b, 0x68, 0x55, + 0x02, 0x83, 0xf8, 0x1c, 0xa4, 0xbb, 0x9c, 0x95, 0x47, 0x0b, 0x9c, 0x35, 0x40, 0xc7, 0x09, 0x88, + 0x89, 0xee, 0x0f, 0x20, 0x8e, 0x06, 0xda, 0xad, 0x36, 0x9d, 0x56, 0x65, 0xbe, 0x01, 0x8b, 0x7e, + 0x42, 0xd7, 0x73, 0xc3, 0x6b, 0x83, 0xf1, 0x09, 0xda, 0xb8, 0x65, 0x64, 0x5f, 0xa5, 0xfd, 0x64, + 0xec, 0xae, 0x18, 0x91, 0x47, 0xd3, 0xd4, 0x73, 0x17, 0x45, 0x0a, 0x0a, 0xa1, 0xf7, 0x73, 0x5b, + 0xaf, 0x30, 0xfd, 0x72, 0xd0, 0xee, 0xab, 0x09, 0x8f, 0xe2, 0x60, 0x04, 0x3d, 0x31, 0x04, 0x7e, + 0xea, 0xb3, 0x21, 0xe8, 0x63, 0x5f, 0xfb, 0x73, 0x7d, 0x76, 0xfe, 0x69, 0x9f, 0x7b, 0xa8, 0x1e, + 0x02, 0x17, 0x49, 0x5f, 0x4b, 0x9f, 0x81, 0x72, 0x97, 0x8c, 0xba, 0xdb, 0x9e, 0x5f, 0xcd, 0xf6, + 0x71, 0xc6, 0xe8, 0x65, 0x84, 0xee, 0xee, 0x34, 0xf5, 0x36, 0x6d, 0x4d, 0xf3, 0x71, 0x84, 0xd6, + 0xc2, 0x82, 0xa4, 0xf0, 0x4e, 0x31, 0xbd, 0xb2, 0x69, 0xf8, 0x5d, 0xa3, 0xa8, 0x2c, 0x8e, 0x82, + 0xf4, 0x10, 0xb9, 0xa3, 0xf8, 0x43, 0x36, 0xe4, 0xe2, 0xe3, 0x08, 0xc2, 0x08, 0x12, 0xe0, 0x1a, + 0xbb, 0x68, 0x45, 0x4d, 0x18, 0x03, 0xa5, 0xcc, 0x9a, 0xaf, 0xd2, 0x5b, 0x88, 0xb7, 0xd0, 0x32, + 0x48, 0x29, 0xa4, 0x5d, 0x61, 0x6a, 0x01, 0x79, 0x8f, 0xd0, 0x2c, 0xfb, 0x8c, 0x63, 0xf2, 0xb5, + 0x57, 0x84, 0x5a, 0x80, 0x9f, 0x21, 0x14, 0xf8, 0x0a, 0xfa, 0xa6, 0x82, 0xfc, 0x06, 0x6c, 0x4f, + 0x53, 0x6f, 0xc3, 0xd6, 0x39, 0xf3, 0x11, 0xba, 0x96, 0x01, 0x23, 0x48, 0xce, 0xd1, 0xd6, 0x49, + 0x08, 0x5c, 0xc7, 0x67, 0x31, 0x84, 0xff, 0xe7, 0x1f, 0x18, 0xa3, 0xca, 0xc0, 0x57, 0x03, 0xd3, + 0xc5, 0x3a, 0x35, 0xe7, 0xee, 0x9b, 0xcb, 0xeb, 0x86, 0x73, 0x75, 0xdd, 0x70, 0x7e, 0x5c, 0x37, + 0x9c, 0xcf, 0x37, 0x8d, 0xd2, 0xd5, 0x4d, 0xa3, 0xf4, 0xed, 0xa6, 0x51, 0xfa, 0x70, 0xf0, 0xc7, + 0xe9, 0x7f, 0xea, 0xc4, 0x01, 0xdb, 0x9f, 0xbd, 0x45, 0xd9, 0x32, 0x04, 0x55, 0xf3, 0xa0, 0x3c, + 0xfd, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x9d, 0xe9, 0x1f, 0x2f, 0xa8, 0x04, 0x00, 0x00, } func (m *MsgTransfer) Marshal() (dAtA []byte, err error) { @@ -579,6 +645,50 @@ func (m *DenomTrace) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *IdentifiedDenomTrace) 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 *IdentifiedDenomTrace) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IdentifiedDenomTrace) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTransfer(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0x1a + } + if len(m.BaseDenom) > 0 { + i -= len(m.BaseDenom) + copy(dAtA[i:], m.BaseDenom) + i = encodeVarintTransfer(dAtA, i, uint64(len(m.BaseDenom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Trace) > 0 { + i -= len(m.Trace) + copy(dAtA[i:], m.Trace) + i = encodeVarintTransfer(dAtA, i, uint64(len(m.Trace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintTransfer(dAtA []byte, offset int, v uint64) int { offset -= sovTransfer(v) base := offset @@ -689,6 +799,27 @@ func (m *DenomTrace) Size() (n int) { return n } +func (m *IdentifiedDenomTrace) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Trace) + if l > 0 { + n += 1 + l + sovTransfer(uint64(l)) + } + l = len(m.BaseDenom) + if l > 0 { + n += 1 + l + sovTransfer(uint64(l)) + } + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovTransfer(uint64(l)) + } + return n +} + func sovTransfer(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1357,6 +1488,157 @@ func (m *DenomTrace) Unmarshal(dAtA []byte) error { } return nil } +func (m *IdentifiedDenomTrace) 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 ErrIntOverflowTransfer + } + 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: IdentifiedDenomTrace: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IdentifiedDenomTrace: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + 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 ErrInvalidLengthTransfer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Trace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + 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 ErrInvalidLengthTransfer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BaseDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTransfer + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTransfer(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTransfer + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTransfer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTransfer(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From dac7de39d930c274ec35854a8834f53215688ea5 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 29 Jul 2020 00:41:53 +0200 Subject: [PATCH 03/41] validation --- proto/ibc/transfer/genesis.proto | 6 +- proto/ibc/transfer/transfer.proto | 18 +- x/ibc-transfer/types/genesis.go | 16 +- x/ibc-transfer/types/genesis.pb.go | 30 +- x/ibc-transfer/types/packet.go | 27 +- x/ibc-transfer/types/trace.go | 94 ++- x/ibc-transfer/types/transfer.pb.go | 221 +++-- x/staking/types/staking.pb.go | 1210 ++++++++++++++------------- 8 files changed, 908 insertions(+), 714 deletions(-) diff --git a/proto/ibc/transfer/genesis.proto b/proto/ibc/transfer/genesis.proto index ce703119b8bd..5700f19d5ea7 100644 --- a/proto/ibc/transfer/genesis.proto +++ b/proto/ibc/transfer/genesis.proto @@ -12,5 +12,9 @@ message GenesisState{ (gogoproto.customname) = "PortID", (gogoproto.moretags) = "yaml:\"port_id\"" ]; - repeated IdentifiedDenomTrace denom_traces = 2 [(gogoproto.moretags) = "yaml:\"denom_traces\""]; + repeated IdentifiedDenomTrace denom_traces = 2 [ + (gogoproto.castrepeated) = "Traces", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"denom_traces\"" + ]; } diff --git a/proto/ibc/transfer/transfer.proto b/proto/ibc/transfer/transfer.proto index 91c4f12155e4..5478e6287152 100644 --- a/proto/ibc/transfer/transfer.proto +++ b/proto/ibc/transfer/transfer.proto @@ -22,18 +22,20 @@ message MsgTransfer { (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; + // fungible token denomination trace info for source tracking + DenomTrace trace = 4; // the sender address - bytes sender = 4 [ + bytes sender = 5 [ (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress" ]; // the recipient address on the destination chain - string receiver = 5; + string receiver = 6; // Timeout height relative to the current block height. // The timeout is disabled when set to 0. - uint64 timeout_height = 6 [(gogoproto.moretags) = "yaml:\"timeout_height\""]; + uint64 timeout_height = 7 [(gogoproto.moretags) = "yaml:\"timeout_height\""]; // Timeout timestamp (in nanoseconds) relative to the current block timestamp. // The timeout is disabled when set to 0. - uint64 timeout_timestamp = 7 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""]; + uint64 timeout_timestamp = 8 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""]; } // FungibleTokenPacketData defines a struct for the packet payload @@ -44,8 +46,8 @@ message FungibleTokenPacketData { (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; - // coins denomination trace for tracking the source - repeated DenomTrace denom_traces = 2 [(gogoproto.moretags) = "yaml:\"denom_traces\""]; + // fungible token denomination trace info for source tracking + DenomTrace trace = 2 [(gogoproto.nullable) = false]; // the sender address string sender = 3; // the recipient address on the destination chain @@ -77,5 +79,5 @@ message IdentifiedDenomTrace { // base denomination of the relayed fungible token string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) - bytes hash = 3; -} \ No newline at end of file + string hash = 3; +} diff --git a/x/ibc-transfer/types/genesis.go b/x/ibc-transfer/types/genesis.go index e5ac802cb86d..e6a0c9ab55a4 100644 --- a/x/ibc-transfer/types/genesis.go +++ b/x/ibc-transfer/types/genesis.go @@ -4,15 +4,27 @@ import ( host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) +// NewGenesisState creates a new ibc-transfer GenesisState instance. +func NewGenesisState(portID string, denomTraces Traces) GenesisState { + return GenesisState{ + PortID: portID, + DenomTraces: denomTraces, + } +} + // DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. func DefaultGenesisState() GenesisState { return GenesisState{ - PortID: PortID, + PortID: PortID, + DenomTraces: Traces{}, } } // Validate performs basic genesis state validation returning an error upon any // failure. func (gs GenesisState) Validate() error { - return host.PortIdentifierValidator(gs.PortID) + if err := host.PortIdentifierValidator(gs.PortID); err != nil { + return err + } + return gs.DenomTraces.Validate() } diff --git a/x/ibc-transfer/types/genesis.pb.go b/x/ibc-transfer/types/genesis.pb.go index 8b3e76fcaec3..8ea3002cf0e0 100644 --- a/x/ibc-transfer/types/genesis.pb.go +++ b/x/ibc-transfer/types/genesis.pb.go @@ -25,8 +25,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the ibc-transfer genesis state type GenesisState struct { - PortID string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` - DenomTraces []*IdentifiedDenomTrace `protobuf:"bytes,2,rep,name=denom_traces,json=denomTraces,proto3" json:"denom_traces,omitempty" yaml:"denom_traces"` + PortID string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + DenomTraces Traces `protobuf:"bytes,2,rep,name=denom_traces,json=denomTraces,proto3,castrepeated=Traces" json:"denom_traces" yaml:"denom_traces"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -69,7 +69,7 @@ func (m *GenesisState) GetPortID() string { return "" } -func (m *GenesisState) GetDenomTraces() []*IdentifiedDenomTrace { +func (m *GenesisState) GetDenomTraces() Traces { if m != nil { return m.DenomTraces } @@ -83,25 +83,25 @@ func init() { func init() { proto.RegisterFile("ibc/transfer/genesis.proto", fileDescriptor_c13b8463155e05c2) } var fileDescriptor_c13b8463155e05c2 = []byte{ - // 274 bytes of a gzipped FileDescriptorProto + // 286 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xca, 0x4c, 0x4a, 0xd6, 0x2f, 0x29, 0x4a, 0xcc, 0x2b, 0x4e, 0x4b, 0x2d, 0xd2, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xc9, 0x4c, 0x4a, 0xd6, 0x83, 0xc9, 0x49, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf4, 0x41, 0x2c, 0x88, 0x1a, 0x29, 0x69, 0x14, 0xfd, 0x30, - 0x06, 0x44, 0x52, 0x69, 0x29, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xc8, 0xe0, 0x92, 0xc4, 0x92, 0x54, + 0x06, 0x44, 0x52, 0x69, 0x33, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xc8, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, 0x53, 0x2e, 0xf6, 0x82, 0xfc, 0xa2, 0x92, 0xf8, 0xcc, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0x99, 0x47, 0xf7, 0xe4, 0xd9, 0x02, 0xf2, 0x8b, 0x4a, 0x3c, 0x5d, 0x3e, 0xdd, 0x93, 0xe7, 0xab, 0x4c, 0xcc, 0xcd, 0xb1, 0x52, 0x82, 0x2a, 0x51, 0x0a, 0x62, 0x03, 0xb1, 0x3c, 0x53, - 0x84, 0xe2, 0xb8, 0x78, 0x52, 0x52, 0xf3, 0xf2, 0x73, 0xe3, 0x4b, 0x8a, 0x12, 0x93, 0x53, 0x8b, + 0x84, 0x72, 0xb8, 0x78, 0x52, 0x52, 0xf3, 0xf2, 0x73, 0xe3, 0x4b, 0x8a, 0x12, 0x93, 0x53, 0x8b, 0x25, 0x98, 0x14, 0x98, 0x35, 0xb8, 0x8d, 0x94, 0xf4, 0x90, 0xdd, 0xa7, 0xe7, 0x99, 0x92, 0x9a, - 0x57, 0x92, 0x99, 0x96, 0x99, 0x9a, 0xe2, 0x02, 0x52, 0x1b, 0x02, 0x52, 0xea, 0x24, 0xfe, 0xe9, - 0x9e, 0xbc, 0x30, 0xc4, 0x54, 0x64, 0x13, 0x94, 0x82, 0xb8, 0x53, 0xe0, 0x8a, 0x8a, 0x9d, 0xbc, - 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, - 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x30, 0x3d, 0xb3, 0x24, 0xa3, - 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x3f, 0x39, 0xbf, 0x38, 0x37, 0xbf, 0x18, 0x4a, 0xe9, 0x16, - 0xa7, 0x64, 0xeb, 0x57, 0xe8, 0x67, 0x26, 0x25, 0xeb, 0x22, 0x7c, 0x5f, 0x59, 0x90, 0x5a, 0x9c, - 0xc4, 0x06, 0xf6, 0xbb, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x03, 0xe9, 0xd6, 0x5a, 0x01, - 0x00, 0x00, + 0x57, 0x92, 0x99, 0x96, 0x99, 0x9a, 0xe2, 0x02, 0x52, 0x1b, 0x02, 0x52, 0xea, 0xa4, 0x7a, 0xe2, + 0x9e, 0x3c, 0xc3, 0xa7, 0x7b, 0xf2, 0xc2, 0x10, 0x93, 0x91, 0x4d, 0x51, 0x5a, 0x75, 0x5f, 0x9e, + 0x0d, 0xac, 0xaa, 0x38, 0x88, 0x3b, 0x05, 0xae, 0xa5, 0xd8, 0xc9, 0xfb, 0xc4, 0x23, 0x39, 0xc6, + 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, + 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x0c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, + 0x73, 0xf5, 0x93, 0xf3, 0x8b, 0x73, 0xf3, 0x8b, 0xa1, 0x94, 0x6e, 0x71, 0x4a, 0xb6, 0x7e, 0x85, + 0x7e, 0x66, 0x52, 0xb2, 0x2e, 0x22, 0x2c, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0x21, 0x61, + 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x82, 0xc6, 0x21, 0x88, 0x68, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -274,7 +274,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DenomTraces = append(m.DenomTraces, &IdentifiedDenomTrace{}) + m.DenomTraces = append(m.DenomTraces, IdentifiedDenomTrace{}) if err := m.DenomTraces[len(m.DenomTraces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/x/ibc-transfer/types/packet.go b/x/ibc-transfer/types/packet.go index 9386a5bf54f9..c5be13059595 100644 --- a/x/ibc-transfer/types/packet.go +++ b/x/ibc-transfer/types/packet.go @@ -1,6 +1,8 @@ package types import ( + "bytes" + "fmt" "strings" "time" @@ -23,9 +25,10 @@ var ( // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance func NewFungibleTokenPacketData( - amount sdk.Coins, sender, receiver string) FungibleTokenPacketData { + amount sdk.Coins, trace DenomTrace, sender, receiver string) FungibleTokenPacketData { return FungibleTokenPacketData{ Amount: amount, + Trace: trace, Sender: sender, Receiver: receiver, } @@ -39,6 +42,28 @@ func (ftpd FungibleTokenPacketData) ValidateBasic() error { if !ftpd.Amount.IsValid() { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, ftpd.Amount.String()) } + if err := ftpd.Trace.Validate(); err != nil { + return err + } + // Only validate the ibc denomination when trace info is not provided + if ftpd.Trace.Trace == "" { + denomTraceHash, err := ValidateIBCDenom(ftpd.Amount[0].Denom) + if err != nil { + return err + } + + traceHash := ftpd.Trace.Hash() + if !bytes.Equal(traceHash.Bytes(), denomTraceHash.Bytes()) { + return fmt.Errorf("token denomination trace hash mismatch, expected %s got %s", traceHash, denomTraceHash) + } + } else if ftpd.Trace.BaseDenom != ftpd.Amount[0].Denom { + return sdkerrors.Wrapf( + ErrInvalidDenomForTransfer, + "token denom must match the trace base denom (%s ≠ %s)", + ftpd.Amount, ftpd.Trace.BaseDenom, + ) + } + if strings.TrimSpace(ftpd.Sender) == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be blank") } diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 9c61de1d805b..13794b5b573f 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -1,20 +1,23 @@ package types import ( + "bytes" fmt "fmt" "strings" "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) // Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula: // // hash = sha256(trace + "/" + baseDenom) func (dt DenomTrace) Hash() tmbytes.HexBytes { - return tmhash.Sum(dt.GetDenomPrefix() + dt.BaseDenom) + return tmhash.Sum([]byte(dt.GetPrefix() + dt.BaseDenom)) } // GetPrefix returns the receiving denomination prefix composed by the trace info and a separator. @@ -56,3 +59,92 @@ func (dt *DenomTrace) RemovePrefix() error { return nil } + +func (dt DenomTrace) validateTrace() error { + // empty trace is accepted when token lives on the original chain + if dt.Trace == "" { + return nil + } + + traceSplit := strings.Split(dt.Trace, "/") + + switch { + case traceSplit[0] == dt.Trace: + return fmt.Errorf("trace %s must contain '/' separators", dt.Trace) + case len(traceSplit)%2 != 0: + return fmt.Errorf("trace info %s must come in pairs of port and channel identifiers '{portID}/{channelID}'", dt.Trace) + } + + // validate correctness of port and channel identifiers + for i := 0; i < len(traceSplit); i += 2 { + if err := host.PortIdentifierValidator(traceSplit[i]); err != nil { + return sdkerrors.Wrapf(err, "invalid port ID at position %d", i) + } + if err := host.ChannelIdentifierValidator(traceSplit[i+1]); err != nil { + return sdkerrors.Wrapf(err, "invalid channel ID at position %d", i) + } + } + return nil +} + +// Validate performs a basic validation of the DenomTrace fields. +func (dt DenomTrace) Validate() error { + if err := sdk.ValidateDenom(dt.BaseDenom); err != nil { + return err + } + + return dt.validateTrace() +} + +// Traces defines a wrapper type for a slice of IdentifiedDenomTraces. +type Traces []IdentifiedDenomTrace + +// Validate performs a basic validation of each denomination trace info. +func (t Traces) Validate() error { + seenTraces := make(map[string]bool) + for i, trace := range t { + if seenTraces[trace.Hash] { + return fmt.Errorf("duplicated denomination trace with hash %s", trace.Hash) + } + hash := tmhash.Sum([]byte(trace.Trace + "/" + trace.BaseDenom)) + if !bytes.Equal(tmbytes.HexBytes(trace.Hash), hash) { + return fmt.Errorf("trace hash mismatch, expected %s got %s", trace.Hash, hash) + } + + denomTrace := DenomTrace{ + Trace: trace.Trace, + BaseDenom: trace.BaseDenom, + } + + if err := denomTrace.Validate(); err != nil { + sdkerrors.Wrapf(err, "failed denom trace %d validation", i) + } + seenTraces[trace.Hash] = true + } + return nil +} + +// ValidateIBCDenom checks that the denomination for an IBC fungible token is valid. +func ValidateIBCDenom(denom string) (tmbytes.HexBytes, error) { + denomSplit := strings.SplitN(denom, "/", 3) + + var err error + switch { + case len(denomSplit) == 0: + err = sdkerrors.Wrap(ErrInvalidDenomForTransfer, denom) + case denomSplit[0] == denom: + err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) + case denomSplit[0] != "ibc": + err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination %s must start with 'ibc'", denom) + case len(denomSplit) == 2 && len(denomSplit[1]) != tmhash.Size: + err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid SHA256 hash %s length, expected %d, got %d", denomSplit[1], tmhash.Size, len(denomSplit[1])) + default: + err = sdkerrors.Wrap(ErrInvalidDenomForTransfer, denom) + } + + if err != nil { + return nil, err + } + + return tmbytes.HexBytes(denomSplit[1]), nil +} diff --git a/x/ibc-transfer/types/transfer.pb.go b/x/ibc-transfer/types/transfer.pb.go index a8f5a3dfe174..4a171bc9d723 100644 --- a/x/ibc-transfer/types/transfer.pb.go +++ b/x/ibc-transfer/types/transfer.pb.go @@ -34,16 +34,18 @@ type MsgTransfer struct { SourceChannel string `protobuf:"bytes,2,opt,name=source_channel,json=sourceChannel,proto3" json:"source_channel,omitempty" yaml:"source_channel"` // the tokens to be transferred Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` + // fungible token denomination trace info for source tracking + Trace *DenomTrace `protobuf:"bytes,4,opt,name=trace,proto3" json:"trace,omitempty"` // the sender address - Sender github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,4,opt,name=sender,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"sender,omitempty"` + Sender github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,5,opt,name=sender,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"sender,omitempty"` // the recipient address on the destination chain - Receiver string `protobuf:"bytes,5,opt,name=receiver,proto3" json:"receiver,omitempty"` + Receiver string `protobuf:"bytes,6,opt,name=receiver,proto3" json:"receiver,omitempty"` // Timeout height relative to the current block height. // The timeout is disabled when set to 0. - TimeoutHeight uint64 `protobuf:"varint,6,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty" yaml:"timeout_height"` + TimeoutHeight uint64 `protobuf:"varint,7,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty" yaml:"timeout_height"` // Timeout timestamp (in nanoseconds) relative to the current block timestamp. // The timeout is disabled when set to 0. - TimeoutTimestamp uint64 `protobuf:"varint,7,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty" yaml:"timeout_timestamp"` + TimeoutTimestamp uint64 `protobuf:"varint,8,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty" yaml:"timeout_timestamp"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -100,6 +102,13 @@ func (m *MsgTransfer) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { return nil } +func (m *MsgTransfer) GetTrace() *DenomTrace { + if m != nil { + return m.Trace + } + return nil +} + func (m *MsgTransfer) GetSender() github_com_cosmos_cosmos_sdk_types.AccAddress { if m != nil { return m.Sender @@ -133,8 +142,8 @@ func (m *MsgTransfer) GetTimeoutTimestamp() uint64 { type FungibleTokenPacketData struct { // the tokens to be transferred Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` - // coins denomination trace for tracking the source - DenomTraces []*DenomTrace `protobuf:"bytes,2,rep,name=denom_traces,json=denomTraces,proto3" json:"denom_traces,omitempty" yaml:"denom_traces"` + // fungible token denomination trace info for source tracking + Trace *DenomTrace `protobuf:"bytes,2,opt,name=trace,proto3" json:"trace,omitempty"` // the sender address Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` // the recipient address on the destination chain @@ -181,9 +190,9 @@ func (m *FungibleTokenPacketData) GetAmount() github_com_cosmos_cosmos_sdk_types return nil } -func (m *FungibleTokenPacketData) GetDenomTraces() []*DenomTrace { +func (m *FungibleTokenPacketData) GetTrace() *DenomTrace { if m != nil { - return m.DenomTraces + return m.Trace } return nil } @@ -320,7 +329,7 @@ type IdentifiedDenomTrace struct { // base denomination of the relayed fungible token BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty" yaml:"base_denom"` // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) - Hash []byte `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` + Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` } func (m *IdentifiedDenomTrace) Reset() { *m = IdentifiedDenomTrace{} } @@ -370,11 +379,11 @@ func (m *IdentifiedDenomTrace) GetBaseDenom() string { return "" } -func (m *IdentifiedDenomTrace) GetHash() []byte { +func (m *IdentifiedDenomTrace) GetHash() string { if m != nil { return m.Hash } - return nil + return "" } func init() { @@ -388,44 +397,44 @@ func init() { func init() { proto.RegisterFile("ibc/transfer/transfer.proto", fileDescriptor_08134a70fd29e656) } var fileDescriptor_08134a70fd29e656 = []byte{ - // 590 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0x4f, 0x6f, 0xd3, 0x30, - 0x14, 0x6f, 0xd6, 0xae, 0xdb, 0xdc, 0x0e, 0x31, 0xef, 0x5f, 0x18, 0xa8, 0xa9, 0x7c, 0xea, 0x65, - 0x2d, 0x03, 0x24, 0x24, 0x4e, 0xac, 0x9b, 0x10, 0x13, 0x42, 0x9a, 0xac, 0x0a, 0x21, 0x2e, 0x55, - 0xe2, 0xbc, 0xa5, 0x51, 0x1b, 0xbb, 0xb2, 0xdd, 0xc1, 0xbe, 0x05, 0x9f, 0x83, 0x4f, 0xb2, 0xe3, - 0x0e, 0x1c, 0x38, 0x05, 0xb4, 0x7d, 0x83, 0x1e, 0xe1, 0x82, 0x62, 0x67, 0x69, 0x2b, 0x4d, 0x88, - 0x03, 0x9c, 0xe2, 0xdf, 0x7b, 0xbf, 0xf7, 0xcb, 0xfb, 0x67, 0xa3, 0x87, 0x71, 0xc0, 0x3a, 0x5a, - 0xfa, 0x5c, 0x9d, 0x81, 0x2c, 0x0e, 0xed, 0xb1, 0x14, 0x5a, 0xe0, 0x7a, 0x1c, 0xb0, 0xf6, 0xad, - 0x6d, 0x6f, 0x2b, 0x12, 0x91, 0x30, 0x8e, 0x4e, 0x76, 0xb2, 0x9c, 0xbd, 0x4d, 0x26, 0x54, 0x22, - 0x54, 0xc7, 0x7e, 0xac, 0x91, 0x7c, 0x2d, 0xa3, 0xda, 0x5b, 0x15, 0xf5, 0xf2, 0x50, 0xfc, 0x1c, - 0xd5, 0x94, 0x98, 0x48, 0x06, 0xfd, 0xb1, 0x90, 0xda, 0x75, 0x9a, 0x4e, 0x6b, 0xad, 0xbb, 0x33, - 0x4d, 0x3d, 0x7c, 0xe1, 0x27, 0xa3, 0x17, 0x64, 0xce, 0x49, 0x28, 0xb2, 0xe8, 0x54, 0x48, 0x8d, - 0x5f, 0xa2, 0x7b, 0xb9, 0x8f, 0x0d, 0x7c, 0xce, 0x61, 0xe4, 0x2e, 0x99, 0xd8, 0x07, 0xd3, 0xd4, - 0xdb, 0x5e, 0x88, 0xcd, 0xfd, 0x84, 0xae, 0x5b, 0xc3, 0x91, 0xc5, 0xf8, 0x1d, 0xaa, 0xfa, 0x89, - 0x98, 0x70, 0xed, 0x96, 0x9b, 0xe5, 0x56, 0xed, 0x49, 0xbd, 0x9d, 0x67, 0x7a, 0x24, 0x62, 0xde, - 0x7d, 0x7c, 0x99, 0x7a, 0xa5, 0x2f, 0xdf, 0xbd, 0x56, 0x14, 0xeb, 0xc1, 0x24, 0x68, 0x33, 0x91, - 0x74, 0x16, 0x0a, 0xda, 0x57, 0xe1, 0xb0, 0xa3, 0x2f, 0xc6, 0x60, 0x03, 0x14, 0xcd, 0xd5, 0xf0, - 0x09, 0xaa, 0x2a, 0xe0, 0x21, 0x48, 0xb7, 0xd2, 0x74, 0x5a, 0xf5, 0xee, 0xc1, 0xcf, 0xd4, 0xdb, - 0xff, 0x0b, 0x95, 0x43, 0xc6, 0x0e, 0xc3, 0x50, 0x82, 0x52, 0x34, 0x17, 0xc0, 0x7b, 0x68, 0x55, - 0x02, 0x83, 0xf8, 0x1c, 0xa4, 0xbb, 0x9c, 0x95, 0x47, 0x0b, 0x9c, 0x35, 0x40, 0xc7, 0x09, 0x88, - 0x89, 0xee, 0x0f, 0x20, 0x8e, 0x06, 0xda, 0xad, 0x36, 0x9d, 0x56, 0x65, 0xbe, 0x01, 0x8b, 0x7e, - 0x42, 0xd7, 0x73, 0xc3, 0x6b, 0x83, 0xf1, 0x09, 0xda, 0xb8, 0x65, 0x64, 0x5f, 0xa5, 0xfd, 0x64, - 0xec, 0xae, 0x18, 0x91, 0x47, 0xd3, 0xd4, 0x73, 0x17, 0x45, 0x0a, 0x0a, 0xa1, 0xf7, 0x73, 0x5b, - 0xaf, 0x30, 0xfd, 0x72, 0xd0, 0xee, 0xab, 0x09, 0x8f, 0xe2, 0x60, 0x04, 0x3d, 0x31, 0x04, 0x7e, - 0xea, 0xb3, 0x21, 0xe8, 0x63, 0x5f, 0xfb, 0x73, 0x7d, 0x76, 0xfe, 0x69, 0x9f, 0x7b, 0xa8, 0x1e, - 0x02, 0x17, 0x49, 0x5f, 0x4b, 0x9f, 0x81, 0x72, 0x97, 0x8c, 0xba, 0xdb, 0x9e, 0x5f, 0xcd, 0xf6, - 0x71, 0xc6, 0xe8, 0x65, 0x84, 0xee, 0xee, 0x34, 0xf5, 0x36, 0x6d, 0x4d, 0xf3, 0x71, 0x84, 0xd6, - 0xc2, 0x82, 0xa4, 0xf0, 0x4e, 0x31, 0xbd, 0xb2, 0x69, 0xf8, 0x5d, 0xa3, 0xa8, 0x2c, 0x8e, 0x82, - 0xf4, 0x10, 0xb9, 0xa3, 0xf8, 0x43, 0x36, 0xe4, 0xe2, 0xe3, 0x08, 0xc2, 0x08, 0x12, 0xe0, 0x1a, - 0xbb, 0x68, 0x45, 0x4d, 0x18, 0x03, 0xa5, 0xcc, 0x9a, 0xaf, 0xd2, 0x5b, 0x88, 0xb7, 0xd0, 0x32, - 0x48, 0x29, 0xa4, 0x5d, 0x61, 0x6a, 0x01, 0x79, 0x8f, 0xd0, 0x2c, 0xfb, 0x8c, 0x63, 0xf2, 0xb5, - 0x57, 0x84, 0x5a, 0x80, 0x9f, 0x21, 0x14, 0xf8, 0x0a, 0xfa, 0xa6, 0x82, 0xfc, 0x06, 0x6c, 0x4f, - 0x53, 0x6f, 0xc3, 0xd6, 0x39, 0xf3, 0x11, 0xba, 0x96, 0x01, 0x23, 0x48, 0xce, 0xd1, 0xd6, 0x49, - 0x08, 0x5c, 0xc7, 0x67, 0x31, 0x84, 0xff, 0xe7, 0x1f, 0x18, 0xa3, 0xca, 0xc0, 0x57, 0x03, 0xd3, - 0xc5, 0x3a, 0x35, 0xe7, 0xee, 0x9b, 0xcb, 0xeb, 0x86, 0x73, 0x75, 0xdd, 0x70, 0x7e, 0x5c, 0x37, - 0x9c, 0xcf, 0x37, 0x8d, 0xd2, 0xd5, 0x4d, 0xa3, 0xf4, 0xed, 0xa6, 0x51, 0xfa, 0x70, 0xf0, 0xc7, - 0xe9, 0x7f, 0xea, 0xc4, 0x01, 0xdb, 0x9f, 0xbd, 0x45, 0xd9, 0x32, 0x04, 0x55, 0xf3, 0xa0, 0x3c, - 0xfd, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x9d, 0xe9, 0x1f, 0x2f, 0xa8, 0x04, 0x00, 0x00, + // 579 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xcd, 0x6e, 0xd3, 0x40, + 0x18, 0x8c, 0xdb, 0x34, 0x6d, 0x37, 0x2d, 0xa2, 0x4b, 0x5b, 0x4c, 0x41, 0x76, 0xe4, 0x93, 0x2f, + 0xb5, 0x69, 0x41, 0x42, 0xe2, 0x44, 0xd3, 0x0a, 0x11, 0x21, 0xa4, 0xca, 0x8a, 0x10, 0xe2, 0x12, + 0xd9, 0xeb, 0xaf, 0xb6, 0x95, 0x78, 0x37, 0xda, 0x5d, 0x17, 0x7a, 0xe7, 0x01, 0x78, 0x0e, 0x9e, + 0xa4, 0xc7, 0x5e, 0x90, 0x38, 0x19, 0x94, 0xbc, 0x41, 0x8e, 0x9c, 0x90, 0xbd, 0xce, 0x9f, 0x54, + 0xa1, 0x5e, 0x7a, 0xf2, 0xce, 0x37, 0xf3, 0x7d, 0xde, 0x9d, 0xb1, 0x17, 0x3d, 0x4d, 0x02, 0xe2, + 0x4a, 0xee, 0x53, 0x71, 0x01, 0x7c, 0xb6, 0x70, 0x86, 0x9c, 0x49, 0x86, 0xb7, 0x92, 0x80, 0x38, + 0xd3, 0xda, 0xc1, 0x6e, 0xc4, 0x22, 0x56, 0x12, 0x6e, 0xb1, 0x52, 0x9a, 0x83, 0x47, 0x84, 0x89, + 0x94, 0x09, 0x57, 0x3d, 0x54, 0xd1, 0xfa, 0x56, 0x47, 0xcd, 0x0f, 0x22, 0xea, 0x56, 0xad, 0xf8, + 0x15, 0x6a, 0x0a, 0x96, 0x71, 0x02, 0xbd, 0x21, 0xe3, 0x52, 0xd7, 0x5a, 0x9a, 0xbd, 0xd9, 0xde, + 0x9f, 0xe4, 0x26, 0xbe, 0xf2, 0xd3, 0xc1, 0x6b, 0x6b, 0x81, 0xb4, 0x3c, 0xa4, 0xd0, 0x39, 0xe3, + 0x12, 0xbf, 0x41, 0x0f, 0x2a, 0x8e, 0xc4, 0x3e, 0xa5, 0x30, 0xd0, 0x57, 0xca, 0xde, 0x27, 0x93, + 0xdc, 0xdc, 0x5b, 0xea, 0xad, 0x78, 0xcb, 0xdb, 0x56, 0x85, 0x53, 0x85, 0xf1, 0x47, 0xd4, 0xf0, + 0x53, 0x96, 0x51, 0xa9, 0xaf, 0xb6, 0x56, 0xed, 0xe6, 0xf1, 0x96, 0x53, 0xed, 0xf4, 0x94, 0x25, + 0xb4, 0xfd, 0xfc, 0x3a, 0x37, 0x6b, 0x3f, 0x7e, 0x9b, 0x76, 0x94, 0xc8, 0x38, 0x0b, 0x1c, 0xc2, + 0x52, 0x77, 0xe9, 0x40, 0x87, 0x22, 0xec, 0xbb, 0xf2, 0x6a, 0x08, 0xaa, 0x41, 0x78, 0xd5, 0x34, + 0xec, 0xa0, 0x35, 0xc9, 0x7d, 0x02, 0x7a, 0xbd, 0xa5, 0xd9, 0xcd, 0x63, 0xdd, 0x59, 0xf4, 0xca, + 0x39, 0x03, 0xca, 0xd2, 0x6e, 0xc1, 0x7b, 0x4a, 0x86, 0x3b, 0xa8, 0x21, 0x80, 0x86, 0xc0, 0xf5, + 0xb5, 0x96, 0x66, 0x6f, 0xb5, 0x8f, 0xfe, 0xe6, 0xe6, 0xe1, 0x1d, 0xde, 0x7a, 0x42, 0xc8, 0x49, + 0x18, 0x72, 0x10, 0xc2, 0xab, 0x06, 0xe0, 0x03, 0xb4, 0xc1, 0x81, 0x40, 0x72, 0x09, 0x5c, 0x6f, + 0x14, 0x76, 0x78, 0x33, 0x5c, 0x18, 0x26, 0x93, 0x14, 0x58, 0x26, 0x7b, 0x31, 0x24, 0x51, 0x2c, + 0xf5, 0xf5, 0x96, 0x66, 0xd7, 0x17, 0x0d, 0x5b, 0xe6, 0x2d, 0x6f, 0xbb, 0x2a, 0xbc, 0x2b, 0x31, + 0xee, 0xa0, 0x9d, 0xa9, 0xa2, 0x78, 0x0a, 0xe9, 0xa7, 0x43, 0x7d, 0xa3, 0x1c, 0xf2, 0x6c, 0x92, + 0x9b, 0xfa, 0xf2, 0x90, 0x99, 0xc4, 0xf2, 0x1e, 0x56, 0xb5, 0xee, 0xac, 0xf4, 0x53, 0x43, 0x8f, + 0xdf, 0x66, 0x34, 0x4a, 0x82, 0x01, 0x74, 0x59, 0x1f, 0xe8, 0xb9, 0x4f, 0xfa, 0x20, 0xcf, 0x7c, + 0xe9, 0x2f, 0xe4, 0xa2, 0xdd, 0x4f, 0x2e, 0x2b, 0x77, 0xcb, 0x65, 0x7f, 0x96, 0xcb, 0x6a, 0x69, + 0xe5, 0x6d, 0x26, 0xd7, 0x97, 0x4d, 0xb6, 0xba, 0xc8, 0xba, 0xe5, 0x58, 0x27, 0xa4, 0x4f, 0xd9, + 0x97, 0x01, 0x84, 0x11, 0xa4, 0x40, 0x25, 0xd6, 0xd1, 0xba, 0xc8, 0x08, 0x01, 0x21, 0xca, 0x0f, + 0x7e, 0xc3, 0x9b, 0x42, 0xbc, 0x8b, 0xd6, 0x80, 0x73, 0xc6, 0xd5, 0xc7, 0xec, 0x29, 0x60, 0x7d, + 0x42, 0x68, 0xbe, 0xbd, 0x42, 0xa3, 0xce, 0xa1, 0x29, 0x8d, 0xda, 0xed, 0x4b, 0x84, 0x02, 0x5f, + 0x40, 0x2f, 0x2c, 0x84, 0xd5, 0xbf, 0xb0, 0x37, 0xc9, 0xcd, 0x1d, 0x95, 0xca, 0x9c, 0xb3, 0xbc, + 0xcd, 0x02, 0x94, 0x03, 0xad, 0x4b, 0xb4, 0xdb, 0x09, 0x81, 0xca, 0xe4, 0x22, 0x81, 0xf0, 0x7e, + 0xde, 0x81, 0x31, 0xaa, 0xc7, 0xbe, 0x88, 0x2b, 0x17, 0xcb, 0x75, 0xfb, 0xfd, 0xf5, 0xc8, 0xd0, + 0x6e, 0x46, 0x86, 0xf6, 0x67, 0x64, 0x68, 0xdf, 0xc7, 0x46, 0xed, 0x66, 0x6c, 0xd4, 0x7e, 0x8d, + 0x8d, 0xda, 0xe7, 0xa3, 0xff, 0xe6, 0xfa, 0xd5, 0x4d, 0x02, 0x72, 0x38, 0xbf, 0x95, 0x8a, 0x98, + 0x83, 0x46, 0x79, 0xb5, 0xbc, 0xf8, 0x17, 0x00, 0x00, 0xff, 0xff, 0x17, 0x3b, 0xa0, 0x4a, 0xb2, + 0x04, 0x00, 0x00, } func (m *MsgTransfer) Marshal() (dAtA []byte, err error) { @@ -451,25 +460,37 @@ func (m *MsgTransfer) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.TimeoutTimestamp != 0 { i = encodeVarintTransfer(dAtA, i, uint64(m.TimeoutTimestamp)) i-- - dAtA[i] = 0x38 + dAtA[i] = 0x40 } if m.TimeoutHeight != 0 { i = encodeVarintTransfer(dAtA, i, uint64(m.TimeoutHeight)) i-- - dAtA[i] = 0x30 + dAtA[i] = 0x38 } if len(m.Receiver) > 0 { i -= len(m.Receiver) copy(dAtA[i:], m.Receiver) i = encodeVarintTransfer(dAtA, i, uint64(len(m.Receiver))) i-- - dAtA[i] = 0x2a + dAtA[i] = 0x32 } if len(m.Sender) > 0 { i -= len(m.Sender) copy(dAtA[i:], m.Sender) i = encodeVarintTransfer(dAtA, i, uint64(len(m.Sender))) i-- + dAtA[i] = 0x2a + } + if m.Trace != nil { + { + size, err := m.Trace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTransfer(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x22 } if len(m.Amount) > 0 { @@ -537,19 +558,17 @@ func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) i-- dAtA[i] = 0x1a } - if len(m.DenomTraces) > 0 { - for iNdEx := len(m.DenomTraces) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.DenomTraces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTransfer(dAtA, i, uint64(size)) + if m.Trace != nil { + { + size, err := m.Trace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x12 + i -= size + i = encodeVarintTransfer(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x12 } if len(m.Amount) > 0 { for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { @@ -720,6 +739,10 @@ func (m *MsgTransfer) Size() (n int) { n += 1 + l + sovTransfer(uint64(l)) } } + if m.Trace != nil { + l = m.Trace.Size() + n += 1 + l + sovTransfer(uint64(l)) + } l = len(m.Sender) if l > 0 { n += 1 + l + sovTransfer(uint64(l)) @@ -749,11 +772,9 @@ func (m *FungibleTokenPacketData) Size() (n int) { n += 1 + l + sovTransfer(uint64(l)) } } - if len(m.DenomTraces) > 0 { - for _, e := range m.DenomTraces { - l = e.Size() - n += 1 + l + sovTransfer(uint64(l)) - } + if m.Trace != nil { + l = m.Trace.Size() + n += 1 + l + sovTransfer(uint64(l)) } l = len(m.Sender) if l > 0 { @@ -954,6 +975,42 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTransfer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Trace == nil { + m.Trace = &DenomTrace{} + } + if err := m.Trace.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) } @@ -987,7 +1044,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { m.Sender = []byte{} } iNdEx = postIndex - case 5: + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) } @@ -1019,7 +1076,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { } m.Receiver = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 6: + case 7: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TimeoutHeight", wireType) } @@ -1038,7 +1095,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { break } } - case 7: + case 8: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType) } @@ -1146,7 +1203,7 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DenomTraces", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1173,8 +1230,10 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DenomTraces = append(m.DenomTraces, &DenomTrace{}) - if err := m.DenomTraces[len(m.DenomTraces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.Trace == nil { + m.Trace = &DenomTrace{} + } + if err := m.Trace.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1585,7 +1644,7 @@ func (m *IdentifiedDenomTrace) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) } - var byteLen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTransfer @@ -1595,25 +1654,23 @@ func (m *IdentifiedDenomTrace) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTransfer } - postIndex := iNdEx + byteLen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTransfer } if postIndex > l { return io.ErrUnexpectedEOF } - m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) - if m.Hash == nil { - m.Hash = []byte{} - } + m.Hash = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/x/staking/types/staking.pb.go b/x/staking/types/staking.pb.go index 44b497096f73..8169b56ec933 100644 --- a/x/staking/types/staking.pb.go +++ b/x/staking/types/staking.pb.go @@ -1569,612 +1569,614 @@ func (this *Pool) Description() (desc *github_com_gogo_protobuf_protoc_gen_gogo_ func StakingDescription() (desc *github_com_gogo_protobuf_protoc_gen_gogo_descriptor.FileDescriptorSet) { d := &github_com_gogo_protobuf_protoc_gen_gogo_descriptor.FileDescriptorSet{} var gzipped = []byte{ - // 9675 bytes of a gzipped FileDescriptorSet + // 9698 bytes of a gzipped FileDescriptorSet 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x7b, 0x70, 0x24, 0xc7, 0x79, 0x1f, 0xf6, 0x81, 0xc5, 0xee, 0xb7, 0x8b, 0xc5, 0xa2, 0x81, 0xbb, 0xc3, 0x2d, 0xc9, 0xdb, - 0xe3, 0x1c, 0x1f, 0x38, 0x3e, 0x70, 0xd4, 0x89, 0x0f, 0x71, 0x8f, 0x22, 0x85, 0x05, 0x70, 0x77, - 0x20, 0x81, 0x3b, 0x70, 0x00, 0x1c, 0x29, 0xca, 0xf6, 0x78, 0x30, 0xdb, 0x58, 0x0c, 0xb1, 0x3b, - 0xb3, 0x9c, 0x99, 0xbd, 0x03, 0x58, 0x4a, 0x15, 0x53, 0x96, 0xf5, 0x70, 0x64, 0x4b, 0x51, 0x6c, - 0x87, 0x96, 0x25, 0x99, 0x52, 0x2a, 0x91, 0xa3, 0x24, 0x7e, 0x24, 0x8a, 0x1e, 0x76, 0xfe, 0x50, - 0x55, 0x1e, 0x56, 0xaa, 0x5c, 0x29, 0x29, 0x71, 0x52, 0xae, 0x54, 0x0a, 0xb6, 0x48, 0x55, 0x59, - 0x51, 0x98, 0x44, 0xb9, 0xd0, 0x2e, 0x97, 0xf4, 0x47, 0x52, 0xfd, 0x9a, 0xd7, 0xce, 0xee, 0x0c, - 0x8e, 0x47, 0x8a, 0x2e, 0xe9, 0x2f, 0x6c, 0xf7, 0x7c, 0xdf, 0xaf, 0xbb, 0xbf, 0xfe, 0xfa, 0xfb, - 0xbe, 0xfe, 0xba, 0x67, 0x00, 0xbf, 0x79, 0x0e, 0x4e, 0xb6, 0x4c, 0xb3, 0xd5, 0xc6, 0x67, 0xba, - 0x96, 0xe9, 0x98, 0x5b, 0xbd, 0xed, 0x33, 0x4d, 0x6c, 0x6b, 0x96, 0xde, 0x75, 0x4c, 0x6b, 0x8e, - 0xd6, 0xa1, 0x09, 0x46, 0x31, 0x27, 0x28, 0xa4, 0x55, 0x98, 0x3c, 0xaf, 0xb7, 0xf1, 0xa2, 0x4b, - 0xb8, 0x8e, 0x1d, 0xf4, 0x1e, 0xc8, 0x6e, 0xeb, 0x6d, 0x3c, 0x93, 0x3a, 0x99, 0x99, 0x2d, 0x9e, - 0xbd, 0x63, 0x2e, 0xc4, 0x34, 0x17, 0xe4, 0x58, 0x23, 0xd5, 0x32, 0xe5, 0x90, 0xbe, 0x9b, 0x85, - 0xa9, 0x88, 0xa7, 0x08, 0x41, 0xd6, 0x50, 0x3b, 0x04, 0x31, 0x35, 0x5b, 0x90, 0xe9, 0x6f, 0x34, - 0x03, 0x63, 0x5d, 0x55, 0xdb, 0x55, 0x5b, 0x78, 0x26, 0x4d, 0xab, 0x45, 0x11, 0x9d, 0x00, 0x68, - 0xe2, 0x2e, 0x36, 0x9a, 0xd8, 0xd0, 0xf6, 0x67, 0x32, 0x27, 0x33, 0xb3, 0x05, 0xd9, 0x57, 0x83, - 0xee, 0x85, 0xc9, 0x6e, 0x6f, 0xab, 0xad, 0x6b, 0x8a, 0x8f, 0x0c, 0x4e, 0x66, 0x66, 0x47, 0xe5, - 0x0a, 0x7b, 0xb0, 0xe8, 0x11, 0xdf, 0x0d, 0x13, 0xd7, 0xb0, 0xba, 0xeb, 0x27, 0x2d, 0x52, 0xd2, - 0x32, 0xa9, 0xf6, 0x11, 0x2e, 0x40, 0xa9, 0x83, 0x6d, 0x5b, 0x6d, 0x61, 0xc5, 0xd9, 0xef, 0xe2, - 0x99, 0x2c, 0x1d, 0xfd, 0xc9, 0xbe, 0xd1, 0x87, 0x47, 0x5e, 0xe4, 0x5c, 0x1b, 0xfb, 0x5d, 0x8c, - 0xe6, 0xa1, 0x80, 0x8d, 0x5e, 0x87, 0x21, 0x8c, 0x0e, 0x90, 0xdf, 0x92, 0xd1, 0xeb, 0x84, 0x51, - 0xf2, 0x84, 0x8d, 0x43, 0x8c, 0xd9, 0xd8, 0xba, 0xaa, 0x6b, 0x78, 0x26, 0x47, 0x01, 0xee, 0xee, - 0x03, 0x58, 0x67, 0xcf, 0xc3, 0x18, 0x82, 0x0f, 0x2d, 0x40, 0x01, 0xef, 0x39, 0xd8, 0xb0, 0x75, - 0xd3, 0x98, 0x19, 0xa3, 0x20, 0x77, 0x46, 0xcc, 0x22, 0x6e, 0x37, 0xc3, 0x10, 0x1e, 0x1f, 0x7a, - 0x18, 0xc6, 0xcc, 0xae, 0xa3, 0x9b, 0x86, 0x3d, 0x93, 0x3f, 0x99, 0x9a, 0x2d, 0x9e, 0xbd, 0x35, - 0x52, 0x11, 0x2e, 0x33, 0x1a, 0x59, 0x10, 0xa3, 0x65, 0xa8, 0xd8, 0x66, 0xcf, 0xd2, 0xb0, 0xa2, - 0x99, 0x4d, 0xac, 0xe8, 0xc6, 0xb6, 0x39, 0x53, 0xa0, 0x00, 0xb5, 0xfe, 0x81, 0x50, 0xc2, 0x05, - 0xb3, 0x89, 0x97, 0x8d, 0x6d, 0x53, 0x2e, 0xdb, 0x81, 0x32, 0x3a, 0x0a, 0x39, 0x7b, 0xdf, 0x70, - 0xd4, 0xbd, 0x99, 0x12, 0xd5, 0x10, 0x5e, 0x92, 0xbe, 0x9e, 0x83, 0x89, 0x24, 0x2a, 0x76, 0x0e, - 0x46, 0xb7, 0xc9, 0x28, 0x67, 0xd2, 0x87, 0x91, 0x01, 0xe3, 0x09, 0x0a, 0x31, 0x77, 0x83, 0x42, - 0x9c, 0x87, 0xa2, 0x81, 0x6d, 0x07, 0x37, 0x99, 0x46, 0x64, 0x12, 0xea, 0x14, 0x30, 0xa6, 0x7e, - 0x95, 0xca, 0xde, 0x90, 0x4a, 0x3d, 0x0b, 0x13, 0x6e, 0x97, 0x14, 0x4b, 0x35, 0x5a, 0x42, 0x37, - 0xcf, 0xc4, 0xf5, 0x64, 0x6e, 0x49, 0xf0, 0xc9, 0x84, 0x4d, 0x2e, 0xe3, 0x40, 0x19, 0x2d, 0x02, - 0x98, 0x06, 0x36, 0xb7, 0x95, 0x26, 0xd6, 0xda, 0x33, 0xf9, 0x01, 0x52, 0xba, 0x4c, 0x48, 0xfa, - 0xa4, 0x64, 0xb2, 0x5a, 0xad, 0x8d, 0x1e, 0xf5, 0x54, 0x6d, 0x6c, 0x80, 0xa6, 0xac, 0xb2, 0x45, - 0xd6, 0xa7, 0x6d, 0x9b, 0x50, 0xb6, 0x30, 0xd1, 0x7b, 0xdc, 0xe4, 0x23, 0x2b, 0xd0, 0x4e, 0xcc, - 0xc5, 0x8e, 0x4c, 0xe6, 0x6c, 0x6c, 0x60, 0xe3, 0x96, 0xbf, 0x88, 0x4e, 0x81, 0x5b, 0xa1, 0x50, - 0xb5, 0x02, 0x6a, 0x85, 0x4a, 0xa2, 0xf2, 0x92, 0xda, 0xc1, 0xd5, 0x17, 0xa1, 0x1c, 0x14, 0x0f, - 0x9a, 0x86, 0x51, 0xdb, 0x51, 0x2d, 0x87, 0x6a, 0xe1, 0xa8, 0xcc, 0x0a, 0xa8, 0x02, 0x19, 0x6c, - 0x34, 0xa9, 0x95, 0x1b, 0x95, 0xc9, 0x4f, 0xf4, 0x3e, 0x6f, 0xc0, 0x19, 0x3a, 0xe0, 0xbb, 0xfa, - 0x67, 0x34, 0x80, 0x1c, 0x1e, 0x77, 0xf5, 0x11, 0x18, 0x0f, 0x0c, 0x20, 0x69, 0xd3, 0xd2, 0x07, - 0xe1, 0x48, 0x24, 0x34, 0x7a, 0x16, 0xa6, 0x7b, 0x86, 0x6e, 0x38, 0xd8, 0xea, 0x5a, 0x98, 0x68, - 0x2c, 0x6b, 0x6a, 0xe6, 0x2f, 0xc6, 0x06, 0xe8, 0xdc, 0xa6, 0x9f, 0x9a, 0xa1, 0xc8, 0x53, 0xbd, - 0xfe, 0xca, 0x7b, 0x0a, 0xf9, 0xef, 0x8d, 0x55, 0x5e, 0x7a, 0xe9, 0xa5, 0x97, 0xd2, 0xd2, 0xcb, - 0x39, 0x98, 0x8e, 0x5a, 0x33, 0x91, 0xcb, 0xf7, 0x28, 0xe4, 0x8c, 0x5e, 0x67, 0x0b, 0x5b, 0x54, - 0x48, 0xa3, 0x32, 0x2f, 0xa1, 0x79, 0x18, 0x6d, 0xab, 0x5b, 0xb8, 0x3d, 0x93, 0x3d, 0x99, 0x9a, - 0x2d, 0x9f, 0xbd, 0x37, 0xd1, 0xaa, 0x9c, 0x5b, 0x21, 0x2c, 0x32, 0xe3, 0x44, 0x8f, 0x43, 0x96, - 0x9b, 0x68, 0x82, 0x70, 0x4f, 0x32, 0x04, 0xb2, 0x96, 0x64, 0xca, 0x87, 0x6e, 0x81, 0x02, 0xf9, - 0xcb, 0x74, 0x23, 0x47, 0xfb, 0x9c, 0x27, 0x15, 0x44, 0x2f, 0x50, 0x15, 0xf2, 0x74, 0x99, 0x34, - 0xb1, 0x70, 0x6d, 0x6e, 0x99, 0x28, 0x56, 0x13, 0x6f, 0xab, 0xbd, 0xb6, 0xa3, 0x5c, 0x55, 0xdb, - 0x3d, 0x4c, 0x15, 0xbe, 0x20, 0x97, 0x78, 0xe5, 0x15, 0x52, 0x87, 0x6a, 0x50, 0x64, 0xab, 0x4a, - 0x37, 0x9a, 0x78, 0x8f, 0x5a, 0xcf, 0x51, 0x99, 0x2d, 0xb4, 0x65, 0x52, 0x43, 0x9a, 0x7f, 0xde, - 0x36, 0x0d, 0xa1, 0x9a, 0xb4, 0x09, 0x52, 0x41, 0x9b, 0x7f, 0x24, 0x6c, 0xb8, 0x6f, 0x8b, 0x1e, - 0x5e, 0x58, 0xa7, 0xa4, 0xaf, 0xa4, 0x21, 0x4b, 0xed, 0xc5, 0x04, 0x14, 0x37, 0xde, 0xbf, 0xb6, - 0xa4, 0x2c, 0x5e, 0xde, 0x6c, 0xac, 0x2c, 0x55, 0x52, 0xa8, 0x0c, 0x40, 0x2b, 0xce, 0xaf, 0x5c, - 0x9e, 0xdf, 0xa8, 0xa4, 0xdd, 0xf2, 0xf2, 0xa5, 0x8d, 0x87, 0x1f, 0xac, 0x64, 0x5c, 0x86, 0x4d, - 0x56, 0x91, 0xf5, 0x13, 0xbc, 0xfb, 0x6c, 0x65, 0x14, 0x55, 0xa0, 0xc4, 0x00, 0x96, 0x9f, 0x5d, - 0x5a, 0x7c, 0xf8, 0xc1, 0x4a, 0x2e, 0x58, 0xf3, 0xee, 0xb3, 0x95, 0x31, 0x34, 0x0e, 0x05, 0x5a, - 0xd3, 0xb8, 0x7c, 0x79, 0xa5, 0x92, 0x77, 0x31, 0xd7, 0x37, 0xe4, 0xe5, 0x4b, 0x17, 0x2a, 0x05, - 0x17, 0xf3, 0x82, 0x7c, 0x79, 0x73, 0xad, 0x02, 0x2e, 0xc2, 0xea, 0xd2, 0xfa, 0xfa, 0xfc, 0x85, - 0xa5, 0x4a, 0xd1, 0xa5, 0x68, 0xbc, 0x7f, 0x63, 0x69, 0xbd, 0x52, 0x0a, 0x74, 0xeb, 0xdd, 0x67, - 0x2b, 0xe3, 0x6e, 0x13, 0x4b, 0x97, 0x36, 0x57, 0x2b, 0x65, 0x34, 0x09, 0xe3, 0xac, 0x09, 0xd1, - 0x89, 0x89, 0x50, 0xd5, 0xc3, 0x0f, 0x56, 0x2a, 0x5e, 0x47, 0x18, 0xca, 0x64, 0xa0, 0xe2, 0xe1, - 0x07, 0x2b, 0x48, 0x5a, 0x80, 0x51, 0xaa, 0x5d, 0x08, 0x41, 0x79, 0x65, 0xbe, 0xb1, 0xb4, 0xa2, - 0x5c, 0x5e, 0xdb, 0x58, 0xbe, 0x7c, 0x69, 0x7e, 0xa5, 0x92, 0xf2, 0xea, 0xe4, 0xa5, 0xa7, 0x37, - 0x97, 0xe5, 0xa5, 0xc5, 0x4a, 0xda, 0x5f, 0xb7, 0xb6, 0x34, 0xbf, 0xb1, 0xb4, 0x58, 0xc9, 0x48, - 0x1a, 0x4c, 0x47, 0xd9, 0xc9, 0xc8, 0x95, 0xe1, 0x9b, 0xe2, 0xf4, 0x80, 0x29, 0xa6, 0x58, 0x7d, - 0x53, 0xfc, 0x5a, 0x1a, 0xa6, 0x22, 0x7c, 0x45, 0x64, 0x23, 0x4f, 0xc0, 0x28, 0x53, 0x51, 0xe6, - 0x3d, 0x4f, 0x47, 0x3a, 0x1d, 0xaa, 0xb0, 0x7d, 0x1e, 0x94, 0xf2, 0xf9, 0x23, 0x88, 0xcc, 0x80, - 0x08, 0x82, 0x40, 0xf4, 0xd9, 0xf4, 0x9f, 0xed, 0xb3, 0xe9, 0xcc, 0xed, 0x3d, 0x9c, 0xc4, 0xed, - 0xd1, 0xba, 0xc3, 0xd9, 0xf6, 0xd1, 0x08, 0xdb, 0x7e, 0x0e, 0x26, 0xfb, 0x80, 0x12, 0xdb, 0xd8, - 0x5f, 0x48, 0xc1, 0xcc, 0x20, 0xe1, 0xc4, 0x58, 0xba, 0x74, 0xc0, 0xd2, 0x9d, 0x0b, 0x4b, 0xf0, - 0xf6, 0xc1, 0x93, 0xd0, 0x37, 0xd7, 0x5f, 0x4c, 0xc1, 0xd1, 0xe8, 0x48, 0x31, 0xb2, 0x0f, 0x8f, - 0x43, 0xae, 0x83, 0x9d, 0x1d, 0x53, 0x44, 0x4b, 0x77, 0x45, 0xf8, 0x60, 0xf2, 0x38, 0x3c, 0xd9, - 0x9c, 0xcb, 0xef, 0xc4, 0x33, 0x83, 0xc2, 0x3d, 0xd6, 0x9b, 0xbe, 0x9e, 0x7e, 0x2c, 0x0d, 0x47, - 0x22, 0xc1, 0x23, 0x3b, 0x7a, 0x1b, 0x80, 0x6e, 0x74, 0x7b, 0x0e, 0x8b, 0x88, 0x98, 0x81, 0x2d, - 0xd0, 0x1a, 0x6a, 0xbc, 0x88, 0xf1, 0xec, 0x39, 0xee, 0xf3, 0x0c, 0x7d, 0x0e, 0xac, 0x8a, 0x12, - 0xbc, 0xc7, 0xeb, 0x68, 0x96, 0x76, 0xf4, 0xc4, 0x80, 0x91, 0xf6, 0x29, 0xe6, 0x03, 0x50, 0xd1, - 0xda, 0x3a, 0x36, 0x1c, 0xc5, 0x76, 0x2c, 0xac, 0x76, 0x74, 0xa3, 0x45, 0x3d, 0x48, 0xbe, 0x3e, - 0xba, 0xad, 0xb6, 0x6d, 0x2c, 0x4f, 0xb0, 0xc7, 0xeb, 0xe2, 0x29, 0xe1, 0xa0, 0x0a, 0x64, 0xf9, - 0x38, 0x72, 0x01, 0x0e, 0xf6, 0xd8, 0xe5, 0x90, 0x3e, 0x55, 0x80, 0xa2, 0x2f, 0xae, 0x46, 0xb7, - 0x43, 0xe9, 0x79, 0xf5, 0xaa, 0xaa, 0x88, 0xbd, 0x12, 0x93, 0x44, 0x91, 0xd4, 0xad, 0xf1, 0xfd, - 0xd2, 0x03, 0x30, 0x4d, 0x49, 0xcc, 0x9e, 0x83, 0x2d, 0x45, 0x6b, 0xab, 0xb6, 0x4d, 0x85, 0x96, - 0xa7, 0xa4, 0x88, 0x3c, 0xbb, 0x4c, 0x1e, 0x2d, 0x88, 0x27, 0xe8, 0x21, 0x98, 0xa2, 0x1c, 0x9d, - 0x5e, 0xdb, 0xd1, 0xbb, 0x6d, 0xac, 0x90, 0xdd, 0x9b, 0x4d, 0x3d, 0x89, 0xdb, 0xb3, 0x49, 0x42, - 0xb1, 0xca, 0x09, 0x48, 0x8f, 0x6c, 0xb4, 0x08, 0xb7, 0x51, 0xb6, 0x16, 0x36, 0xb0, 0xa5, 0x3a, - 0x58, 0xc1, 0x2f, 0xf4, 0xd4, 0xb6, 0xad, 0xa8, 0x46, 0x53, 0xd9, 0x51, 0xed, 0x9d, 0x99, 0x69, - 0x02, 0xd0, 0x48, 0xcf, 0xa4, 0xe4, 0xe3, 0x84, 0xf0, 0x02, 0xa7, 0x5b, 0xa2, 0x64, 0xf3, 0x46, - 0xf3, 0xa2, 0x6a, 0xef, 0xa0, 0x3a, 0x1c, 0xa5, 0x28, 0xb6, 0x63, 0xe9, 0x46, 0x4b, 0xd1, 0x76, - 0xb0, 0xb6, 0xab, 0xf4, 0x9c, 0xed, 0xf7, 0xcc, 0xdc, 0xe2, 0x6f, 0x9f, 0xf6, 0x70, 0x9d, 0xd2, - 0x2c, 0x10, 0x92, 0x4d, 0x67, 0xfb, 0x3d, 0x68, 0x1d, 0x4a, 0x64, 0x32, 0x3a, 0xfa, 0x8b, 0x58, - 0xd9, 0x36, 0x2d, 0xea, 0x1a, 0xcb, 0x11, 0xa6, 0xc9, 0x27, 0xc1, 0xb9, 0xcb, 0x9c, 0x61, 0xd5, - 0x6c, 0xe2, 0xfa, 0xe8, 0xfa, 0xda, 0xd2, 0xd2, 0xa2, 0x5c, 0x14, 0x28, 0xe7, 0x4d, 0x8b, 0x28, - 0x54, 0xcb, 0x74, 0x05, 0x5c, 0x64, 0x0a, 0xd5, 0x32, 0x85, 0x78, 0x1f, 0x82, 0x29, 0x4d, 0x63, - 0x63, 0xd6, 0x35, 0x85, 0xef, 0xb1, 0xec, 0x99, 0x4a, 0x40, 0x58, 0x9a, 0x76, 0x81, 0x11, 0x70, - 0x1d, 0xb7, 0xd1, 0xa3, 0x70, 0xc4, 0x13, 0x96, 0x9f, 0x71, 0xb2, 0x6f, 0x94, 0x61, 0xd6, 0x87, - 0x60, 0xaa, 0xbb, 0xdf, 0xcf, 0x88, 0x02, 0x2d, 0x76, 0xf7, 0xc3, 0x6c, 0x8f, 0xc0, 0x74, 0x77, - 0xa7, 0xdb, 0xcf, 0x77, 0x8f, 0x9f, 0x0f, 0x75, 0x77, 0xba, 0x61, 0xc6, 0x3b, 0xe9, 0x86, 0xdb, - 0xc2, 0x9a, 0xea, 0xe0, 0xe6, 0xcc, 0x31, 0x3f, 0xb9, 0xef, 0x01, 0x3a, 0x03, 0x15, 0x4d, 0x53, - 0xb0, 0xa1, 0x6e, 0xb5, 0xb1, 0xa2, 0x5a, 0xd8, 0x50, 0xed, 0x99, 0x9a, 0x9f, 0xb8, 0xac, 0x69, - 0x4b, 0xf4, 0xe9, 0x3c, 0x7d, 0x88, 0xee, 0x81, 0x49, 0x73, 0xeb, 0x79, 0x8d, 0xa9, 0xa4, 0xd2, - 0xb5, 0xf0, 0xb6, 0xbe, 0x37, 0x73, 0x07, 0x95, 0xef, 0x04, 0x79, 0x40, 0x15, 0x72, 0x8d, 0x56, - 0xa3, 0xd3, 0x50, 0xd1, 0xec, 0x1d, 0xd5, 0xea, 0x52, 0x9b, 0x6c, 0x77, 0x55, 0x0d, 0xcf, 0xdc, - 0xc9, 0x48, 0x59, 0xfd, 0x25, 0x51, 0x4d, 0x96, 0x84, 0x7d, 0x4d, 0xdf, 0x76, 0x04, 0xe2, 0xdd, - 0x6c, 0x49, 0xd0, 0x3a, 0x8e, 0x36, 0x0b, 0x15, 0x22, 0x8a, 0x40, 0xc3, 0xb3, 0x94, 0xac, 0xdc, - 0xdd, 0xe9, 0xfa, 0xdb, 0x3d, 0x05, 0xe3, 0x84, 0xd2, 0x6b, 0xf4, 0x34, 0x0b, 0xc8, 0xba, 0x3b, - 0xbe, 0x16, 0x1f, 0x84, 0xa3, 0x84, 0xa8, 0x83, 0x1d, 0xb5, 0xa9, 0x3a, 0xaa, 0x8f, 0xfa, 0x3e, - 0x4a, 0x4d, 0xe4, 0xbe, 0xca, 0x1f, 0x06, 0xfa, 0x69, 0xf5, 0xb6, 0xf6, 0x5d, 0xcd, 0xba, 0x9f, - 0xf5, 0x93, 0xd4, 0x09, 0xdd, 0x7a, 0xcb, 0x82, 0x6e, 0xa9, 0x0e, 0x25, 0xbf, 0xe2, 0xa3, 0x02, - 0x30, 0xd5, 0xaf, 0xa4, 0x48, 0x14, 0xb4, 0x70, 0x79, 0x91, 0xc4, 0x2f, 0xcf, 0x2d, 0x55, 0xd2, - 0x24, 0x8e, 0x5a, 0x59, 0xde, 0x58, 0x52, 0xe4, 0xcd, 0x4b, 0x1b, 0xcb, 0xab, 0x4b, 0x95, 0x8c, - 0x2f, 0x60, 0x7f, 0x32, 0x9b, 0xbf, 0xab, 0x72, 0xb7, 0xf4, 0xed, 0x34, 0x94, 0x83, 0x3b, 0x30, - 0xf4, 0x18, 0x1c, 0x13, 0xe9, 0x12, 0x1b, 0x3b, 0xca, 0x35, 0xdd, 0xa2, 0x2b, 0xb2, 0xa3, 0x32, - 0xef, 0xe8, 0xea, 0xc4, 0x34, 0xa7, 0x5a, 0xc7, 0xce, 0x33, 0xba, 0x45, 0xd6, 0x5b, 0x47, 0x75, - 0xd0, 0x0a, 0xd4, 0x0c, 0x53, 0xb1, 0x1d, 0xd5, 0x68, 0xaa, 0x56, 0x53, 0xf1, 0x12, 0x55, 0x8a, - 0xaa, 0x69, 0xd8, 0xb6, 0x4d, 0xe6, 0x09, 0x5d, 0x94, 0x5b, 0x0d, 0x73, 0x9d, 0x13, 0x7b, 0x2e, - 0x62, 0x9e, 0x93, 0x86, 0xf4, 0x37, 0x33, 0x48, 0x7f, 0x6f, 0x81, 0x42, 0x47, 0xed, 0x2a, 0xd8, - 0x70, 0xac, 0x7d, 0x1a, 0x77, 0xe7, 0xe5, 0x7c, 0x47, 0xed, 0x2e, 0x91, 0xf2, 0xdb, 0xb2, 0xfd, - 0x79, 0x32, 0x9b, 0xcf, 0x57, 0x0a, 0x4f, 0x66, 0xf3, 0x85, 0x0a, 0x48, 0xaf, 0x66, 0xa0, 0xe4, - 0x8f, 0xc3, 0xc9, 0xb6, 0x46, 0xa3, 0x2e, 0x2b, 0x45, 0x8d, 0xda, 0xa9, 0xa1, 0x51, 0xfb, 0xdc, - 0x02, 0xf1, 0x65, 0xf5, 0x1c, 0x8b, 0x8e, 0x65, 0xc6, 0x49, 0xe2, 0x08, 0xa2, 0x6c, 0x98, 0x45, - 0x23, 0x79, 0x99, 0x97, 0xd0, 0x05, 0xc8, 0x3d, 0x6f, 0x53, 0xec, 0x1c, 0xc5, 0xbe, 0x63, 0x38, - 0xf6, 0x93, 0xeb, 0x14, 0xbc, 0xf0, 0xe4, 0xba, 0x72, 0xe9, 0xb2, 0xbc, 0x3a, 0xbf, 0x22, 0x73, - 0x76, 0x74, 0x1c, 0xb2, 0x6d, 0xf5, 0xc5, 0xfd, 0xa0, 0xd7, 0xa3, 0x55, 0x49, 0x27, 0xe1, 0x38, - 0x64, 0xaf, 0x61, 0x75, 0x37, 0xe8, 0x6b, 0x68, 0xd5, 0x5b, 0xb8, 0x18, 0xce, 0xc0, 0x28, 0x95, - 0x17, 0x02, 0xe0, 0x12, 0xab, 0x8c, 0xa0, 0x3c, 0x64, 0x17, 0x2e, 0xcb, 0x64, 0x41, 0x54, 0xa0, - 0xc4, 0x6a, 0x95, 0xb5, 0xe5, 0xa5, 0x85, 0xa5, 0x4a, 0x5a, 0x7a, 0x08, 0x72, 0x4c, 0x08, 0x64, - 0xb1, 0xb8, 0x62, 0xa8, 0x8c, 0xf0, 0x22, 0xc7, 0x48, 0x89, 0xa7, 0x9b, 0xab, 0x8d, 0x25, 0xb9, - 0x92, 0x0e, 0x4e, 0x75, 0xb6, 0x32, 0x2a, 0xd9, 0x50, 0xf2, 0x07, 0xe2, 0x6f, 0xcf, 0x26, 0xfb, - 0x1b, 0x29, 0x28, 0xfa, 0x02, 0x6b, 0x12, 0x11, 0xa9, 0xed, 0xb6, 0x79, 0x4d, 0x51, 0xdb, 0xba, - 0x6a, 0x73, 0xd5, 0x00, 0x5a, 0x35, 0x4f, 0x6a, 0x92, 0x4e, 0xdd, 0xdb, 0xb4, 0x44, 0x46, 0x2b, - 0x39, 0xe9, 0x73, 0x29, 0xa8, 0x84, 0x23, 0xdb, 0x50, 0x37, 0x53, 0x3f, 0xce, 0x6e, 0x4a, 0x9f, - 0x49, 0x41, 0x39, 0x18, 0xce, 0x86, 0xba, 0x77, 0xfb, 0x8f, 0xb5, 0x7b, 0x7f, 0x9e, 0x86, 0xf1, - 0x40, 0x10, 0x9b, 0xb4, 0x77, 0x2f, 0xc0, 0xa4, 0xde, 0xc4, 0x9d, 0xae, 0xe9, 0x60, 0x43, 0xdb, - 0x57, 0xda, 0xf8, 0x2a, 0x6e, 0xcf, 0x48, 0xd4, 0x68, 0x9c, 0x19, 0x1e, 0x26, 0xcf, 0x2d, 0x7b, - 0x7c, 0x2b, 0x84, 0xad, 0x3e, 0xb5, 0xbc, 0xb8, 0xb4, 0xba, 0x76, 0x79, 0x63, 0xe9, 0xd2, 0xc2, - 0xfb, 0x95, 0xcd, 0x4b, 0x4f, 0x5d, 0xba, 0xfc, 0xcc, 0x25, 0xb9, 0xa2, 0x87, 0xc8, 0xde, 0xc2, - 0x65, 0xbf, 0x06, 0x95, 0x70, 0xa7, 0xd0, 0x31, 0x88, 0xea, 0x56, 0x65, 0x04, 0x4d, 0xc1, 0xc4, - 0xa5, 0xcb, 0xca, 0xfa, 0xf2, 0xe2, 0x92, 0xb2, 0x74, 0xfe, 0xfc, 0xd2, 0xc2, 0xc6, 0x3a, 0x4b, - 0x7c, 0xb8, 0xd4, 0x1b, 0x81, 0x05, 0x2e, 0x7d, 0x3a, 0x03, 0x53, 0x11, 0x3d, 0x41, 0xf3, 0x7c, - 0xcb, 0xc2, 0x76, 0x51, 0xf7, 0x27, 0xe9, 0xfd, 0x1c, 0x89, 0x19, 0xd6, 0x54, 0xcb, 0xe1, 0x3b, - 0x9c, 0xd3, 0x40, 0xa4, 0x64, 0x38, 0xfa, 0xb6, 0x8e, 0x2d, 0x9e, 0x27, 0x62, 0xfb, 0x98, 0x09, - 0xaf, 0x9e, 0xa5, 0x8a, 0xee, 0x03, 0xd4, 0x35, 0x6d, 0xdd, 0xd1, 0xaf, 0x62, 0x45, 0x37, 0x44, - 0x52, 0x89, 0xec, 0x6b, 0xb2, 0x72, 0x45, 0x3c, 0x59, 0x36, 0x1c, 0x97, 0xda, 0xc0, 0x2d, 0x35, - 0x44, 0x4d, 0x8c, 0x79, 0x46, 0xae, 0x88, 0x27, 0x2e, 0xf5, 0xed, 0x50, 0x6a, 0x9a, 0x3d, 0x12, - 0xec, 0x31, 0x3a, 0xe2, 0x3b, 0x52, 0x72, 0x91, 0xd5, 0xb9, 0x24, 0x3c, 0x8c, 0xf7, 0xb2, 0x59, - 0x25, 0xb9, 0xc8, 0xea, 0x18, 0xc9, 0xdd, 0x30, 0xa1, 0xb6, 0x5a, 0x16, 0x01, 0x17, 0x40, 0x6c, - 0x63, 0x52, 0x76, 0xab, 0x29, 0x61, 0xf5, 0x49, 0xc8, 0x0b, 0x39, 0x10, 0x57, 0x4d, 0x24, 0xa1, - 0x74, 0xd9, 0x6e, 0x3b, 0x3d, 0x5b, 0x90, 0xf3, 0x86, 0x78, 0x78, 0x3b, 0x94, 0x74, 0x5b, 0xf1, - 0x92, 0xf3, 0xe9, 0x93, 0xe9, 0xd9, 0xbc, 0x5c, 0xd4, 0x6d, 0x37, 0xb1, 0x29, 0x7d, 0x31, 0x0d, - 0xe5, 0xe0, 0xe1, 0x02, 0x5a, 0x84, 0x7c, 0xdb, 0xd4, 0x54, 0xaa, 0x5a, 0xec, 0x64, 0x6b, 0x36, - 0xe6, 0x3c, 0x62, 0x6e, 0x85, 0xd3, 0xcb, 0x2e, 0x67, 0xf5, 0x3f, 0xa4, 0x20, 0x2f, 0xaa, 0xd1, - 0x51, 0xc8, 0x76, 0x55, 0x67, 0x87, 0xc2, 0x8d, 0x36, 0xd2, 0x95, 0x94, 0x4c, 0xcb, 0xa4, 0xde, - 0xee, 0xaa, 0x06, 0x55, 0x01, 0x5e, 0x4f, 0xca, 0x64, 0x5e, 0xdb, 0x58, 0x6d, 0xd2, 0x5d, 0x8f, - 0xd9, 0xe9, 0x60, 0xc3, 0xb1, 0xc5, 0xbc, 0xf2, 0xfa, 0x05, 0x5e, 0x8d, 0xee, 0x85, 0x49, 0xc7, - 0x52, 0xf5, 0x76, 0x80, 0x36, 0x4b, 0x69, 0x2b, 0xe2, 0x81, 0x4b, 0x5c, 0x87, 0xe3, 0x02, 0xb7, - 0x89, 0x1d, 0x55, 0xdb, 0xc1, 0x4d, 0x8f, 0x29, 0x47, 0xb3, 0x1b, 0xc7, 0x38, 0xc1, 0x22, 0x7f, - 0x2e, 0x78, 0xa5, 0x6f, 0xa7, 0x60, 0x52, 0xec, 0xd3, 0x9a, 0xae, 0xb0, 0x56, 0x01, 0x54, 0xc3, - 0x30, 0x1d, 0xbf, 0xb8, 0xfa, 0x55, 0xb9, 0x8f, 0x6f, 0x6e, 0xde, 0x65, 0x92, 0x7d, 0x00, 0xd5, - 0x0e, 0x80, 0xf7, 0x64, 0xa0, 0xd8, 0x6a, 0x50, 0xe4, 0x27, 0x47, 0xf4, 0xf8, 0x91, 0xed, 0xec, - 0x81, 0x55, 0x91, 0x0d, 0x1d, 0x9a, 0x86, 0xd1, 0x2d, 0xdc, 0xd2, 0x0d, 0x9e, 0x0f, 0x66, 0x05, - 0x91, 0x7f, 0xc9, 0xba, 0xf9, 0x97, 0xc6, 0x27, 0x52, 0x30, 0xa5, 0x99, 0x9d, 0x70, 0x7f, 0x1b, - 0x95, 0x50, 0x7a, 0xc1, 0xbe, 0x98, 0x7a, 0xee, 0xf1, 0x96, 0xee, 0xec, 0xf4, 0xb6, 0xe6, 0x34, - 0xb3, 0x73, 0xa6, 0x65, 0xb6, 0x55, 0xa3, 0xe5, 0x9d, 0x9f, 0xd2, 0x1f, 0xda, 0xfd, 0x2d, 0x6c, - 0xdc, 0xdf, 0x32, 0x7d, 0xa7, 0xa9, 0xe7, 0xbc, 0x9f, 0x7f, 0x9d, 0x4a, 0x7d, 0x21, 0x9d, 0xb9, - 0xb0, 0xd6, 0xf8, 0x52, 0xba, 0x7a, 0x81, 0x35, 0xb7, 0x26, 0xc4, 0x23, 0xe3, 0xed, 0x36, 0xd6, - 0xc8, 0x90, 0xe1, 0xfb, 0xf7, 0xc2, 0x74, 0xcb, 0x6c, 0x99, 0x14, 0xf1, 0x0c, 0xf9, 0xc5, 0x4f, - 0x64, 0x0b, 0x6e, 0x6d, 0x35, 0xf6, 0xf8, 0xb6, 0x7e, 0x09, 0xa6, 0x38, 0xb1, 0x42, 0x8f, 0x84, - 0xd8, 0xc6, 0x06, 0x0d, 0x4d, 0xab, 0xcd, 0xfc, 0xfe, 0x77, 0xa9, 0x43, 0x97, 0x27, 0x39, 0x2b, - 0x79, 0xc6, 0xf6, 0x3e, 0x75, 0x19, 0x8e, 0x04, 0xf0, 0xd8, 0xb2, 0xc5, 0x56, 0x0c, 0xe2, 0xbf, - 0xe5, 0x88, 0x53, 0x3e, 0xc4, 0x75, 0xce, 0x5a, 0x5f, 0x80, 0xf1, 0xc3, 0x60, 0xfd, 0x3b, 0x8e, - 0x55, 0xc2, 0x7e, 0x90, 0x0b, 0x30, 0x41, 0x41, 0xb4, 0x9e, 0xed, 0x98, 0x1d, 0x6a, 0x13, 0x87, - 0xc3, 0xfc, 0xd1, 0x77, 0xd9, 0x3a, 0x2a, 0x13, 0xb6, 0x05, 0x97, 0xab, 0x5e, 0x07, 0x7a, 0x0a, - 0xd6, 0xc4, 0x5a, 0x3b, 0x06, 0xe1, 0x9b, 0xbc, 0x23, 0x2e, 0x7d, 0xfd, 0x0a, 0x4c, 0x93, 0xdf, - 0xd4, 0x64, 0xf9, 0x7b, 0x12, 0x9f, 0x83, 0x9b, 0xf9, 0xf6, 0x2f, 0xb0, 0xa5, 0x3a, 0xe5, 0x02, - 0xf8, 0xfa, 0xe4, 0x9b, 0xc5, 0x16, 0x76, 0x1c, 0x6c, 0xd9, 0x8a, 0xda, 0x8e, 0xea, 0x9e, 0x2f, - 0x89, 0x31, 0xf3, 0x1b, 0xaf, 0x07, 0x67, 0xf1, 0x02, 0xe3, 0x9c, 0x6f, 0xb7, 0xeb, 0x9b, 0x70, - 0x2c, 0x42, 0x2b, 0x12, 0x60, 0x7e, 0x9a, 0x63, 0x4e, 0xf7, 0x69, 0x06, 0x81, 0x5d, 0x03, 0x51, - 0xef, 0xce, 0x65, 0x02, 0xcc, 0xdf, 0xe4, 0x98, 0x88, 0xf3, 0x8a, 0x29, 0x25, 0x88, 0x4f, 0xc2, - 0xe4, 0x55, 0x6c, 0x6d, 0x99, 0x36, 0x4f, 0x1c, 0x25, 0x80, 0xfb, 0x0c, 0x87, 0x9b, 0xe0, 0x8c, - 0x34, 0x93, 0x44, 0xb0, 0x1e, 0x85, 0xfc, 0xb6, 0xaa, 0xe1, 0x04, 0x10, 0x9f, 0xe5, 0x10, 0x63, - 0x84, 0x9e, 0xb0, 0xce, 0x43, 0xa9, 0x65, 0x72, 0xaf, 0x15, 0xcf, 0xfe, 0x39, 0xce, 0x5e, 0x14, - 0x3c, 0x1c, 0xa2, 0x6b, 0x76, 0x7b, 0x6d, 0xe2, 0xd2, 0xe2, 0x21, 0x7e, 0x4b, 0x40, 0x08, 0x1e, - 0x0e, 0x71, 0x08, 0xb1, 0xbe, 0x22, 0x20, 0x6c, 0x9f, 0x3c, 0x9f, 0x80, 0xa2, 0x69, 0xb4, 0xf7, - 0x4d, 0x23, 0x49, 0x27, 0x3e, 0xcf, 0x11, 0x80, 0xb3, 0x10, 0x80, 0x73, 0x50, 0x48, 0x3a, 0x11, - 0xff, 0xf0, 0x75, 0xb1, 0x3c, 0xc4, 0x0c, 0x5c, 0x80, 0x09, 0x61, 0xa0, 0x74, 0xd3, 0x48, 0x00, - 0xf1, 0x8f, 0x38, 0x44, 0xd9, 0xc7, 0xc6, 0x87, 0xe1, 0x60, 0xdb, 0x69, 0xe1, 0x24, 0x20, 0x5f, - 0x14, 0xc3, 0xe0, 0x2c, 0x5c, 0x94, 0x5b, 0xd8, 0xd0, 0x76, 0x92, 0x21, 0xfc, 0xb6, 0x10, 0xa5, - 0xe0, 0x21, 0x10, 0x0b, 0x30, 0xde, 0x51, 0x2d, 0x7b, 0x47, 0x6d, 0x27, 0x9a, 0x8e, 0x7f, 0xcc, - 0x31, 0x4a, 0x2e, 0x13, 0x97, 0x48, 0xcf, 0x38, 0x0c, 0xcc, 0x97, 0x84, 0x44, 0x7c, 0x6c, 0x7c, - 0xe9, 0xd9, 0x0e, 0xcd, 0xb2, 0x1d, 0x06, 0xed, 0x9f, 0x88, 0xa5, 0xc7, 0x78, 0x57, 0xfd, 0x88, - 0xe7, 0xa0, 0x60, 0xeb, 0x2f, 0x26, 0x82, 0xf9, 0xa7, 0x62, 0xa6, 0x29, 0x03, 0x61, 0x7e, 0x3f, - 0x1c, 0x8f, 0x74, 0x13, 0x09, 0xc0, 0xfe, 0x19, 0x07, 0x3b, 0x1a, 0xe1, 0x2a, 0xb8, 0x49, 0x38, - 0x2c, 0xe4, 0xef, 0x08, 0x93, 0x80, 0x43, 0x58, 0x6b, 0x64, 0x1f, 0x61, 0xab, 0xdb, 0x87, 0x93, - 0xda, 0xef, 0x0a, 0xa9, 0x31, 0xde, 0x80, 0xd4, 0x36, 0xe0, 0x28, 0x47, 0x3c, 0xdc, 0xbc, 0xfe, - 0x9e, 0x30, 0xac, 0x8c, 0x7b, 0x33, 0x38, 0xbb, 0x1f, 0x80, 0xaa, 0x2b, 0x4e, 0x11, 0xb0, 0xda, - 0x4a, 0x47, 0xed, 0x26, 0x40, 0xfe, 0x7d, 0x8e, 0x2c, 0x2c, 0xbe, 0x1b, 0xf1, 0xda, 0xab, 0x6a, - 0x97, 0x80, 0x3f, 0x0b, 0x33, 0x02, 0xbc, 0x67, 0x58, 0x58, 0x33, 0x5b, 0x86, 0xfe, 0x22, 0x6e, - 0x26, 0x80, 0xfe, 0xe7, 0xa1, 0xa9, 0xda, 0xf4, 0xb1, 0x13, 0xe4, 0x65, 0xa8, 0xb8, 0xb1, 0x8a, - 0xa2, 0x77, 0xba, 0xa6, 0xe5, 0xc4, 0x20, 0xfe, 0x0b, 0x31, 0x53, 0x2e, 0xdf, 0x32, 0x65, 0xab, - 0x2f, 0x41, 0x99, 0x16, 0x93, 0xaa, 0xe4, 0x97, 0x39, 0xd0, 0xb8, 0xc7, 0xc5, 0x0d, 0x87, 0x66, - 0x76, 0xba, 0xaa, 0x95, 0xc4, 0xfe, 0xfd, 0x4b, 0x61, 0x38, 0x38, 0x0b, 0x37, 0x1c, 0xce, 0x7e, - 0x17, 0x13, 0x6f, 0x9f, 0x00, 0xe1, 0x2b, 0xc2, 0x70, 0x08, 0x1e, 0x0e, 0x21, 0x02, 0x86, 0x04, - 0x10, 0x5f, 0x15, 0x10, 0x82, 0x87, 0x40, 0x3c, 0xed, 0x39, 0x5a, 0x0b, 0xb7, 0x74, 0xdb, 0xb1, - 0x58, 0x98, 0x3c, 0x1c, 0xea, 0x6b, 0xaf, 0x07, 0x83, 0x30, 0xd9, 0xc7, 0x4a, 0x2c, 0x11, 0x4f, - 0xbb, 0xd2, 0x5d, 0x54, 0x7c, 0xc7, 0xbe, 0x2e, 0x2c, 0x91, 0x8f, 0x8d, 0xf4, 0xcd, 0x17, 0x21, - 0x12, 0xb1, 0x6b, 0x64, 0xef, 0x90, 0x00, 0xee, 0x0f, 0x42, 0x9d, 0x5b, 0x17, 0xbc, 0x04, 0xd3, - 0x17, 0xff, 0xf4, 0x8c, 0x5d, 0xbc, 0x9f, 0x48, 0x3b, 0xff, 0x30, 0x14, 0xff, 0x6c, 0x32, 0x4e, - 0x66, 0x43, 0x26, 0x42, 0xf1, 0x14, 0x8a, 0xbb, 0x3f, 0x34, 0xf3, 0xb7, 0xdf, 0xe0, 0xe3, 0x0d, - 0x86, 0x53, 0xf5, 0x15, 0xa2, 0xe4, 0xc1, 0xa0, 0x27, 0x1e, 0xec, 0x17, 0xde, 0x70, 0xf5, 0x3c, - 0x10, 0xf3, 0xd4, 0xcf, 0xc3, 0x78, 0x20, 0xe0, 0x89, 0x87, 0xfa, 0x10, 0x87, 0x2a, 0xf9, 0xe3, - 0x9d, 0xfa, 0x43, 0x90, 0x25, 0xc1, 0x4b, 0x3c, 0xfb, 0x2f, 0x72, 0x76, 0x4a, 0x5e, 0x7f, 0x2f, - 0xe4, 0x45, 0xd0, 0x12, 0xcf, 0xfa, 0x61, 0xce, 0xea, 0xb2, 0x10, 0x76, 0x11, 0xb0, 0xc4, 0xb3, - 0x7f, 0x44, 0xb0, 0x0b, 0x16, 0xc2, 0x9e, 0x5c, 0x84, 0xdf, 0xf8, 0x3b, 0x59, 0xee, 0x74, 0x84, - 0xec, 0xce, 0xc1, 0x18, 0x8f, 0x54, 0xe2, 0xb9, 0x3f, 0xc6, 0x1b, 0x17, 0x1c, 0xf5, 0x47, 0x60, - 0x34, 0xa1, 0xc0, 0x7f, 0x99, 0xb3, 0x32, 0xfa, 0xfa, 0x02, 0x14, 0x7d, 0xd1, 0x49, 0x3c, 0xfb, - 0xaf, 0x70, 0x76, 0x3f, 0x17, 0xe9, 0x3a, 0x8f, 0x4e, 0xe2, 0x01, 0x3e, 0x21, 0xba, 0xce, 0x39, - 0x88, 0xd8, 0x44, 0x60, 0x12, 0xcf, 0xfd, 0x49, 0x21, 0x75, 0xc1, 0x52, 0x7f, 0x02, 0x0a, 0xae, - 0xb3, 0x89, 0xe7, 0xff, 0xbb, 0x9c, 0xdf, 0xe3, 0x21, 0x12, 0xf0, 0x39, 0xbb, 0x78, 0x88, 0x4f, - 0x09, 0x09, 0xf8, 0xb8, 0xc8, 0x32, 0x0a, 0x07, 0x30, 0xf1, 0x48, 0x7f, 0x4f, 0x2c, 0xa3, 0x50, - 0xfc, 0x42, 0x66, 0x93, 0xda, 0xfc, 0x78, 0x88, 0x5f, 0x15, 0xb3, 0x49, 0xe9, 0x49, 0x37, 0xc2, - 0x11, 0x41, 0x3c, 0xc6, 0xdf, 0x17, 0xdd, 0x08, 0x05, 0x04, 0xf5, 0x35, 0x40, 0xfd, 0xd1, 0x40, - 0x3c, 0xde, 0xcb, 0x1c, 0x6f, 0xb2, 0x2f, 0x18, 0xa8, 0x3f, 0x03, 0x47, 0xa3, 0x23, 0x81, 0x78, - 0xd4, 0xdf, 0x78, 0x23, 0xb4, 0x77, 0xf3, 0x07, 0x02, 0xf5, 0x0d, 0xcf, 0xa5, 0xf8, 0xa3, 0x80, - 0x78, 0xd8, 0x4f, 0xbf, 0x11, 0x34, 0xdc, 0xfe, 0x20, 0xa0, 0x3e, 0x0f, 0xe0, 0x39, 0xe0, 0x78, - 0xac, 0xcf, 0x70, 0x2c, 0x1f, 0x13, 0x59, 0x1a, 0xdc, 0xff, 0xc6, 0xf3, 0x7f, 0x56, 0x2c, 0x0d, - 0xce, 0x41, 0x96, 0x86, 0x70, 0xbd, 0xf1, 0xdc, 0x9f, 0x13, 0x4b, 0x43, 0xb0, 0x10, 0xcd, 0xf6, - 0x79, 0xb7, 0x78, 0x84, 0xcf, 0x0b, 0xcd, 0xf6, 0x71, 0xd5, 0x2f, 0xc1, 0x64, 0x9f, 0x43, 0x8c, - 0x87, 0xfa, 0x02, 0x87, 0xaa, 0x84, 0xfd, 0xa1, 0xdf, 0x79, 0x71, 0x67, 0x18, 0x8f, 0xf6, 0x0f, - 0x42, 0xce, 0x8b, 0xfb, 0xc2, 0xfa, 0x39, 0xc8, 0x1b, 0xbd, 0x76, 0x9b, 0x2c, 0x1e, 0x34, 0xfc, - 0xce, 0xdf, 0xcc, 0x7f, 0xff, 0x11, 0x97, 0x8e, 0x60, 0xa8, 0x3f, 0x04, 0xa3, 0xb8, 0xb3, 0x85, - 0x9b, 0x71, 0x9c, 0xdf, 0xff, 0x91, 0x30, 0x98, 0x84, 0xba, 0xfe, 0x04, 0x00, 0x4b, 0x8d, 0xd0, - 0xe3, 0xc1, 0x18, 0xde, 0xff, 0xf1, 0x23, 0x7e, 0x1b, 0xc7, 0x63, 0xf1, 0x00, 0xd8, 0xdd, 0x9e, - 0xe1, 0x00, 0xaf, 0x07, 0x01, 0xe8, 0x8c, 0x3c, 0x0a, 0x63, 0xcf, 0xdb, 0xa6, 0xe1, 0xa8, 0xad, - 0x38, 0xee, 0xff, 0xc9, 0xb9, 0x05, 0x3d, 0x11, 0x58, 0xc7, 0xb4, 0xb0, 0xa3, 0xb6, 0xec, 0x38, - 0xde, 0xff, 0xc5, 0x79, 0x5d, 0x06, 0xc2, 0xac, 0xa9, 0xb6, 0x93, 0x64, 0xdc, 0xff, 0x5b, 0x30, - 0x0b, 0x06, 0xd2, 0x69, 0xf2, 0x7b, 0x17, 0xef, 0xc7, 0xf1, 0xfe, 0x40, 0x74, 0x9a, 0xd3, 0xd7, - 0xdf, 0x0b, 0x05, 0xf2, 0x93, 0x5d, 0xb1, 0x8b, 0x61, 0xfe, 0x3f, 0x9c, 0xd9, 0xe3, 0x20, 0x2d, - 0xdb, 0x4e, 0xd3, 0xd1, 0xe3, 0x85, 0x7d, 0x9d, 0xcf, 0xb4, 0xa0, 0xaf, 0xcf, 0x43, 0xd1, 0x76, - 0x9a, 0xcd, 0x1e, 0x8f, 0x4f, 0x63, 0xd8, 0xff, 0xef, 0x8f, 0xdc, 0x94, 0x85, 0xcb, 0x43, 0x66, - 0xfb, 0xda, 0xae, 0xd3, 0x35, 0xe9, 0x11, 0x48, 0x1c, 0xc2, 0x1b, 0x1c, 0xc1, 0xc7, 0x52, 0x5f, - 0x80, 0x12, 0x19, 0x8b, 0x85, 0xbb, 0x98, 0x9e, 0x57, 0xc5, 0x40, 0xfc, 0x25, 0x17, 0x40, 0x80, - 0xa9, 0xf1, 0xb3, 0xdf, 0x7c, 0xf5, 0x44, 0xea, 0x5b, 0xaf, 0x9e, 0x48, 0xfd, 0xf9, 0xab, 0x27, - 0x52, 0x9f, 0x7c, 0xed, 0xc4, 0xc8, 0xb7, 0x5e, 0x3b, 0x31, 0xf2, 0xa7, 0xaf, 0x9d, 0x18, 0x89, - 0x4e, 0x1b, 0xc3, 0x05, 0xf3, 0x82, 0xc9, 0x12, 0xc6, 0xcf, 0x49, 0x81, 0x74, 0x71, 0xcb, 0xf4, - 0xb2, 0xb5, 0xee, 0x26, 0x07, 0xfe, 0x20, 0x0d, 0x77, 0xd2, 0xeb, 0xbe, 0x56, 0x47, 0x37, 0x9c, - 0x33, 0x9a, 0xb5, 0xdf, 0x75, 0xcc, 0x33, 0x1d, 0x6c, 0xed, 0xb6, 0x31, 0xff, 0xc3, 0xb3, 0xbf, - 0x33, 0x1e, 0xd9, 0x1c, 0x23, 0x9b, 0x63, 0xcf, 0xab, 0x91, 0xd9, 0x62, 0x69, 0x01, 0xc6, 0xd6, - 0x2c, 0xd3, 0xdc, 0xbe, 0xdc, 0x45, 0x88, 0xdf, 0x60, 0xe6, 0x37, 0xe3, 0xa8, 0x1a, 0x56, 0x20, - 0xb3, 0x8b, 0xf7, 0x69, 0xe2, 0xbc, 0x24, 0x93, 0x9f, 0x84, 0xaa, 0xa9, 0x3a, 0x2a, 0x4d, 0x98, - 0x97, 0x64, 0xfa, 0x5b, 0x6a, 0xc0, 0x28, 0x05, 0x41, 0x8f, 0x42, 0xc6, 0xec, 0xda, 0x3c, 0xbb, - 0x7f, 0xfb, 0xdc, 0xa0, 0xbe, 0xcc, 0xf1, 0x26, 0x1b, 0xd9, 0x6f, 0x1e, 0xd4, 0x46, 0x64, 0xc2, - 0xd3, 0x58, 0xfb, 0xeb, 0xef, 0x9c, 0x48, 0xfd, 0xf6, 0xab, 0x27, 0x52, 0x83, 0x24, 0xf9, 0xdc, - 0x9c, 0x4f, 0x50, 0x3e, 0x61, 0x0c, 0x92, 0xcb, 0x56, 0x8e, 0x8e, 0xf0, 0xdd, 0xf0, 0x4b, 0x69, - 0x38, 0xe1, 0x23, 0x6a, 0xeb, 0x5b, 0xf6, 0x99, 0xdd, 0xab, 0x67, 0xc8, 0xf8, 0x6c, 0x2e, 0x35, - 0xe4, 0xeb, 0x29, 0x79, 0x3e, 0xb7, 0x7b, 0x75, 0x80, 0xbc, 0xe6, 0x20, 0xbb, 0xa6, 0xea, 0x96, - 0x10, 0x4c, 0xca, 0x13, 0xcc, 0xb4, 0x77, 0xb9, 0x95, 0xd4, 0xb1, 0x82, 0x74, 0x16, 0xf2, 0x4f, - 0x2d, 0x3f, 0xfc, 0x60, 0x12, 0x9e, 0x0c, 0xe7, 0x69, 0xc8, 0x42, 0x14, 0x5f, 0x8b, 0x10, 0xc7, - 0x37, 0x5e, 0x3b, 0x91, 0x72, 0x45, 0x32, 0x1b, 0x2b, 0x12, 0x3e, 0x5a, 0x57, 0x18, 0x9f, 0x4c, - 0x43, 0x2d, 0x7c, 0x2a, 0x40, 0x96, 0xa2, 0xed, 0xa8, 0x9d, 0xee, 0xa0, 0x77, 0xba, 0xce, 0x41, - 0x61, 0x43, 0xd0, 0xa0, 0x19, 0x18, 0xb3, 0xb1, 0x66, 0x1a, 0x4d, 0x9b, 0x8e, 0x24, 0x23, 0x8b, - 0x22, 0x19, 0x8d, 0xa1, 0x1a, 0xa6, 0xcd, 0xaf, 0x9c, 0xb2, 0x42, 0xe3, 0xd7, 0x53, 0x87, 0x5b, - 0x1b, 0x65, 0xb7, 0x29, 0xba, 0x40, 0xd6, 0x52, 0xcf, 0xdd, 0x3b, 0xec, 0x40, 0x85, 0x4e, 0xa3, - 0x37, 0x04, 0xdf, 0xe9, 0xc9, 0x89, 0xf0, 0xe9, 0xc9, 0x33, 0xb8, 0xdd, 0x7e, 0xca, 0x30, 0xaf, - 0x19, 0x1b, 0x84, 0xc7, 0x15, 0xc9, 0xc7, 0xd3, 0x70, 0xa2, 0xef, 0xa0, 0x84, 0x9b, 0x97, 0x41, - 0x12, 0xa9, 0x43, 0x7e, 0x51, 0x58, 0xad, 0xc3, 0x0a, 0xe4, 0x57, 0x0f, 0x29, 0x90, 0x71, 0xd1, - 0x92, 0x90, 0xc7, 0x3d, 0xf1, 0xf2, 0x10, 0xfd, 0xbf, 0x01, 0x71, 0x7c, 0xe8, 0x71, 0xb8, 0xdd, - 0xa7, 0x40, 0xea, 0x96, 0xa6, 0x9f, 0xe1, 0x42, 0xf6, 0xad, 0x98, 0x23, 0xbe, 0x15, 0x43, 0x48, - 0xe6, 0xe8, 0xc3, 0xe8, 0x45, 0x53, 0x4d, 0x66, 0xbb, 0xaa, 0x31, 0xab, 0xb4, 0x1a, 0xa7, 0xb8, - 0xd5, 0x98, 0x69, 0x94, 0xfe, 0x6a, 0x14, 0xc6, 0x64, 0xfc, 0x42, 0x0f, 0xdb, 0xf4, 0x95, 0x44, - 0xac, 0xed, 0x98, 0xfc, 0xb6, 0xbb, 0x34, 0x17, 0x39, 0x9e, 0x39, 0x4e, 0xbd, 0xa4, 0xed, 0x98, - 0x17, 0x47, 0x64, 0xca, 0x41, 0xdf, 0x01, 0x6b, 0xf7, 0xec, 0x1d, 0x7e, 0x29, 0xf9, 0xd4, 0x70, - 0xd6, 0xf3, 0x84, 0xf4, 0xe2, 0x88, 0xcc, 0x78, 0x48, 0xb3, 0xf4, 0xfd, 0xb5, 0x6c, 0x92, 0x66, - 0x97, 0x8d, 0x6d, 0xda, 0x2c, 0xe1, 0x40, 0x17, 0x01, 0x6c, 0xec, 0x88, 0xab, 0x0c, 0xa3, 0x94, - 0xff, 0xee, 0xe1, 0xfc, 0xeb, 0xd8, 0x61, 0x6e, 0xeb, 0xe2, 0x88, 0x5c, 0xb0, 0x45, 0x81, 0x20, - 0xe9, 0x86, 0xee, 0x28, 0xda, 0x8e, 0xaa, 0x1b, 0xf4, 0x0c, 0x3e, 0x16, 0x69, 0xd9, 0xd0, 0x9d, - 0x05, 0x42, 0x4e, 0x90, 0x74, 0x51, 0x20, 0xa2, 0x78, 0xa1, 0x87, 0xf9, 0xdd, 0xb7, 0x58, 0x51, - 0x3c, 0x4d, 0x48, 0x89, 0x28, 0x28, 0x0f, 0x7a, 0x0a, 0x8a, 0xf4, 0xb8, 0x55, 0xd9, 0x6a, 0x9b, - 0xda, 0x2e, 0x7f, 0xb3, 0x64, 0x76, 0x38, 0x44, 0x83, 0x30, 0x34, 0x08, 0xfd, 0xc5, 0x11, 0x19, - 0xb6, 0xdc, 0x12, 0x6a, 0x40, 0x9e, 0x5d, 0xfb, 0x75, 0xf6, 0xf8, 0xbb, 0x81, 0x77, 0x0e, 0x47, - 0xa2, 0x37, 0x80, 0x37, 0xf6, 0x2e, 0x8e, 0xc8, 0x63, 0x1a, 0xfb, 0x89, 0x96, 0xa0, 0x80, 0x8d, - 0x26, 0xef, 0x4e, 0x91, 0xbf, 0x45, 0x35, 0x5c, 0x2f, 0x8c, 0xa6, 0xe8, 0x4c, 0x1e, 0xf3, 0xdf, - 0xe8, 0x71, 0xc8, 0x69, 0x66, 0xa7, 0xa3, 0x3b, 0xf4, 0x1d, 0xc3, 0xe2, 0xd9, 0x3b, 0x62, 0x3a, - 0x42, 0x69, 0x2f, 0x8e, 0xc8, 0x9c, 0x8b, 0x4c, 0x4f, 0x13, 0xb7, 0xf5, 0xab, 0xd8, 0x22, 0x83, - 0x99, 0x4a, 0x32, 0x3d, 0x8b, 0x8c, 0x9e, 0x0e, 0xa7, 0xd0, 0x14, 0x85, 0xc6, 0x18, 0x77, 0x2f, - 0xd2, 0xdd, 0x50, 0xf4, 0x69, 0x32, 0xb1, 0x58, 0x7c, 0x07, 0xc2, 0x9d, 0xbd, 0x28, 0x4a, 0x65, - 0x28, 0xf9, 0xf5, 0x56, 0xea, 0xb8, 0x8c, 0xf4, 0x10, 0x7f, 0x06, 0xc6, 0xae, 0x62, 0xcb, 0x66, - 0x27, 0xf8, 0x94, 0x91, 0x17, 0xd1, 0x29, 0x18, 0xa7, 0x72, 0x53, 0xc4, 0xf3, 0x34, 0xbd, 0x30, - 0x52, 0xa2, 0x95, 0x57, 0x38, 0x51, 0x0d, 0x8a, 0xdd, 0xb3, 0x5d, 0x97, 0x24, 0x43, 0x49, 0xa0, - 0x7b, 0xb6, 0xcb, 0x09, 0xa4, 0x3a, 0x54, 0xc2, 0xaa, 0xeb, 0xf7, 0x9a, 0x85, 0x08, 0xaf, 0x59, - 0x10, 0x9e, 0xf6, 0xf7, 0xd2, 0x2e, 0xb3, 0xab, 0xad, 0x64, 0xb9, 0x11, 0x23, 0x41, 0xb9, 0x8b, - 0x67, 0xab, 0x7d, 0xa1, 0x9d, 0xeb, 0x6b, 0x1a, 0x79, 0x12, 0x8a, 0x7c, 0xf2, 0xcf, 0x6a, 0x29, - 0x99, 0x72, 0xa0, 0xe3, 0x44, 0xa1, 0x54, 0xdd, 0x50, 0xf4, 0xa6, 0x78, 0x9b, 0x98, 0x96, 0x97, - 0x9b, 0xe8, 0x69, 0xa8, 0x68, 0xa6, 0x61, 0x63, 0xc3, 0xee, 0xd9, 0x4a, 0x57, 0xb5, 0xd4, 0x8e, - 0xf7, 0xd2, 0x5d, 0xf4, 0x34, 0x2d, 0x08, 0xf2, 0x35, 0x4a, 0x2d, 0x4f, 0x68, 0xc1, 0x0a, 0xb4, - 0x02, 0x70, 0x55, 0x6d, 0xeb, 0x4d, 0xd5, 0x31, 0x2d, 0x9b, 0xbf, 0x9c, 0x32, 0x08, 0xec, 0x8a, - 0x20, 0xdc, 0xec, 0x36, 0x55, 0x07, 0xf3, 0x20, 0xca, 0xc7, 0x8f, 0xee, 0x82, 0x09, 0xb5, 0xdb, - 0x55, 0x6c, 0x47, 0x75, 0xb0, 0xb2, 0xb5, 0xef, 0x60, 0x9b, 0xda, 0x8b, 0x92, 0x3c, 0xae, 0x76, - 0xbb, 0xeb, 0xa4, 0xb6, 0x41, 0x2a, 0xa5, 0xa6, 0x3b, 0xdb, 0x74, 0x69, 0xba, 0xb1, 0x5d, 0xca, - 0x8b, 0xed, 0x48, 0x1d, 0xbd, 0x5a, 0xc1, 0x64, 0x20, 0x6e, 0xa3, 0xe4, 0x76, 0xb0, 0xde, 0xda, - 0x71, 0xe8, 0xb0, 0x33, 0x32, 0x2f, 0x91, 0x89, 0xe9, 0x5a, 0xe6, 0x55, 0x76, 0x5b, 0x28, 0x2f, - 0xb3, 0x82, 0xf4, 0x6b, 0x69, 0x98, 0xec, 0x5b, 0xbe, 0x04, 0x97, 0x5e, 0xf0, 0xe7, 0x6d, 0x91, - 0xdf, 0xe8, 0x1c, 0xc1, 0x55, 0x9b, 0xfc, 0xa5, 0x95, 0xe2, 0xd9, 0xdb, 0x06, 0x48, 0xe0, 0x22, - 0x25, 0xe2, 0x03, 0xe7, 0x2c, 0x68, 0x13, 0x2a, 0x6d, 0xd5, 0x76, 0x14, 0xb6, 0x8a, 0xd8, 0x5b, - 0xc2, 0x99, 0xa1, 0x96, 0x60, 0x45, 0x15, 0xab, 0x8f, 0x28, 0x37, 0x87, 0x2b, 0xb7, 0x03, 0xb5, - 0xe8, 0x59, 0x98, 0xde, 0xda, 0x7f, 0x51, 0x35, 0x1c, 0xdd, 0xa0, 0x97, 0x8d, 0x82, 0x73, 0x54, - 0x1b, 0x00, 0xbd, 0x74, 0x55, 0x6f, 0x62, 0x43, 0x13, 0x93, 0x33, 0xe5, 0x42, 0xb8, 0x93, 0x67, - 0x4b, 0xcf, 0x42, 0x39, 0x68, 0x8b, 0x50, 0x19, 0xd2, 0xce, 0x1e, 0x97, 0x48, 0xda, 0xd9, 0x43, - 0x0f, 0xf3, 0x88, 0x3c, 0x4d, 0x6f, 0xcb, 0x0d, 0x72, 0x16, 0x9c, 0xdb, 0x7b, 0x97, 0x50, 0x92, - 0xdc, 0x95, 0xe0, 0x1a, 0x86, 0x30, 0xb6, 0x74, 0x1a, 0x26, 0x42, 0x46, 0xcc, 0x37, 0xad, 0x29, - 0xff, 0xb4, 0x4a, 0x13, 0x30, 0x1e, 0xb0, 0x55, 0xd2, 0x1f, 0xe7, 0x20, 0x2f, 0x63, 0xbb, 0x4b, - 0x94, 0x18, 0x5d, 0x84, 0x02, 0xde, 0xd3, 0x70, 0xd7, 0x11, 0x56, 0x61, 0x98, 0x11, 0x67, 0x3c, - 0x4b, 0x82, 0x9e, 0x98, 0x2b, 0x97, 0x19, 0x3d, 0x1a, 0x70, 0xc9, 0xa7, 0xe2, 0x40, 0xfc, 0x3e, - 0xf9, 0xb1, 0xa0, 0x4f, 0xbe, 0x23, 0x86, 0x37, 0xe4, 0x94, 0x1f, 0x0d, 0x38, 0xe5, 0xb8, 0x86, - 0x03, 0x5e, 0x79, 0x39, 0xc2, 0x2b, 0xc7, 0x0d, 0x7f, 0x80, 0x5b, 0x5e, 0x8e, 0x70, 0xcb, 0xb3, - 0xb1, 0x7d, 0x89, 0xf4, 0xcb, 0x8f, 0x05, 0xfd, 0x72, 0x9c, 0x38, 0x42, 0x8e, 0x79, 0x25, 0xca, - 0x31, 0x9f, 0x8e, 0xc1, 0x18, 0xe8, 0x99, 0x17, 0xfa, 0x3c, 0xf3, 0x5d, 0x31, 0x50, 0x11, 0xae, - 0x79, 0x39, 0xe0, 0x13, 0x21, 0x91, 0x6c, 0xa2, 0x9d, 0x22, 0x3a, 0xdf, 0xef, 0xe5, 0xef, 0x8e, - 0x53, 0xb5, 0x28, 0x37, 0xff, 0x44, 0xc8, 0xcd, 0xdf, 0x19, 0x37, 0xaa, 0x90, 0x9f, 0xf7, 0xbc, - 0xf3, 0x69, 0x62, 0x1f, 0x43, 0x2b, 0x83, 0xd8, 0x52, 0x6c, 0x59, 0xa6, 0xc5, 0x1d, 0x1f, 0x2b, - 0x48, 0xb3, 0xc4, 0x62, 0x7b, 0xfa, 0x3f, 0xc4, 0x93, 0xd3, 0x45, 0xeb, 0xd3, 0x76, 0xe9, 0x6b, - 0x29, 0x8f, 0x97, 0x5a, 0x36, 0xbf, 0xb5, 0x2f, 0x70, 0x6b, 0xef, 0x73, 0xf0, 0xe9, 0xa0, 0x83, - 0xaf, 0x41, 0x91, 0xf8, 0x94, 0x90, 0xef, 0x56, 0xbb, 0xc2, 0x77, 0xa3, 0x7b, 0x60, 0x92, 0xda, - 0x5f, 0x16, 0x06, 0x70, 0x43, 0x92, 0xa5, 0x86, 0x64, 0x82, 0x3c, 0x60, 0x12, 0x64, 0x8e, 0xe2, - 0x7e, 0x98, 0xf2, 0xd1, 0x12, 0x5c, 0xea, 0x0b, 0x98, 0x93, 0xaa, 0xb8, 0xd4, 0xf3, 0xdd, 0xee, - 0x45, 0xd5, 0xde, 0x91, 0x56, 0x3d, 0x01, 0x79, 0x71, 0x01, 0x82, 0xac, 0x66, 0x36, 0xd9, 0xb8, - 0xc7, 0x65, 0xfa, 0x9b, 0xc4, 0x0a, 0x6d, 0xb3, 0xc5, 0x6f, 0x40, 0x92, 0x9f, 0x84, 0xca, 0x5d, - 0xda, 0x05, 0xb6, 0x66, 0xa5, 0x2f, 0xa7, 0x3c, 0x3c, 0x2f, 0x54, 0x88, 0xf2, 0xea, 0xa9, 0x9b, - 0xe9, 0xd5, 0xd3, 0x6f, 0xce, 0xab, 0x4b, 0x6f, 0xa4, 0xbc, 0x29, 0x75, 0xfd, 0xf5, 0x8d, 0x89, - 0x80, 0x68, 0x17, 0x7b, 0x13, 0x9c, 0xdd, 0xd4, 0x65, 0x05, 0x11, 0x6a, 0xe5, 0x22, 0x12, 0x14, - 0x63, 0xbe, 0xa4, 0x06, 0x7a, 0x88, 0xfa, 0x79, 0x73, 0x9b, 0x9b, 0x86, 0x5a, 0x4c, 0xa2, 0x47, - 0x66, 0xd4, 0x3e, 0xff, 0x52, 0x08, 0x84, 0x0d, 0xb7, 0x42, 0x81, 0x74, 0x9d, 0xbd, 0xfe, 0x04, - 0x3c, 0xbd, 0x28, 0x2a, 0xa4, 0x26, 0xa0, 0x7e, 0x1b, 0x83, 0x2e, 0x41, 0x0e, 0x5f, 0xa5, 0xb7, - 0x51, 0x59, 0xb2, 0xe9, 0xd6, 0x81, 0x8e, 0x18, 0x1b, 0x4e, 0x63, 0x86, 0x08, 0xf3, 0xfb, 0x07, - 0xb5, 0x0a, 0xe3, 0xb9, 0xcf, 0xec, 0xe8, 0x0e, 0xee, 0x74, 0x9d, 0x7d, 0x99, 0xa3, 0x48, 0x1f, - 0x49, 0x13, 0x7f, 0x18, 0xb0, 0x3f, 0x91, 0xe2, 0x15, 0x8b, 0x26, 0xed, 0x0b, 0x91, 0x92, 0x89, - 0xfc, 0x36, 0x80, 0x96, 0x6a, 0x2b, 0xd7, 0x54, 0xc3, 0xc1, 0x4d, 0x2e, 0xf7, 0x42, 0x4b, 0xb5, - 0x9f, 0xa1, 0x15, 0x24, 0xde, 0x24, 0x8f, 0x7b, 0x36, 0x6e, 0xd2, 0x09, 0xc8, 0xc8, 0x63, 0x2d, - 0xd5, 0xde, 0xb4, 0x71, 0xd3, 0x37, 0xd6, 0xb1, 0x9b, 0x31, 0xd6, 0xa0, 0xbc, 0xf3, 0x61, 0x79, - 0x7f, 0x2c, 0xed, 0xad, 0x0e, 0x2f, 0x7c, 0xf8, 0xc9, 0x94, 0xc5, 0x67, 0xe9, 0x9e, 0x22, 0xe8, - 0x04, 0xd0, 0xfb, 0x61, 0xd2, 0x5d, 0x95, 0x4a, 0x8f, 0xae, 0x56, 0xa1, 0x85, 0x87, 0x5b, 0xdc, - 0x95, 0xab, 0xc1, 0x6a, 0x1b, 0xfd, 0x1c, 0x1c, 0x0b, 0xd9, 0x20, 0xb7, 0x81, 0xf4, 0xa1, 0x4c, - 0xd1, 0x91, 0xa0, 0x29, 0x12, 0xf8, 0x9e, 0xf4, 0x32, 0x37, 0x65, 0xd5, 0xdc, 0x41, 0x42, 0x58, - 0xbf, 0x7b, 0x8b, 0xd2, 0x09, 0xe9, 0x4f, 0x52, 0x30, 0x11, 0xea, 0x20, 0x7a, 0x0f, 0x8c, 0x32, - 0x0f, 0x9c, 0x1a, 0x9a, 0x08, 0xa1, 0x12, 0xe7, 0x63, 0x62, 0x0c, 0x68, 0x1e, 0xf2, 0x98, 0x47, - 0xd7, 0x5c, 0x28, 0x77, 0xc6, 0x04, 0xe1, 0x9c, 0xdf, 0x65, 0x43, 0x8b, 0x50, 0x70, 0x45, 0x1f, - 0xb3, 0x73, 0x73, 0x67, 0x8e, 0x83, 0x78, 0x8c, 0xd2, 0x02, 0x14, 0x7d, 0xdd, 0x63, 0xef, 0x02, - 0xee, 0xf1, 0xed, 0x16, 0x0b, 0xa0, 0xf3, 0x1d, 0x75, 0x8f, 0xee, 0xb4, 0xd0, 0x31, 0x18, 0x23, - 0x0f, 0x5b, 0xfc, 0x65, 0xa9, 0x8c, 0x9c, 0xeb, 0xa8, 0x7b, 0x17, 0x54, 0x5b, 0xfa, 0x78, 0x0a, - 0xca, 0xc1, 0x7e, 0xa2, 0x7b, 0x01, 0x11, 0x5a, 0xb5, 0x85, 0x15, 0xa3, 0xd7, 0x61, 0x3e, 0x52, - 0x20, 0x4e, 0x74, 0xd4, 0xbd, 0xf9, 0x16, 0xbe, 0xd4, 0xeb, 0xd0, 0xa6, 0x6d, 0xb4, 0x0a, 0x15, - 0x41, 0x2c, 0x92, 0x5d, 0x5c, 0x2a, 0xc7, 0xfb, 0xbf, 0x57, 0xc3, 0x09, 0xd8, 0x5e, 0xf7, 0x65, - 0xb2, 0xd7, 0x2d, 0x33, 0x3c, 0xf1, 0x44, 0x7a, 0x08, 0x26, 0x42, 0x23, 0x46, 0x12, 0x8c, 0x77, - 0x7b, 0x5b, 0xca, 0x2e, 0xde, 0xa7, 0xaf, 0xbf, 0x33, 0x55, 0x2f, 0xc8, 0xc5, 0x6e, 0x6f, 0xeb, - 0x29, 0xbc, 0x4f, 0x73, 0x87, 0x92, 0x06, 0xe5, 0xe0, 0x66, 0x8a, 0x38, 0x0e, 0xcb, 0xec, 0x19, - 0x4d, 0xf1, 0x61, 0x03, 0x5a, 0x40, 0xe7, 0x60, 0xf4, 0xaa, 0xc9, 0xb4, 0x79, 0xd8, 0xee, 0xe9, - 0x8a, 0xe9, 0x60, 0xdf, 0x96, 0x8c, 0xf1, 0x48, 0x36, 0x8c, 0x52, 0xbd, 0x8c, 0x3c, 0xa8, 0xb8, - 0x02, 0xa0, 0x3a, 0x8e, 0xa5, 0x6f, 0xf5, 0x3c, 0xf8, 0x99, 0xb9, 0xfe, 0xb4, 0xfe, 0xdc, 0x9a, - 0xaa, 0x5b, 0x8d, 0x5b, 0xb9, 0x66, 0x4f, 0x7b, 0x3c, 0x3e, 0xed, 0xf6, 0x21, 0x49, 0xaf, 0x67, - 0x21, 0xc7, 0xb6, 0x9b, 0xe8, 0xf1, 0x60, 0xf2, 0xa3, 0x78, 0xf6, 0xc4, 0xa0, 0xee, 0x33, 0x2a, - 0xde, 0x7b, 0x37, 0x82, 0xba, 0x2b, 0x9c, 0x51, 0x68, 0x14, 0x5f, 0x3d, 0xa8, 0x8d, 0xd1, 0xe8, - 0x63, 0x79, 0xd1, 0x4b, 0x2f, 0x0c, 0xda, 0x5d, 0x8b, 0x5c, 0x46, 0xf6, 0xd0, 0xb9, 0x8c, 0x8b, - 0x30, 0xee, 0x0b, 0xb7, 0xf4, 0x26, 0xdf, 0xa7, 0x9c, 0x18, 0xb6, 0xe8, 0x96, 0x17, 0x79, 0xff, - 0x8b, 0x6e, 0x38, 0xb6, 0xdc, 0x44, 0xb3, 0xc1, 0x4d, 0x36, 0x8d, 0xda, 0x58, 0xb8, 0xe0, 0xdb, - 0x37, 0xd3, 0x77, 0xf2, 0x6f, 0x81, 0x02, 0x7d, 0xb1, 0x99, 0x92, 0xb0, 0xe8, 0x21, 0x4f, 0x2a, - 0xe8, 0xc3, 0xbb, 0x61, 0xc2, 0x0b, 0x6c, 0x18, 0x49, 0x9e, 0xa1, 0x78, 0xd5, 0x94, 0xf0, 0x01, - 0x98, 0x36, 0xf0, 0x9e, 0xa3, 0x84, 0xa9, 0x0b, 0x94, 0x1a, 0x91, 0x67, 0x57, 0x82, 0x1c, 0x77, - 0x42, 0xd9, 0x33, 0xa1, 0x94, 0x16, 0x58, 0xea, 0xc3, 0xad, 0xa5, 0x64, 0xc7, 0x21, 0xef, 0x86, - 0x9d, 0x45, 0x4a, 0x30, 0xa6, 0xb2, 0x68, 0xd3, 0x0d, 0x64, 0x2d, 0x6c, 0xf7, 0xda, 0x0e, 0x07, - 0x29, 0x51, 0x1a, 0x1a, 0xc8, 0xca, 0xac, 0x9e, 0xd2, 0x9e, 0x82, 0x71, 0x61, 0x55, 0x18, 0xdd, - 0x38, 0xa5, 0x2b, 0x89, 0x4a, 0x4a, 0x74, 0x1a, 0x2a, 0x5d, 0xcb, 0xec, 0x9a, 0x36, 0xb6, 0x14, - 0xb5, 0xd9, 0xb4, 0xb0, 0x6d, 0xcf, 0x94, 0x19, 0x9e, 0xa8, 0x9f, 0x67, 0xd5, 0xd2, 0xbb, 0x60, - 0x4c, 0xc4, 0xd3, 0xd3, 0x30, 0xda, 0x70, 0x2d, 0x64, 0x56, 0x66, 0x05, 0xe2, 0x5f, 0xe7, 0xbb, - 0x5d, 0x9e, 0x5d, 0x23, 0x3f, 0xa5, 0x36, 0x8c, 0xf1, 0x09, 0x8b, 0xcc, 0xa9, 0xac, 0x42, 0xa9, - 0xab, 0x5a, 0x64, 0x18, 0xfe, 0xcc, 0xca, 0xa0, 0x1d, 0xe1, 0x9a, 0x6a, 0x39, 0xeb, 0xd8, 0x09, - 0x24, 0x58, 0x8a, 0x94, 0x9f, 0x55, 0x49, 0x8f, 0xc2, 0x78, 0x80, 0x86, 0x74, 0xd3, 0x31, 0x1d, - 0xb5, 0x2d, 0x16, 0x3a, 0x2d, 0xb8, 0x3d, 0x49, 0x7b, 0x3d, 0x91, 0xce, 0x41, 0xc1, 0x9d, 0x2b, - 0xb2, 0xd1, 0x10, 0xa2, 0x48, 0x71, 0xf1, 0xb3, 0x22, 0x4d, 0x22, 0x99, 0xd7, 0xf8, 0x27, 0x9a, - 0x32, 0x32, 0x2b, 0x48, 0xd8, 0x67, 0x98, 0x98, 0x37, 0x43, 0x8f, 0xc1, 0x18, 0x37, 0x4c, 0x7c, - 0x3d, 0x0e, 0x4a, 0x17, 0xad, 0x51, 0x4b, 0x25, 0xd2, 0x45, 0xcc, 0x6e, 0x79, 0xcd, 0xa4, 0xfd, - 0xcd, 0x7c, 0x10, 0xf2, 0xc2, 0xf8, 0x04, 0xbd, 0x04, 0x6b, 0xe1, 0x64, 0x9c, 0x97, 0xe0, 0x8d, - 0x78, 0x8c, 0x44, 0x9b, 0x6c, 0xbd, 0x65, 0xe0, 0xa6, 0xe2, 0x2d, 0x41, 0xfe, 0xc2, 0xec, 0x04, - 0x7b, 0xb0, 0x22, 0xd6, 0x97, 0xf4, 0x00, 0xe4, 0x58, 0x5f, 0x23, 0x4d, 0x5c, 0x94, 0x6b, 0xfd, - 0x6e, 0x0a, 0xf2, 0xc2, 0x7d, 0x44, 0x32, 0x05, 0x06, 0x91, 0xbe, 0xd1, 0x41, 0xdc, 0x7c, 0x93, - 0x74, 0x1f, 0x20, 0xaa, 0x29, 0xca, 0x55, 0xd3, 0xd1, 0x8d, 0x96, 0xc2, 0xe6, 0x82, 0xbf, 0x37, - 0x48, 0x9f, 0x5c, 0xa1, 0x0f, 0xd6, 0x48, 0xfd, 0x3d, 0xa7, 0xa0, 0xe8, 0xcb, 0x72, 0xa1, 0x31, - 0xc8, 0x5c, 0xc2, 0xd7, 0x2a, 0x23, 0xa8, 0x08, 0x63, 0x32, 0xa6, 0x39, 0x82, 0x4a, 0xea, 0xec, - 0xeb, 0x63, 0x30, 0x31, 0xdf, 0x58, 0x58, 0x9e, 0xef, 0x76, 0xdb, 0x3a, 0x7f, 0x9f, 0xee, 0x32, - 0x64, 0xe9, 0x3e, 0x39, 0xc1, 0xf9, 0x4e, 0x35, 0x49, 0xc2, 0x09, 0xc9, 0x30, 0x4a, 0xb7, 0xd3, - 0x28, 0xc9, 0xb1, 0x4f, 0x35, 0x51, 0x1e, 0x8a, 0x74, 0x92, 0x2a, 0x5c, 0x82, 0xd3, 0xa0, 0x6a, - 0x92, 0xe4, 0x14, 0xfa, 0x39, 0x28, 0x78, 0xfb, 0xe4, 0xa4, 0x67, 0x44, 0xd5, 0xc4, 0x69, 0x2b, - 0x82, 0xef, 0xed, 0x0c, 0x92, 0x1e, 0x4d, 0x54, 0x13, 0xe7, 0x6b, 0xd0, 0xb3, 0x30, 0x26, 0xf6, - 0x60, 0xc9, 0x4e, 0x71, 0xaa, 0x09, 0x53, 0x4a, 0x64, 0xfa, 0xd8, 0xd6, 0x39, 0xc9, 0x51, 0x55, - 0x35, 0x51, 0xde, 0x0c, 0x6d, 0x42, 0x8e, 0x07, 0xbf, 0x89, 0x4e, 0x7a, 0xaa, 0xc9, 0x12, 0x45, - 0x44, 0xc8, 0x5e, 0x72, 0x22, 0xe9, 0xf1, 0x5c, 0x35, 0x71, 0xc2, 0x10, 0xa9, 0x00, 0xbe, 0xfd, - 0x74, 0xe2, 0x73, 0xb7, 0x6a, 0xf2, 0x44, 0x20, 0xfa, 0x00, 0xe4, 0xdd, 0x5d, 0x53, 0xc2, 0x93, - 0xb4, 0x6a, 0xd2, 0x5c, 0x5c, 0x63, 0x33, 0xf1, 0x2d, 0x89, 0x7b, 0x63, 0x6f, 0x49, 0x78, 0x87, - 0xdc, 0xee, 0x31, 0xf8, 0x5f, 0xa6, 0xe0, 0x78, 0xf8, 0x38, 0x59, 0x35, 0xf6, 0x07, 0x5c, 0x08, - 0x18, 0x70, 0x5b, 0xe4, 0x31, 0xc8, 0xcc, 0x1b, 0xfb, 0x24, 0xd8, 0xa0, 0xdf, 0xf6, 0xeb, 0x59, - 0x6d, 0x91, 0xa6, 0x23, 0xe5, 0x4d, 0xab, 0x1d, 0x7d, 0x6b, 0xa4, 0x9e, 0xfd, 0xc1, 0xe7, 0x6b, - 0x23, 0x8d, 0xdd, 0x88, 0x51, 0xc5, 0xdc, 0x15, 0xc8, 0xcf, 0x1b, 0xfb, 0xe2, 0x9a, 0xc0, 0x28, - 0x1d, 0xd0, 0x61, 0x8f, 0xff, 0x5f, 0x2b, 0x11, 0x64, 0xbb, 0x63, 0xda, 0x67, 0xd8, 0x1f, 0x3e, - 0xe2, 0x1c, 0x2b, 0x0d, 0x38, 0xe1, 0x8f, 0xbf, 0x31, 0x50, 0x1d, 0x2c, 0x4d, 0xe9, 0x02, 0x64, - 0x17, 0x4c, 0x9d, 0x86, 0x3c, 0x4d, 0x6c, 0x98, 0x1d, 0x91, 0xf3, 0xa4, 0x05, 0x74, 0x0a, 0x72, - 0x6a, 0xc7, 0xec, 0x19, 0x8e, 0x88, 0x9a, 0x89, 0x2b, 0xf9, 0xaf, 0x07, 0xb5, 0xcc, 0xb2, 0xe1, - 0xc8, 0xfc, 0x51, 0x3d, 0xfb, 0xbd, 0x57, 0x6a, 0x29, 0xe9, 0x49, 0x18, 0x5b, 0xc4, 0xda, 0x8d, - 0x60, 0x2d, 0x62, 0x2d, 0x84, 0x75, 0x1a, 0xf2, 0xcb, 0x86, 0xc3, 0x3e, 0x1a, 0x76, 0x1b, 0x64, - 0x74, 0x83, 0x1d, 0x8b, 0x84, 0xda, 0x27, 0xf5, 0x84, 0x74, 0x11, 0x6b, 0x2e, 0x69, 0x13, 0x6b, - 0x61, 0x52, 0x02, 0x4f, 0xea, 0xa5, 0x06, 0x94, 0xae, 0xa8, 0x6d, 0x1e, 0xee, 0x61, 0x1b, 0xdd, - 0x07, 0x05, 0x55, 0x14, 0xe8, 0xce, 0xaa, 0xd4, 0x28, 0xff, 0xf0, 0xa0, 0x06, 0x1e, 0x91, 0xec, - 0x11, 0xd4, 0xb3, 0x2f, 0xfd, 0xb7, 0x93, 0x29, 0xc9, 0x84, 0xb1, 0x0b, 0xaa, 0x4d, 0x2d, 0xfd, - 0x83, 0x81, 0x44, 0x0a, 0x8d, 0x14, 0x1b, 0x47, 0xae, 0x1f, 0xd4, 0x26, 0xf7, 0xd5, 0x4e, 0xbb, - 0x2e, 0x79, 0xcf, 0x24, 0x7f, 0x7e, 0x65, 0xce, 0x97, 0x5f, 0xa1, 0x91, 0x64, 0x63, 0xea, 0xfa, - 0x41, 0x6d, 0xc2, 0xe3, 0x21, 0x4f, 0x24, 0x37, 0xe9, 0x22, 0x75, 0x21, 0xc7, 0x82, 0xde, 0xc8, - 0x13, 0x42, 0x9e, 0xf2, 0x49, 0x7b, 0x29, 0x9f, 0xfa, 0xa1, 0xd2, 0x0c, 0x3c, 0x2e, 0x63, 0x1c, - 0xf5, 0xec, 0x47, 0x5f, 0xa9, 0x8d, 0x48, 0x16, 0xa0, 0x75, 0xbd, 0xd3, 0x6b, 0xb3, 0x17, 0xbf, - 0xc5, 0x51, 0xd3, 0x83, 0xac, 0xdf, 0x34, 0x9d, 0xc4, 0x02, 0xb2, 0x89, 0x39, 0xae, 0xa4, 0x5c, - 0x20, 0x2c, 0xce, 0xf8, 0xd6, 0x41, 0x2d, 0x45, 0x7b, 0x4f, 0x65, 0x74, 0x17, 0xe4, 0x58, 0x28, - 0xcf, 0xe3, 0x9f, 0xb2, 0xe0, 0x61, 0x63, 0x92, 0xf9, 0x53, 0xe9, 0x71, 0x18, 0x5b, 0xb5, 0x5b, - 0x8b, 0x64, 0x48, 0xc7, 0x21, 0xdf, 0xb1, 0x5b, 0x8a, 0x2f, 0x9a, 0x1a, 0xeb, 0xd8, 0xad, 0x8d, - 0x01, 0x51, 0x18, 0x9f, 0x96, 0x77, 0x43, 0x6e, 0x63, 0x8f, 0xb2, 0x9f, 0x72, 0xa5, 0x94, 0xf1, - 0xf7, 0x91, 0xa3, 0x07, 0x98, 0x3e, 0x94, 0x01, 0xd8, 0xd8, 0x73, 0x47, 0x38, 0xe0, 0x08, 0x0e, - 0x49, 0x90, 0x73, 0xf6, 0xdc, 0x88, 0xba, 0xd0, 0x80, 0x57, 0x0f, 0x6a, 0xb9, 0x8d, 0x3d, 0xb2, - 0xbd, 0x90, 0xf9, 0x93, 0x60, 0x2a, 0x2b, 0x13, 0x4a, 0x65, 0xb9, 0x09, 0xbc, 0x6c, 0x44, 0x02, - 0x6f, 0xd4, 0x77, 0x02, 0x70, 0x0c, 0xc6, 0x2c, 0xf5, 0x9a, 0x42, 0x66, 0x94, 0x7d, 0x85, 0x34, - 0x67, 0xa9, 0xd7, 0x56, 0xcc, 0x16, 0x5a, 0x80, 0x6c, 0xdb, 0x6c, 0x89, 0xbc, 0xdb, 0x51, 0x31, - 0x28, 0x12, 0x71, 0xf1, 0xdb, 0xc4, 0x2b, 0x66, 0xab, 0x71, 0x8c, 0xc8, 0xff, 0x4b, 0x7f, 0x56, - 0x9b, 0x08, 0xd6, 0xdb, 0x32, 0x65, 0x76, 0x93, 0x81, 0xf9, 0x81, 0xc9, 0xc0, 0xc2, 0xb0, 0x64, - 0x20, 0x04, 0x93, 0x81, 0x77, 0xd0, 0x33, 0x4d, 0x76, 0x86, 0x33, 0xdd, 0x17, 0x7c, 0xce, 0x1b, - 0xfb, 0xf4, 0x14, 0xf5, 0x56, 0x28, 0xb8, 0x17, 0x85, 0xf8, 0x67, 0x9f, 0xbd, 0x0a, 0xae, 0x6f, - 0x1f, 0x4d, 0x41, 0x39, 0xd8, 0x63, 0x9a, 0xcf, 0xb1, 0x5b, 0xfc, 0x83, 0xa9, 0x2c, 0xed, 0x49, - 0x94, 0x62, 0x59, 0x64, 0xca, 0x43, 0x3a, 0x3f, 0x1f, 0xd2, 0xf9, 0x29, 0x21, 0x20, 0xf6, 0xee, - 0x0e, 0x53, 0xf5, 0x69, 0x2e, 0x9d, 0x92, 0xaf, 0xd2, 0xf6, 0x54, 0x9f, 0x6a, 0xc4, 0xcf, 0x43, - 0xd1, 0xf7, 0x34, 0x32, 0xa8, 0x7f, 0x24, 0x22, 0xd9, 0x31, 0xe9, 0x4e, 0x88, 0x78, 0x22, 0x8e, - 0x10, 0x3c, 0x52, 0x57, 0x51, 0x0b, 0x2e, 0x51, 0xd2, 0xeb, 0x15, 0x8d, 0xc5, 0x3f, 0xfd, 0xce, - 0x89, 0x91, 0x97, 0x5e, 0x3d, 0x31, 0x32, 0xf0, 0x7e, 0xa6, 0xff, 0x22, 0x6b, 0xc0, 0x83, 0xdc, - 0x6f, 0x37, 0x77, 0x43, 0xde, 0xf5, 0x63, 0xef, 0x83, 0x5b, 0x39, 0x8d, 0xed, 0xa8, 0xbb, 0xba, - 0xd1, 0x12, 0x7f, 0xb9, 0xbb, 0x29, 0xf3, 0xd1, 0xf0, 0xda, 0x1b, 0x77, 0x3b, 0x6f, 0xf6, 0xd2, - 0x58, 0x35, 0xca, 0x1b, 0x4a, 0x07, 0x59, 0x40, 0xab, 0x76, 0x6b, 0xc1, 0xc2, 0xec, 0x63, 0x23, - 0x7c, 0x9f, 0x14, 0x7c, 0xd9, 0x87, 0xdb, 0xa8, 0x5b, 0xe6, 0x82, 0x63, 0x71, 0xbf, 0x1b, 0xed, - 0xe5, 0x88, 0x02, 0xaf, 0x08, 0x2d, 0x01, 0xd0, 0xf4, 0x8a, 0x6d, 0x7b, 0xc9, 0xbc, 0x5a, 0x18, - 0x63, 0xc1, 0xa5, 0x90, 0x55, 0x07, 0xdb, 0x62, 0xae, 0x3d, 0x46, 0xf4, 0x41, 0x98, 0xea, 0xe8, - 0x86, 0x62, 0xe3, 0xf6, 0xb6, 0xd2, 0xc4, 0x6d, 0xfa, 0x29, 0x16, 0x7e, 0x70, 0x57, 0x68, 0xac, - 0x70, 0xc7, 0x74, 0x57, 0xfc, 0x9c, 0xcd, 0x2d, 0x1b, 0xce, 0xf5, 0x83, 0x5a, 0x95, 0x79, 0x87, - 0x08, 0x48, 0x49, 0x9e, 0xec, 0xe8, 0xc6, 0x3a, 0x6e, 0x6f, 0x2f, 0xba, 0x75, 0xe8, 0x45, 0x98, - 0xe4, 0x14, 0xa6, 0x97, 0xf4, 0x20, 0xb6, 0xa7, 0xd4, 0x58, 0xbd, 0x7e, 0x50, 0x9b, 0x61, 0x68, - 0x7d, 0x24, 0xd2, 0x0f, 0x0f, 0x6a, 0xf7, 0x27, 0xe8, 0xd3, 0xbc, 0xa6, 0x09, 0xf7, 0x58, 0x71, - 0x41, 0x78, 0x0d, 0x69, 0xdb, 0x4b, 0xd0, 0x8b, 0xb6, 0x47, 0xc3, 0x6d, 0xf7, 0x91, 0x24, 0x6d, - 0xdb, 0xe7, 0x9a, 0xbd, 0x0c, 0xbe, 0x68, 0xfb, 0x28, 0xe4, 0xba, 0xbd, 0x2d, 0x71, 0x8a, 0x56, - 0x90, 0x79, 0x09, 0xcd, 0xfa, 0x0f, 0xd2, 0x8a, 0x67, 0x4b, 0x62, 0x3e, 0x49, 0xac, 0xe2, 0xa6, - 0x39, 0x59, 0xec, 0x47, 0xa3, 0x8f, 0xaf, 0x65, 0xa0, 0xb2, 0x6a, 0xb7, 0x96, 0x9a, 0xba, 0x73, - 0x93, 0xd5, 0xab, 0x1b, 0x25, 0x1d, 0xea, 0xcd, 0x1a, 0x0b, 0xd7, 0x0f, 0x6a, 0x65, 0x26, 0x9d, - 0x9b, 0x29, 0x93, 0x0e, 0x4c, 0x78, 0x7a, 0xa9, 0x58, 0xaa, 0xc3, 0xdd, 0x53, 0x63, 0x31, 0xa1, - 0x06, 0x2e, 0x62, 0xed, 0xfa, 0x41, 0xed, 0x28, 0xeb, 0x59, 0x08, 0x4a, 0x92, 0xcb, 0x5a, 0x60, - 0x2d, 0xa0, 0xbd, 0x68, 0xc5, 0xa7, 0xe7, 0x4f, 0x8d, 0x8b, 0x6f, 0xa1, 0xd2, 0xf3, 0xa9, 0xfb, - 0x6a, 0x1a, 0x8a, 0xc4, 0xd5, 0xb3, 0x7a, 0x1c, 0xbd, 0x14, 0x52, 0x3f, 0xc6, 0xa5, 0x90, 0x7e, - 0x7b, 0x96, 0xc2, 0x3d, 0x6e, 0xac, 0x9d, 0x19, 0xa8, 0xf3, 0xc1, 0x90, 0xfb, 0x3f, 0x66, 0xa8, - 0x55, 0xa5, 0x3b, 0x48, 0x19, 0x37, 0xdf, 0x09, 0x02, 0xfc, 0xc5, 0x14, 0x1c, 0xf1, 0xc4, 0x63, - 0x5b, 0x5a, 0x48, 0x8a, 0x4f, 0x5f, 0x3f, 0xa8, 0xdd, 0x1a, 0x96, 0xa2, 0x8f, 0xec, 0x06, 0x24, - 0x39, 0xe5, 0x02, 0xad, 0x5b, 0x5a, 0x74, 0x3f, 0x9a, 0xb6, 0xe3, 0xf6, 0x23, 0x33, 0xb8, 0x1f, - 0x3e, 0xb2, 0x37, 0xd5, 0x8f, 0x45, 0xdb, 0xe9, 0x9f, 0xd4, 0x6c, 0xc2, 0x49, 0xfd, 0x7a, 0x1a, - 0xc6, 0x57, 0xed, 0xd6, 0xa6, 0xd1, 0xfc, 0xe9, 0x82, 0x38, 0xec, 0x82, 0xf8, 0x78, 0x0a, 0xca, - 0x17, 0x75, 0xdb, 0x31, 0x2d, 0x5d, 0x53, 0xdb, 0x74, 0x37, 0xe3, 0xdd, 0x91, 0x4c, 0x1d, 0xfe, - 0x8e, 0xe4, 0x23, 0x90, 0xbb, 0xaa, 0xb6, 0x6d, 0xec, 0xf0, 0xa0, 0xf1, 0x78, 0xd8, 0x77, 0x84, - 0x73, 0xc0, 0x9c, 0x9c, 0x77, 0xe7, 0x77, 0xd3, 0x30, 0x11, 0x0a, 0x3c, 0x50, 0x03, 0xb2, 0xd4, - 0xa2, 0xb3, 0x0d, 0xef, 0xdc, 0x21, 0xe2, 0x0a, 0xb2, 0x27, 0xa6, 0xbc, 0xe8, 0x67, 0x20, 0xdf, - 0x51, 0xf7, 0x98, 0x67, 0x60, 0xfb, 0x9b, 0xf9, 0xc3, 0xe1, 0x78, 0xbb, 0x57, 0x81, 0x23, 0xc9, - 0x63, 0x1d, 0x75, 0x8f, 0xfa, 0x83, 0x2e, 0x4c, 0x90, 0x5a, 0x6d, 0x47, 0x35, 0x5a, 0xd8, 0xef, - 0x7e, 0x2e, 0x1e, 0xba, 0x91, 0xa3, 0x5e, 0x23, 0x3e, 0x38, 0x49, 0x1e, 0xef, 0xa8, 0x7b, 0x0b, - 0xb4, 0x82, 0xb4, 0x58, 0xcf, 0xbf, 0xfc, 0x4a, 0x6d, 0x84, 0x4a, 0xec, 0xdf, 0xa7, 0x00, 0x3c, - 0x89, 0xa1, 0x0d, 0xa8, 0x84, 0xdc, 0x97, 0xb8, 0x63, 0x14, 0x1b, 0xe0, 0x79, 0x1b, 0xdb, 0x09, - 0x2d, 0x34, 0x05, 0x1f, 0x80, 0x22, 0xbb, 0x25, 0xa0, 0xd0, 0x64, 0x7c, 0x3a, 0x36, 0x19, 0x7f, - 0x82, 0x60, 0x5d, 0x3f, 0xa8, 0x21, 0x36, 0x1c, 0x1f, 0xb3, 0x44, 0x53, 0xf4, 0xc0, 0x6a, 0x08, - 0x43, 0x70, 0x2c, 0x45, 0x5f, 0x6c, 0x41, 0xef, 0x9e, 0x99, 0x86, 0xbe, 0x8b, 0x2d, 0x77, 0x8f, - 0xcc, 0x8a, 0xa8, 0x0a, 0x79, 0xf6, 0x55, 0x41, 0x67, 0x5f, 0xfc, 0xbb, 0x0a, 0x51, 0x26, 0x5c, - 0xd7, 0xf0, 0x96, 0xad, 0x8b, 0x59, 0x90, 0x45, 0x11, 0x9d, 0x87, 0x8a, 0x8d, 0xb5, 0x9e, 0xa5, - 0x3b, 0xfb, 0x8a, 0x66, 0x1a, 0x8e, 0xaa, 0x39, 0xdc, 0x69, 0xdf, 0x72, 0xfd, 0xa0, 0x76, 0x8c, - 0xf5, 0x35, 0x4c, 0x21, 0xc9, 0x13, 0xa2, 0x6a, 0x81, 0xd5, 0x90, 0x16, 0x9a, 0xd8, 0x51, 0xf5, - 0xb6, 0xcd, 0x37, 0xb6, 0xa2, 0xe8, 0x1b, 0xcb, 0xef, 0x8c, 0xf9, 0x0f, 0xa3, 0xae, 0x41, 0xc5, - 0xec, 0x62, 0x2b, 0xc2, 0x1e, 0xad, 0x78, 0x2d, 0x87, 0x29, 0x6e, 0xc0, 0x24, 0x4c, 0x08, 0x0c, - 0x61, 0x11, 0xce, 0x07, 0xee, 0x9c, 0xb1, 0xb8, 0x31, 0x1d, 0x1e, 0x72, 0x98, 0x42, 0xf2, 0x5f, - 0x34, 0x63, 0xd1, 0xe5, 0x51, 0xc8, 0x3d, 0xaf, 0xea, 0x6d, 0xf1, 0xa9, 0x55, 0x99, 0x97, 0xd0, - 0x32, 0xe4, 0x6c, 0x47, 0x75, 0x7a, 0x2c, 0xf4, 0x1e, 0x6d, 0xbc, 0x2b, 0x61, 0x9f, 0x1b, 0xa6, - 0xd1, 0x5c, 0xa7, 0x8c, 0x32, 0x07, 0x40, 0xe7, 0x21, 0xe7, 0x98, 0xbb, 0xd8, 0xe0, 0x42, 0x3d, - 0xd4, 0x4a, 0xa7, 0x89, 0x3a, 0xc6, 0x8d, 0x1c, 0xf0, 0x8c, 0xb2, 0x62, 0xef, 0xa8, 0x16, 0xb6, - 0x59, 0xa8, 0xdc, 0x58, 0x3e, 0xf4, 0x72, 0x3c, 0x16, 0xf6, 0x14, 0x0c, 0x4f, 0x92, 0x27, 0xdc, - 0xaa, 0x75, 0x5a, 0x13, 0x8e, 0x9c, 0xc7, 0x6e, 0x28, 0x72, 0x3e, 0x0f, 0x95, 0x9e, 0xb1, 0x65, - 0x1a, 0xf4, 0xb3, 0x88, 0x3c, 0x4d, 0x93, 0x3f, 0x99, 0x9a, 0xcd, 0xf8, 0x67, 0x2b, 0x4c, 0x21, - 0xc9, 0x13, 0x6e, 0x15, 0xbf, 0xfd, 0xd8, 0x84, 0xb2, 0x47, 0x45, 0x97, 0x6c, 0x21, 0x76, 0xc9, - 0xde, 0xce, 0x97, 0xec, 0x91, 0x70, 0x2b, 0xde, 0xaa, 0x1d, 0x77, 0x2b, 0x09, 0x1b, 0x7a, 0x5f, - 0x60, 0x1b, 0x09, 0xbc, 0x85, 0x81, 0x56, 0x26, 0xf9, 0x0e, 0xb2, 0xf8, 0xb6, 0xec, 0x20, 0xeb, - 0xa5, 0x8f, 0xbe, 0x52, 0x1b, 0x71, 0x17, 0xec, 0x2f, 0xa5, 0x21, 0xb7, 0x78, 0x85, 0xbe, 0x46, - 0xf9, 0x13, 0x1a, 0x3e, 0xf8, 0xac, 0xd7, 0x7b, 0x61, 0x8c, 0xc9, 0xc2, 0x46, 0x67, 0x61, 0xb4, - 0x4b, 0x7e, 0xf0, 0x5c, 0xe3, 0xd1, 0x3e, 0x95, 0xa6, 0x74, 0x62, 0x87, 0x49, 0x49, 0xa5, 0x2f, - 0x64, 0x00, 0x16, 0xaf, 0x5c, 0xd9, 0xb0, 0xf4, 0x6e, 0x1b, 0x3b, 0x3f, 0x0d, 0xaf, 0xdf, 0x39, - 0xe1, 0xb5, 0x6f, 0x8e, 0x9f, 0x82, 0xa2, 0x37, 0x47, 0x36, 0x7a, 0x0c, 0xf2, 0x0e, 0xff, 0xcd, - 0xa7, 0xba, 0xda, 0x3f, 0xd5, 0x82, 0x9c, 0x4f, 0xb7, 0xcb, 0x21, 0xfd, 0x97, 0x34, 0x40, 0x5c, - 0x72, 0xe6, 0x27, 0x20, 0x00, 0x3f, 0x0f, 0x39, 0xee, 0x71, 0x32, 0x37, 0x14, 0xad, 0x72, 0x6e, - 0xdf, 0x2c, 0x7d, 0x27, 0x0d, 0x53, 0x9b, 0xc2, 0xec, 0xfe, 0x54, 0xc2, 0xe8, 0x22, 0x8c, 0x61, - 0xc3, 0xb1, 0x74, 0x2c, 0xd2, 0xe0, 0xb3, 0x61, 0x2d, 0x8d, 0x90, 0x16, 0xfd, 0x77, 0x09, 0xe2, - 0xb6, 0x1c, 0x67, 0xf7, 0xc9, 0xf8, 0x13, 0x19, 0x98, 0x19, 0xc4, 0x85, 0x16, 0x60, 0x42, 0xb3, - 0x30, 0xad, 0x50, 0xfc, 0x27, 0x27, 0x8d, 0xaa, 0x2f, 0x63, 0x14, 0x24, 0x90, 0xe4, 0xb2, 0xa8, - 0xe1, 0x0e, 0xb9, 0x45, 0x13, 0x54, 0x64, 0xa9, 0x10, 0xaa, 0x84, 0x41, 0xb4, 0xc4, 0x3d, 0xb2, - 0x97, 0x96, 0xf2, 0x03, 0x30, 0x97, 0x5c, 0xf6, 0x6a, 0xa9, 0x4f, 0x7e, 0x01, 0x26, 0x74, 0x43, - 0x77, 0x74, 0xb5, 0xad, 0x6c, 0xa9, 0x6d, 0xd5, 0xd0, 0x6e, 0x64, 0x2b, 0xc2, 0xbc, 0x29, 0x6f, - 0x36, 0x04, 0x27, 0xc9, 0x65, 0x5e, 0xd3, 0x60, 0x15, 0x64, 0x46, 0x44, 0x53, 0xd9, 0x1b, 0x0a, - 0xdc, 0x04, 0xbb, 0x6f, 0x46, 0x7e, 0x39, 0x03, 0x93, 0x6e, 0x7e, 0xe6, 0xa7, 0x53, 0x91, 0x74, - 0x2a, 0x56, 0x01, 0x98, 0x01, 0x21, 0x9e, 0xe3, 0x06, 0x66, 0x83, 0x98, 0xa0, 0x02, 0x43, 0x58, - 0xb4, 0x1d, 0xdf, 0x7c, 0xfc, 0x45, 0x06, 0x4a, 0xfe, 0xf9, 0xf8, 0xa9, 0x4b, 0x7f, 0x07, 0x65, - 0xcc, 0xe6, 0x3d, 0x93, 0x98, 0xe5, 0xdf, 0x45, 0x09, 0x99, 0xc4, 0xbe, 0xa5, 0x34, 0xd8, 0x16, - 0xfe, 0x55, 0x1a, 0x72, 0xfc, 0x5e, 0xb6, 0xd6, 0xb7, 0x8b, 0x48, 0xc5, 0xdd, 0xfb, 0x1e, 0xbe, - 0x89, 0x78, 0x39, 0x72, 0x13, 0x51, 0xee, 0xa8, 0x7b, 0x4a, 0xe0, 0x2d, 0xa6, 0xd4, 0xec, 0x78, - 0xe3, 0xb8, 0x87, 0x12, 0x7c, 0xce, 0x72, 0x21, 0xde, 0x9d, 0x5c, 0xf4, 0x08, 0x14, 0x09, 0x85, - 0xe7, 0x15, 0x08, 0xfb, 0x51, 0x2f, 0xf9, 0xe0, 0x7b, 0x28, 0xc9, 0xd0, 0x51, 0xf7, 0x96, 0x58, - 0x01, 0xad, 0x00, 0xda, 0x71, 0x53, 0x5f, 0x8a, 0x27, 0x42, 0xc2, 0x7f, 0xdb, 0xf5, 0x83, 0xda, - 0x71, 0xc6, 0xdf, 0x4f, 0x23, 0xc9, 0x93, 0x5e, 0xa5, 0x40, 0x7b, 0x10, 0x80, 0x8c, 0x4b, 0x61, - 0x77, 0x42, 0xd8, 0x16, 0xd6, 0x77, 0x51, 0xc2, 0x7b, 0x26, 0xc9, 0x05, 0x52, 0x58, 0x24, 0xbf, - 0x7d, 0x82, 0xff, 0x95, 0x14, 0x20, 0xcf, 0xf7, 0xb8, 0xe7, 0xf5, 0xef, 0xa3, 0xef, 0x25, 0x8a, - 0x9d, 0x51, 0x2a, 0x7a, 0x93, 0xe5, 0xf1, 0x89, 0x4d, 0x96, 0x6f, 0xa9, 0xde, 0xe7, 0xd9, 0xe7, - 0xf4, 0xc0, 0xac, 0x60, 0x84, 0x0d, 0xfe, 0xd7, 0x29, 0x38, 0xde, 0xa7, 0x38, 0x6e, 0xbf, 0xae, - 0x00, 0xb2, 0x7c, 0x0f, 0xf9, 0x7f, 0x28, 0x4a, 0xf1, 0xff, 0xf8, 0x97, 0x50, 0xff, 0x26, 0xad, - 0x3e, 0x1b, 0x7f, 0xf3, 0xbc, 0x09, 0xcf, 0x28, 0xa6, 0x60, 0xda, 0xdf, 0xbc, 0x3b, 0x80, 0xf3, - 0x50, 0xf2, 0xb7, 0xce, 0xbb, 0x7e, 0xeb, 0xb0, 0xae, 0xf3, 0x5e, 0x07, 0xf8, 0xd0, 0xb2, 0xb7, - 0xfa, 0xc4, 0x3f, 0x9d, 0x8c, 0x1b, 0xbd, 0x7b, 0x91, 0x2d, 0xb4, 0x0a, 0x59, 0x8f, 0xff, 0x5f, - 0x0a, 0xb2, 0x6b, 0xa6, 0xd9, 0x46, 0x26, 0x4c, 0x1a, 0xa6, 0xa3, 0x10, 0x65, 0xc1, 0x4d, 0x85, - 0xe7, 0x46, 0x58, 0x16, 0x74, 0xe1, 0x70, 0x42, 0xf9, 0xfe, 0x41, 0xad, 0x1f, 0x4a, 0x9e, 0x30, - 0x4c, 0xa7, 0x41, 0x6b, 0x36, 0x58, 0xe6, 0xe4, 0x83, 0x30, 0x1e, 0x6c, 0x8c, 0x65, 0x8a, 0x9e, - 0x39, 0x74, 0x63, 0x41, 0x98, 0xeb, 0x07, 0xb5, 0x69, 0x6f, 0x11, 0xb8, 0xd5, 0x92, 0x5c, 0xda, - 0xf2, 0xb5, 0x5e, 0xcf, 0x93, 0xd1, 0xff, 0xe0, 0x95, 0x5a, 0xaa, 0x71, 0x7e, 0xe0, 0x0d, 0x80, - 0xfb, 0x86, 0x76, 0x61, 0xcf, 0x3d, 0xea, 0x0f, 0xde, 0x05, 0xf8, 0x52, 0x1a, 0x6e, 0xe3, 0xd4, - 0xf4, 0xfd, 0xe3, 0x33, 0x5d, 0xb5, 0xa5, 0x1b, 0xfe, 0xcf, 0xef, 0x94, 0xf8, 0x94, 0xd1, 0xc7, - 0x92, 0x01, 0xc5, 0x35, 0xb5, 0x85, 0xc5, 0x87, 0x5c, 0xfa, 0xbf, 0xaa, 0x74, 0x14, 0x72, 0xe6, - 0xf6, 0x36, 0xcb, 0x72, 0xa7, 0x66, 0xb3, 0x32, 0x2f, 0xa1, 0x69, 0x18, 0x6d, 0xeb, 0x1d, 0xdd, - 0xe1, 0x2f, 0xaf, 0xb2, 0x02, 0xaa, 0x41, 0x51, 0x33, 0x7b, 0x86, 0xa3, 0xb0, 0x6b, 0xec, 0x59, - 0xf1, 0x4d, 0xdf, 0x9e, 0xe1, 0x6c, 0x90, 0x1a, 0xe9, 0x09, 0x28, 0xb1, 0xf6, 0xb8, 0x6a, 0x1e, - 0x87, 0x3c, 0x7d, 0x27, 0xc1, 0x6b, 0x75, 0x8c, 0x94, 0xf9, 0xa5, 0x72, 0x86, 0xc2, 0x1a, 0x66, - 0x85, 0x46, 0x63, 0xa0, 0xc0, 0x66, 0xe3, 0xe7, 0x8c, 0xc9, 0xc4, 0x15, 0xd6, 0xf7, 0xce, 0x40, - 0x35, 0x74, 0x71, 0x82, 0x12, 0x0c, 0xb8, 0x36, 0x31, 0x5c, 0xb0, 0x03, 0x6e, 0x55, 0x0c, 0xbd, - 0x99, 0x21, 0xed, 0xc2, 0x51, 0x7a, 0xef, 0xd5, 0xb3, 0xf1, 0x62, 0x26, 0x8e, 0xba, 0xd9, 0xc6, - 0x14, 0xff, 0xe7, 0xea, 0x2c, 0x75, 0xf8, 0x28, 0x80, 0xd7, 0xb2, 0xfb, 0x76, 0x92, 0x7f, 0x4e, - 0xe7, 0x7c, 0x13, 0x2a, 0xfb, 0x88, 0xa5, 0x5f, 0x4f, 0xc1, 0xb1, 0xbe, 0xd6, 0xf8, 0x3c, 0x3c, - 0x11, 0x78, 0xbb, 0x36, 0x95, 0xec, 0x40, 0xc3, 0xff, 0x99, 0x8c, 0x7a, 0x44, 0xbf, 0xaa, 0x51, - 0xfd, 0x62, 0x0d, 0x06, 0x3a, 0xf6, 0x02, 0x1c, 0x09, 0xf6, 0x4b, 0x08, 0xe1, 0x59, 0x28, 0x07, - 0xb7, 0x56, 0x3c, 0xee, 0x7a, 0xd7, 0xe1, 0xc3, 0x89, 0xf1, 0xc0, 0xf6, 0x4a, 0x7a, 0x26, 0x2c, - 0x78, 0x57, 0x12, 0xef, 0xed, 0x7f, 0x53, 0x21, 0x56, 0x10, 0xbe, 0x17, 0xd9, 0xbe, 0x9a, 0x82, - 0x93, 0x41, 0x64, 0xcf, 0x63, 0xd9, 0x6f, 0xf9, 0xb8, 0xde, 0x8c, 0x7a, 0xfc, 0xa7, 0x14, 0xdc, - 0x3e, 0xa4, 0xe7, 0x5c, 0x3c, 0x16, 0x4c, 0xfb, 0x5c, 0xa1, 0xc5, 0xab, 0x85, 0xca, 0x48, 0x83, - 0xdd, 0xb5, 0xeb, 0x09, 0x6e, 0xe1, 0xf7, 0xb6, 0xa6, 0xfa, 0x9f, 0xd9, 0xf2, 0x54, 0xbf, 0xfb, - 0x7a, 0x73, 0xba, 0xf5, 0x8d, 0x14, 0x9c, 0x0e, 0x8e, 0x2a, 0x62, 0xfb, 0xfb, 0xce, 0x9e, 0x98, - 0x7f, 0x93, 0x82, 0x7b, 0x92, 0x0c, 0x81, 0xcf, 0xd0, 0x73, 0x30, 0xe5, 0x05, 0xa3, 0xe1, 0x09, - 0x3a, 0x95, 0x20, 0x85, 0xc0, 0x95, 0x1a, 0xb9, 0x28, 0x37, 0x67, 0x26, 0xfe, 0x38, 0xc5, 0xd7, - 0x9c, 0x7f, 0xde, 0x5d, 0xb1, 0x07, 0xf7, 0x4f, 0x87, 0x14, 0xbb, 0x6f, 0x0f, 0x35, 0x1e, 0xd8, - 0x43, 0x45, 0x4c, 0x68, 0xfa, 0x26, 0x59, 0x90, 0x0f, 0x0b, 0x6b, 0x1a, 0x11, 0xc9, 0xee, 0xc2, - 0x54, 0xc4, 0x22, 0x71, 0x5f, 0xcf, 0x8d, 0x5f, 0x23, 0x47, 0x7f, 0x78, 0x50, 0x8b, 0x08, 0x91, - 0x65, 0xd4, 0xbf, 0x3c, 0xa4, 0xff, 0x9c, 0x82, 0x1a, 0xed, 0x48, 0xc4, 0x54, 0xfe, 0x4d, 0x16, - 0x30, 0xe6, 0x86, 0x34, 0x72, 0x58, 0x5c, 0xd0, 0xf3, 0x90, 0x63, 0x5a, 0xca, 0x65, 0x7b, 0x08, - 0xf5, 0xe6, 0x8c, 0x9e, 0xc1, 0x5e, 0x14, 0xe3, 0x8a, 0xb6, 0x0b, 0x6f, 0x91, 0xfc, 0xde, 0x84, - 0x5d, 0xf8, 0x57, 0xc2, 0x60, 0x47, 0xf7, 0x9c, 0x8b, 0xe8, 0x03, 0x6f, 0xda, 0x60, 0xf3, 0xcf, - 0x2e, 0xbd, 0x65, 0x96, 0xd9, 0xed, 0x7e, 0x8c, 0x65, 0x7e, 0xe7, 0xcd, 0x80, 0x6b, 0x99, 0x63, - 0x86, 0xf0, 0x0e, 0xb7, 0xcc, 0xd7, 0xd3, 0x70, 0x9c, 0x0e, 0xc3, 0xbf, 0x7d, 0x7b, 0x1b, 0x24, - 0xaf, 0x00, 0xb2, 0x2d, 0x4d, 0xb9, 0x59, 0xf6, 0xa3, 0x62, 0x5b, 0xda, 0x95, 0x80, 0xd3, 0x55, - 0x00, 0x35, 0x6d, 0x27, 0xdc, 0x40, 0xe6, 0x86, 0x1b, 0x68, 0xda, 0xce, 0x95, 0x21, 0x5e, 0x3d, - 0x7b, 0x18, 0xdd, 0xf9, 0xc3, 0x14, 0x54, 0xa3, 0x84, 0xce, 0x75, 0x45, 0x85, 0xa3, 0x81, 0xa4, - 0x43, 0x58, 0x5d, 0xee, 0x18, 0xb6, 0xf5, 0x0e, 0x2d, 0xdd, 0x23, 0x16, 0xbe, 0xd9, 0x8b, 0xf7, - 0x2b, 0xc2, 0xe9, 0xb8, 0x9a, 0xdf, 0xbf, 0x85, 0x79, 0x47, 0x2e, 0xd9, 0xdf, 0xea, 0x33, 0xf7, - 0xef, 0xb4, 0xdd, 0xd0, 0x9f, 0xa4, 0xe0, 0xc4, 0x80, 0x1e, 0xfe, 0x4d, 0x76, 0xe7, 0x3f, 0x3f, - 0x50, 0x61, 0x6e, 0xd6, 0xd6, 0xeb, 0x41, 0xbe, 0xa0, 0x82, 0x97, 0xfc, 0x7c, 0x1b, 0xea, 0xc8, - 0x0f, 0xf2, 0x3d, 0x0d, 0xb7, 0x44, 0x72, 0xf1, 0x3e, 0x9d, 0x85, 0xec, 0x8e, 0x6e, 0x3b, 0xee, - 0x57, 0x2a, 0x42, 0xdd, 0x09, 0x71, 0x51, 0x5a, 0x09, 0x41, 0x85, 0x42, 0xae, 0x99, 0x66, 0x9b, - 0x37, 0x2f, 0x2d, 0xc0, 0xa4, 0xaf, 0x8e, 0x83, 0xcf, 0x41, 0xb6, 0x6b, 0x9a, 0x6d, 0x0e, 0x3e, - 0x1d, 0x06, 0x27, 0xb4, 0x7c, 0x98, 0x94, 0x4e, 0x9a, 0x06, 0xc4, 0x40, 0xd8, 0xf7, 0x53, 0x38, - 0xf4, 0x47, 0x52, 0x30, 0x15, 0xa8, 0x76, 0xdf, 0xf0, 0xca, 0x05, 0x3e, 0xbd, 0xd5, 0x77, 0x9f, - 0x81, 0xd1, 0xbb, 0xef, 0xf2, 0xb3, 0x54, 0xf8, 0x9b, 0x50, 0xdd, 0xb3, 0x7f, 0x54, 0x12, 0xaf, - 0x04, 0x2b, 0x00, 0xbe, 0xbc, 0xf5, 0x5d, 0xe1, 0x96, 0xa3, 0x93, 0x1e, 0xd5, 0xbb, 0x63, 0xe9, - 0x78, 0xcc, 0x3b, 0x82, 0x7e, 0xc6, 0x7f, 0xe7, 0xec, 0xce, 0xe1, 0x7c, 0x02, 0xfe, 0xae, 0x38, - 0x32, 0x17, 0xfd, 0x6f, 0xc1, 0x74, 0xd4, 0x2e, 0x18, 0x3d, 0x30, 0x1c, 0xa1, 0x3f, 0x6e, 0xa9, - 0xbe, 0xeb, 0x10, 0x1c, 0x6e, 0xf3, 0x2f, 0xa7, 0xe0, 0xb6, 0xa1, 0x9b, 0x3d, 0xf4, 0xe8, 0x70, - 0xd8, 0x21, 0x91, 0x54, 0xb5, 0x7e, 0x23, 0xac, 0x6e, 0xd7, 0x94, 0xc0, 0xe5, 0x87, 0x68, 0x89, - 0xf6, 0xed, 0x3f, 0x06, 0x4c, 0x6c, 0x7f, 0xac, 0x29, 0x8d, 0xa0, 0x17, 0xa3, 0x2f, 0x01, 0x9c, - 0x89, 0x44, 0x18, 0xbc, 0xe5, 0xa9, 0x3e, 0x90, 0x9c, 0xc1, 0x3f, 0xed, 0x51, 0xb1, 0xf4, 0x80, - 0x69, 0x1f, 0xb2, 0x61, 0x18, 0x30, 0xed, 0xc3, 0x02, 0x75, 0x3e, 0xed, 0x43, 0x23, 0xc9, 0x01, - 0xd3, 0x9e, 0x24, 0x80, 0x1e, 0x30, 0xed, 0x89, 0x02, 0x57, 0x69, 0x04, 0xed, 0xc0, 0x78, 0x20, - 0x4e, 0x41, 0xa7, 0x23, 0xe1, 0xa2, 0x02, 0xc8, 0xea, 0x3d, 0x49, 0x48, 0xfd, 0xf3, 0x1f, 0xe1, - 0x9a, 0x07, 0xcc, 0xff, 0xe0, 0xe8, 0xa3, 0xfa, 0x40, 0x72, 0x06, 0xb7, 0xed, 0x6b, 0xee, 0xb9, - 0x94, 0x8f, 0x00, 0xcd, 0x25, 0x44, 0x12, 0x2d, 0x9f, 0x49, 0x4c, 0xef, 0x36, 0xbc, 0xdb, 0x77, - 0x35, 0x3d, 0x5a, 0x68, 0x91, 0xae, 0xad, 0x7a, 0x6f, 0x22, 0x5a, 0xb7, 0xb1, 0x55, 0x7e, 0xe8, - 0x72, 0x32, 0x92, 0xcd, 0xe7, 0xb4, 0xaa, 0xb7, 0x0f, 0xa1, 0x70, 0xe1, 0xd6, 0xdd, 0x53, 0x54, - 0x29, 0x9a, 0xdc, 0xef, 0xac, 0xaa, 0xa7, 0x86, 0xd2, 0x08, 0xd0, 0x9b, 0x7e, 0x2e, 0xf2, 0xe5, - 0x7c, 0xdf, 0x3b, 0x92, 0x2d, 0x6c, 0x60, 0x5b, 0xb7, 0x0f, 0xf5, 0x8e, 0xe4, 0xf0, 0x6c, 0xfe, - 0x87, 0x73, 0x50, 0xba, 0xc0, 0x50, 0xe9, 0x87, 0xa1, 0xd1, 0xe3, 0x09, 0x3d, 0x70, 0x99, 0x78, - 0xe0, 0x1f, 0x1e, 0xd4, 0xb8, 0x20, 0x5d, 0x5f, 0x6c, 0xf3, 0x2f, 0x44, 0xb1, 0xaf, 0xbb, 0x78, - 0x9f, 0xd8, 0x29, 0x1d, 0xea, 0x7e, 0x2f, 0xbb, 0x58, 0xc1, 0xaf, 0xd4, 0x86, 0xf1, 0x24, 0xf6, - 0xb1, 0x29, 0x7a, 0x3a, 0x43, 0xbf, 0x0f, 0x83, 0x3e, 0x95, 0x82, 0x23, 0x94, 0xca, 0x0b, 0x04, - 0x29, 0xa5, 0xb8, 0x85, 0xd4, 0x37, 0xcb, 0x2b, 0xaa, 0x6f, 0x5b, 0x44, 0x31, 0x1a, 0x75, 0x7e, - 0x38, 0x7e, 0xab, 0xaf, 0xd1, 0x30, 0x9c, 0xf4, 0xc3, 0x83, 0x1a, 0xea, 0xe7, 0x95, 0xe9, 0xd7, - 0x4c, 0x83, 0x75, 0xd1, 0xdf, 0xf4, 0x1e, 0x12, 0x1b, 0x4e, 0x72, 0x81, 0x7a, 0x31, 0x42, 0x20, - 0x3c, 0x5f, 0x83, 0xa2, 0xcf, 0xf8, 0xcc, 0x8c, 0x0e, 0xb8, 0x03, 0xe8, 0xed, 0xbb, 0x11, 0xc7, - 0xf3, 0xf9, 0x3e, 0xd9, 0x0f, 0x81, 0x7e, 0x2d, 0x05, 0x47, 0xbc, 0xbd, 0xbd, 0x1f, 0x3c, 0x97, - 0x7c, 0x77, 0x7f, 0x2e, 0x28, 0xb5, 0x48, 0x3c, 0x22, 0xb5, 0x28, 0x07, 0x29, 0x4f, 0xf7, 0xa2, - 0x1c, 0xc6, 0xb3, 0x30, 0xee, 0xdf, 0xfc, 0x79, 0x5f, 0x7a, 0x1c, 0x76, 0xf6, 0x3b, 0xcd, 0x47, - 0x1b, 0xb8, 0x07, 0x23, 0x07, 0x81, 0x50, 0x15, 0xf2, 0x78, 0xaf, 0x6b, 0x5a, 0x0e, 0x6e, 0xd2, - 0x8b, 0xdb, 0x79, 0xd9, 0x2d, 0x4b, 0xd7, 0x20, 0x62, 0x62, 0xd1, 0x53, 0xa1, 0xcf, 0x54, 0xdd, - 0xc8, 0xa6, 0xa2, 0xff, 0xcb, 0x56, 0xfe, 0x4f, 0x4e, 0xdd, 0x6c, 0xb3, 0xf1, 0xff, 0x03, 0x00, - 0x00, 0xff, 0xff, 0x93, 0x55, 0x11, 0xf3, 0xb7, 0x9b, 0x00, 0x00, + 0xe3, 0x1c, 0x1f, 0x38, 0x3e, 0x70, 0xd4, 0x89, 0xcf, 0x3d, 0x8a, 0x14, 0x16, 0xc0, 0xdd, 0x81, + 0x04, 0xee, 0xc0, 0x01, 0x70, 0xa4, 0x28, 0xdb, 0xe3, 0xc1, 0x6c, 0x63, 0x31, 0xc4, 0xee, 0xcc, + 0x72, 0x66, 0xf6, 0x0e, 0x60, 0x29, 0x55, 0x4c, 0xf9, 0x21, 0xc9, 0x91, 0x2d, 0x45, 0xb1, 0x1d, + 0x5a, 0x96, 0x64, 0x4a, 0xa9, 0x44, 0x8e, 0x92, 0xf8, 0x91, 0x28, 0x7a, 0xd8, 0xf9, 0x43, 0x55, + 0x79, 0x58, 0xa9, 0x72, 0xa5, 0xa4, 0xc4, 0x49, 0xb9, 0x52, 0x29, 0xd8, 0x22, 0x55, 0x65, 0x45, + 0x61, 0x12, 0xe5, 0x42, 0xbb, 0x5c, 0xd2, 0x1f, 0x49, 0xf5, 0x6b, 0x5e, 0x3b, 0xbb, 0x33, 0x38, + 0x1e, 0x29, 0xba, 0xa4, 0xbf, 0xb0, 0xd3, 0xf3, 0x7d, 0xbf, 0xee, 0xfe, 0xfa, 0xeb, 0xef, 0xfb, + 0xfa, 0xeb, 0xee, 0x01, 0x7c, 0x31, 0x0d, 0xb7, 0x69, 0xa6, 0xdd, 0x31, 0xed, 0x33, 0x2f, 0xf6, + 0xb0, 0xb5, 0x7f, 0xa6, 0xab, 0xb6, 0x74, 0x43, 0x75, 0x74, 0xd3, 0x98, 0xeb, 0x5a, 0xa6, 0x63, + 0xa2, 0x12, 0x7b, 0x3d, 0x47, 0x5f, 0x4b, 0x06, 0x14, 0xd7, 0xd4, 0x16, 0x96, 0xf1, 0x8b, 0x3d, + 0x6c, 0x3b, 0xa8, 0x02, 0x99, 0x5d, 0xbc, 0x3f, 0x93, 0x3a, 0x99, 0x9a, 0x2d, 0xc9, 0xe4, 0x27, + 0x3a, 0x0a, 0x39, 0x73, 0x7b, 0xdb, 0xc6, 0xce, 0x4c, 0xfa, 0x64, 0x6a, 0x36, 0x2b, 0xf3, 0x27, + 0x34, 0x0d, 0xa3, 0x6d, 0xbd, 0xa3, 0x3b, 0x33, 0x19, 0x5a, 0xcc, 0x1e, 0x50, 0x0d, 0x8a, 0x9a, + 0xd9, 0x33, 0x1c, 0xc5, 0x31, 0x1d, 0xb5, 0x3d, 0x93, 0x3d, 0x99, 0x9a, 0xcd, 0xcb, 0x40, 0x8b, + 0x36, 0x48, 0x89, 0xf4, 0x24, 0x94, 0x58, 0x7d, 0x76, 0xd7, 0x34, 0x6c, 0x8c, 0x8e, 0x43, 0xde, + 0xc0, 0x7b, 0x8e, 0xe2, 0xd5, 0x3a, 0x46, 0x9e, 0x9f, 0xc6, 0xfb, 0xa4, 0x06, 0x86, 0xc2, 0x2a, + 0x66, 0x0f, 0x8d, 0xc6, 0x37, 0x5e, 0x3b, 0x91, 0xfa, 0xe6, 0x6b, 0x27, 0x52, 0x7f, 0xfe, 0xda, + 0x89, 0xd4, 0x27, 0x5e, 0x3f, 0x31, 0xf2, 0xcd, 0xd7, 0x4f, 0x8c, 0xfc, 0xe9, 0xeb, 0x27, 0x46, + 0x9e, 0x9f, 0x6d, 0xe9, 0xce, 0x4e, 0x6f, 0x6b, 0x4e, 0x33, 0x3b, 0x67, 0xb8, 0x08, 0xd8, 0x9f, + 0xfb, 0xed, 0xe6, 0xee, 0x19, 0x67, 0xbf, 0x8b, 0xb9, 0x4c, 0xb6, 0x72, 0x54, 0x12, 0xef, 0x85, + 0xdf, 0x3c, 0x07, 0x27, 0x5b, 0xa6, 0xd9, 0x6a, 0xe3, 0x33, 0xb4, 0x64, 0xab, 0xb7, 0x7d, 0xa6, + 0x89, 0x6d, 0xcd, 0xd2, 0xbb, 0x8e, 0x69, 0x71, 0x79, 0x4d, 0x30, 0x8a, 0x39, 0x41, 0x21, 0xad, + 0xc2, 0xe4, 0x79, 0xbd, 0x8d, 0x17, 0x5d, 0xc2, 0x75, 0xec, 0xa0, 0x47, 0x21, 0xbb, 0xad, 0xb7, + 0xf1, 0x4c, 0xea, 0x64, 0x66, 0xb6, 0x78, 0xf6, 0x8e, 0xb9, 0x10, 0xd3, 0x5c, 0x90, 0x63, 0x8d, + 0x14, 0xcb, 0x94, 0x43, 0xfa, 0x4e, 0x16, 0xa6, 0x22, 0xde, 0x22, 0x04, 0x59, 0x43, 0xed, 0x60, + 0x2a, 0x95, 0x82, 0x4c, 0x7f, 0xa3, 0x19, 0x18, 0xeb, 0xaa, 0xda, 0xae, 0xda, 0xc2, 0x54, 0x28, + 0x05, 0x59, 0x3c, 0xa2, 0x13, 0x00, 0x4d, 0xdc, 0xc5, 0x46, 0x13, 0x1b, 0xda, 0xfe, 0x4c, 0xe6, + 0x64, 0x66, 0xb6, 0x20, 0xfb, 0x4a, 0xd0, 0xbd, 0x30, 0xd9, 0xed, 0x6d, 0xb5, 0x75, 0x4d, 0xf1, + 0x91, 0xc1, 0xc9, 0xcc, 0xec, 0xa8, 0x5c, 0x61, 0x2f, 0x16, 0x3d, 0xe2, 0xbb, 0x61, 0xe2, 0x1a, + 0x56, 0x77, 0xfd, 0xa4, 0x45, 0x4a, 0x5a, 0x26, 0xc5, 0x3e, 0xc2, 0x05, 0x28, 0x75, 0xb0, 0x6d, + 0xab, 0x2d, 0xac, 0x10, 0xf9, 0xce, 0x64, 0x69, 0xef, 0x4f, 0xf6, 0xf5, 0x3e, 0xdc, 0xf3, 0x22, + 0xe7, 0xda, 0xd8, 0xef, 0x62, 0x34, 0x0f, 0x05, 0x6c, 0xf4, 0x3a, 0x0c, 0x61, 0x74, 0x80, 0xfc, + 0x96, 0x8c, 0x5e, 0x27, 0x8c, 0x92, 0x27, 0x6c, 0x1c, 0x62, 0xcc, 0xc6, 0xd6, 0x55, 0x5d, 0xc3, + 0x33, 0x39, 0x0a, 0x70, 0x77, 0x1f, 0xc0, 0x3a, 0x7b, 0x1f, 0xc6, 0x10, 0x7c, 0x68, 0x01, 0x0a, + 0x78, 0xcf, 0xc1, 0x86, 0xad, 0x9b, 0xc6, 0xcc, 0x18, 0x05, 0xb9, 0x33, 0x62, 0x14, 0x71, 0xbb, + 0x19, 0x86, 0xf0, 0xf8, 0xd0, 0xc3, 0x30, 0x66, 0x76, 0xc9, 0x5c, 0xb3, 0x67, 0xf2, 0x27, 0x53, + 0xb3, 0xc5, 0xb3, 0xb7, 0x46, 0x2a, 0xc2, 0x65, 0x46, 0x23, 0x0b, 0x62, 0xb4, 0x0c, 0x15, 0xdb, + 0xec, 0x59, 0x1a, 0x56, 0x34, 0xb3, 0x89, 0x15, 0xdd, 0xd8, 0x36, 0x67, 0x0a, 0x14, 0xa0, 0xd6, + 0xdf, 0x11, 0x4a, 0xb8, 0x60, 0x36, 0xf1, 0xb2, 0xb1, 0x6d, 0xca, 0x65, 0x3b, 0xf0, 0x4c, 0xe6, + 0xab, 0xbd, 0x6f, 0x38, 0xea, 0xde, 0x4c, 0x89, 0x6a, 0x08, 0x7f, 0x92, 0xbe, 0x96, 0x83, 0x89, + 0x24, 0x2a, 0x76, 0x0e, 0x46, 0xb7, 0x49, 0x2f, 0x67, 0xd2, 0x87, 0x91, 0x01, 0xe3, 0x09, 0x0a, + 0x31, 0x77, 0x83, 0x42, 0x9c, 0x87, 0xa2, 0x81, 0x6d, 0x07, 0x37, 0x99, 0x46, 0x64, 0x12, 0xea, + 0x14, 0x30, 0xa6, 0x7e, 0x95, 0xca, 0xde, 0x90, 0x4a, 0x3d, 0x07, 0x13, 0x6e, 0x93, 0x14, 0x4b, + 0x35, 0x5a, 0x42, 0x37, 0xcf, 0xc4, 0xb5, 0x64, 0x6e, 0x49, 0xf0, 0xc9, 0x84, 0x4d, 0x2e, 0xe3, + 0xc0, 0x33, 0x5a, 0x04, 0x30, 0x0d, 0x6c, 0x6e, 0x2b, 0x4d, 0xac, 0xb5, 0x67, 0xf2, 0x03, 0xa4, + 0x74, 0x99, 0x90, 0xf4, 0x49, 0xc9, 0x64, 0xa5, 0x5a, 0x1b, 0x3d, 0xe6, 0xa9, 0xda, 0xd8, 0x00, + 0x4d, 0x59, 0x65, 0x93, 0xac, 0x4f, 0xdb, 0x36, 0xa1, 0x6c, 0x61, 0xa2, 0xf7, 0xb8, 0xc9, 0x7b, + 0x56, 0xa0, 0x8d, 0x98, 0x8b, 0xed, 0x99, 0xcc, 0xd9, 0x58, 0xc7, 0xc6, 0x2d, 0xff, 0x23, 0x3a, + 0x05, 0x6e, 0x81, 0x42, 0xd5, 0x0a, 0xa8, 0x15, 0x2a, 0x89, 0xc2, 0x4b, 0x6a, 0x07, 0x57, 0x5f, + 0x82, 0x72, 0x50, 0x3c, 0xc4, 0xcc, 0xdb, 0x8e, 0x6a, 0x39, 0x54, 0x0b, 0x47, 0x65, 0xf6, 0x40, + 0x1c, 0x11, 0x36, 0x9a, 0xd4, 0xca, 0x8d, 0xca, 0xe4, 0x27, 0x7a, 0xbf, 0xd7, 0xe1, 0x0c, 0xed, + 0xf0, 0x5d, 0xfd, 0x23, 0x1a, 0x40, 0x0e, 0xf7, 0xbb, 0xfa, 0x08, 0x8c, 0x07, 0x3a, 0x90, 0xb4, + 0x6a, 0xe9, 0x43, 0x70, 0x24, 0x12, 0x1a, 0x3d, 0x07, 0xd3, 0x3d, 0x43, 0x37, 0x1c, 0x6c, 0x75, + 0x2d, 0x4c, 0x34, 0x96, 0x55, 0x35, 0xf3, 0x17, 0x63, 0x03, 0x74, 0x6e, 0xd3, 0x4f, 0xcd, 0x50, + 0xe4, 0xa9, 0x5e, 0x7f, 0xe1, 0x3d, 0x85, 0xfc, 0x77, 0xc7, 0x2a, 0x2f, 0xbf, 0xfc, 0xf2, 0xcb, + 0x69, 0xe9, 0x95, 0x1c, 0x4c, 0x47, 0xcd, 0x99, 0xc8, 0xe9, 0x7b, 0x14, 0x72, 0x46, 0xaf, 0xb3, + 0x85, 0x2d, 0x2a, 0xa4, 0x51, 0x99, 0x3f, 0xa1, 0x79, 0x18, 0x6d, 0xab, 0x5b, 0x98, 0xb9, 0xe4, + 0xf2, 0xd9, 0x7b, 0x13, 0xcd, 0xca, 0xb9, 0x15, 0xc2, 0x22, 0x33, 0x4e, 0xf4, 0x04, 0x64, 0xb9, + 0x89, 0x26, 0x08, 0xf7, 0x24, 0x43, 0x20, 0x73, 0x49, 0xa6, 0x7c, 0xe8, 0x16, 0x28, 0x90, 0xbf, + 0x4c, 0x37, 0x72, 0xb4, 0xcd, 0x79, 0x52, 0x40, 0xf4, 0x02, 0x55, 0x21, 0x4f, 0xa7, 0x49, 0x13, + 0x0b, 0xd7, 0xe6, 0x3e, 0x13, 0xc5, 0x6a, 0xe2, 0x6d, 0xb5, 0xd7, 0x76, 0x94, 0xab, 0x6a, 0xbb, + 0x87, 0xa9, 0xc2, 0x17, 0xe4, 0x12, 0x2f, 0xbc, 0x42, 0xca, 0x48, 0xe4, 0xc1, 0x66, 0x95, 0x6e, + 0x34, 0xf1, 0x1e, 0xb5, 0x9e, 0xa3, 0x32, 0x9b, 0x68, 0xcb, 0xa4, 0x84, 0x54, 0xff, 0x82, 0x6d, + 0x1a, 0x42, 0x35, 0x69, 0x15, 0xa4, 0x80, 0x56, 0xff, 0x48, 0xd8, 0x70, 0xdf, 0x16, 0xdd, 0xbd, + 0xb0, 0x4e, 0x49, 0x5f, 0x4e, 0x43, 0x96, 0xda, 0x8b, 0x09, 0x28, 0x6e, 0x7c, 0x60, 0x6d, 0x49, + 0x59, 0xbc, 0xbc, 0xd9, 0x58, 0x59, 0xaa, 0xa4, 0x50, 0x19, 0x80, 0x16, 0x9c, 0x5f, 0xb9, 0x3c, + 0xbf, 0x51, 0x49, 0xbb, 0xcf, 0xcb, 0x97, 0x36, 0x1e, 0x7e, 0xb0, 0x92, 0x71, 0x19, 0x36, 0x59, + 0x41, 0xd6, 0x4f, 0xf0, 0xde, 0xb3, 0x95, 0x51, 0x54, 0x81, 0x12, 0x03, 0x58, 0x7e, 0x6e, 0x69, + 0xf1, 0xe1, 0x07, 0x2b, 0xb9, 0x60, 0xc9, 0x7b, 0xcf, 0x56, 0xc6, 0xd0, 0x38, 0x14, 0x68, 0x49, + 0xe3, 0xf2, 0xe5, 0x95, 0x4a, 0xde, 0xc5, 0x5c, 0xdf, 0x90, 0x97, 0x2f, 0x5d, 0xa8, 0x14, 0x5c, + 0xcc, 0x0b, 0xf2, 0xe5, 0xcd, 0xb5, 0x0a, 0xb8, 0x08, 0xab, 0x4b, 0xeb, 0xeb, 0xf3, 0x17, 0x96, + 0x2a, 0x45, 0x97, 0xa2, 0xf1, 0x81, 0x8d, 0xa5, 0xf5, 0x4a, 0x29, 0xd0, 0xac, 0xf7, 0x9e, 0xad, + 0x8c, 0xbb, 0x55, 0x2c, 0x5d, 0xda, 0x5c, 0xad, 0x94, 0xd1, 0x24, 0x8c, 0xb3, 0x2a, 0x44, 0x23, + 0x26, 0x42, 0x45, 0x0f, 0x3f, 0x58, 0xa9, 0x78, 0x0d, 0x61, 0x28, 0x93, 0x81, 0x82, 0x87, 0x1f, + 0xac, 0x20, 0x69, 0x01, 0x46, 0xa9, 0x76, 0x21, 0x04, 0xe5, 0x95, 0xf9, 0xc6, 0xd2, 0x8a, 0x72, + 0x79, 0x6d, 0x63, 0xf9, 0xf2, 0xa5, 0xf9, 0x95, 0x4a, 0xca, 0x2b, 0x93, 0x97, 0x9e, 0xd9, 0x5c, + 0x96, 0x97, 0x16, 0x2b, 0x69, 0x7f, 0xd9, 0xda, 0xd2, 0xfc, 0xc6, 0xd2, 0x62, 0x25, 0x23, 0x69, + 0x30, 0x1d, 0x65, 0x27, 0x23, 0x67, 0x86, 0x6f, 0x88, 0xd3, 0x03, 0x86, 0x98, 0x62, 0xf5, 0x0d, + 0xf1, 0xeb, 0x69, 0x98, 0x8a, 0xf0, 0x15, 0x91, 0x95, 0x3c, 0x09, 0xa3, 0x4c, 0x45, 0x99, 0xf7, + 0x3c, 0x1d, 0xe9, 0x74, 0xa8, 0xc2, 0xf6, 0x79, 0x50, 0xca, 0xe7, 0x8f, 0x20, 0x32, 0x03, 0x22, + 0x08, 0x02, 0xd1, 0x67, 0xd3, 0x7f, 0xba, 0xcf, 0xa6, 0x33, 0xb7, 0xf7, 0x70, 0x12, 0xb7, 0x47, + 0xcb, 0x0e, 0x67, 0xdb, 0x47, 0x23, 0x6c, 0xfb, 0x39, 0x98, 0xec, 0x03, 0x4a, 0x6c, 0x63, 0x7f, + 0x2e, 0x05, 0x33, 0x83, 0x84, 0x13, 0x63, 0xe9, 0xd2, 0x01, 0x4b, 0x77, 0x2e, 0x2c, 0xc1, 0xdb, + 0x07, 0x0f, 0x42, 0xdf, 0x58, 0x7f, 0x21, 0x05, 0x47, 0xa3, 0x23, 0xc5, 0xc8, 0x36, 0x3c, 0x01, + 0xb9, 0x0e, 0x76, 0x76, 0x4c, 0x11, 0x2d, 0xdd, 0x15, 0xe1, 0x83, 0xc9, 0xeb, 0xf0, 0x60, 0x73, + 0x2e, 0xbf, 0x13, 0xcf, 0x0c, 0x0a, 0xf7, 0x58, 0x6b, 0xfa, 0x5a, 0xfa, 0xd1, 0x34, 0x1c, 0x89, + 0x04, 0x8f, 0x6c, 0xe8, 0x6d, 0x00, 0xba, 0xd1, 0xed, 0x39, 0x2c, 0x22, 0x62, 0x06, 0xb6, 0x40, + 0x4b, 0xa8, 0xf1, 0x22, 0xc6, 0xb3, 0xe7, 0xb8, 0xef, 0x33, 0xf4, 0x3d, 0xb0, 0x22, 0x4a, 0xf0, + 0xa8, 0xd7, 0xd0, 0x2c, 0x6d, 0xe8, 0x89, 0x01, 0x3d, 0xed, 0x53, 0xcc, 0x07, 0xa0, 0xa2, 0xb5, + 0x75, 0x6c, 0x38, 0x8a, 0xed, 0x58, 0x58, 0xed, 0xe8, 0x46, 0x8b, 0x7a, 0x90, 0x7c, 0x7d, 0x74, + 0x5b, 0x6d, 0xdb, 0x58, 0x9e, 0x60, 0xaf, 0xd7, 0xc5, 0x5b, 0xc2, 0x41, 0x15, 0xc8, 0xf2, 0x71, + 0xe4, 0x02, 0x1c, 0xec, 0xb5, 0xcb, 0x21, 0x7d, 0xb2, 0x00, 0x45, 0x5f, 0x5c, 0x8d, 0x6e, 0x87, + 0xd2, 0x0b, 0xea, 0x55, 0x55, 0x11, 0x6b, 0x25, 0x26, 0x89, 0x22, 0x29, 0x5b, 0xe3, 0xeb, 0xa5, + 0x07, 0x60, 0x9a, 0x92, 0x98, 0x3d, 0x07, 0x5b, 0x8a, 0xd6, 0x56, 0x6d, 0x9b, 0x0a, 0x2d, 0x4f, + 0x49, 0x11, 0x79, 0x77, 0x99, 0xbc, 0x5a, 0x10, 0x6f, 0xd0, 0x43, 0x30, 0x45, 0x39, 0x3a, 0xbd, + 0xb6, 0xa3, 0x77, 0xdb, 0x58, 0x21, 0xab, 0x37, 0x9b, 0x7a, 0x12, 0xb7, 0x65, 0x93, 0x84, 0x62, + 0x95, 0x13, 0x90, 0x16, 0xd9, 0x68, 0x11, 0x6e, 0xa3, 0x6c, 0x2d, 0x6c, 0x60, 0x4b, 0x75, 0xb0, + 0x82, 0x5f, 0xec, 0xa9, 0x6d, 0x5b, 0x51, 0x8d, 0xa6, 0xb2, 0xa3, 0xda, 0x3b, 0x33, 0xd3, 0x04, + 0xa0, 0x91, 0x9e, 0x49, 0xc9, 0xc7, 0x09, 0xe1, 0x05, 0x4e, 0xb7, 0x44, 0xc9, 0xe6, 0x8d, 0xe6, + 0x45, 0xd5, 0xde, 0x41, 0x75, 0x38, 0x4a, 0x51, 0x6c, 0xc7, 0xd2, 0x8d, 0x96, 0xa2, 0xed, 0x60, + 0x6d, 0x57, 0xe9, 0x39, 0xdb, 0x8f, 0xce, 0xdc, 0xe2, 0xaf, 0x9f, 0xb6, 0x70, 0x9d, 0xd2, 0x2c, + 0x10, 0x92, 0x4d, 0x67, 0xfb, 0x51, 0xb4, 0x0e, 0x25, 0x32, 0x18, 0x1d, 0xfd, 0x25, 0xac, 0x6c, + 0x9b, 0x16, 0x75, 0x8d, 0xe5, 0x08, 0xd3, 0xe4, 0x93, 0xe0, 0xdc, 0x65, 0xce, 0xb0, 0x6a, 0x36, + 0x71, 0x7d, 0x74, 0x7d, 0x6d, 0x69, 0x69, 0x51, 0x2e, 0x0a, 0x94, 0xf3, 0xa6, 0x45, 0x14, 0xaa, + 0x65, 0xba, 0x02, 0x2e, 0x32, 0x85, 0x6a, 0x99, 0x42, 0xbc, 0x0f, 0xc1, 0x94, 0xa6, 0xb1, 0x3e, + 0xeb, 0x9a, 0xc2, 0xd7, 0x58, 0xf6, 0x4c, 0x25, 0x20, 0x2c, 0x4d, 0xbb, 0xc0, 0x08, 0xb8, 0x8e, + 0xdb, 0xe8, 0x31, 0x38, 0xe2, 0x09, 0xcb, 0xcf, 0x38, 0xd9, 0xd7, 0xcb, 0x30, 0xeb, 0x43, 0x30, + 0xd5, 0xdd, 0xef, 0x67, 0x44, 0x81, 0x1a, 0xbb, 0xfb, 0x61, 0xb6, 0x47, 0x60, 0xba, 0xbb, 0xd3, + 0xed, 0xe7, 0xbb, 0xc7, 0xcf, 0x87, 0xba, 0x3b, 0xdd, 0x30, 0xe3, 0x9d, 0x74, 0xc1, 0x6d, 0x61, + 0x4d, 0x75, 0x70, 0x73, 0xe6, 0x98, 0x9f, 0xdc, 0xf7, 0x02, 0x9d, 0x81, 0x8a, 0xa6, 0x29, 0xd8, + 0x50, 0xb7, 0xda, 0x58, 0x51, 0x2d, 0x6c, 0xa8, 0xf6, 0x4c, 0xcd, 0x4f, 0x5c, 0xd6, 0xb4, 0x25, + 0xfa, 0x76, 0x9e, 0xbe, 0x44, 0xf7, 0xc0, 0xa4, 0xb9, 0xf5, 0x82, 0xc6, 0x54, 0x52, 0xe9, 0x5a, + 0x78, 0x5b, 0xdf, 0x9b, 0xb9, 0x83, 0xca, 0x77, 0x82, 0xbc, 0xa0, 0x0a, 0xb9, 0x46, 0x8b, 0xd1, + 0x69, 0xa8, 0x68, 0xf6, 0x8e, 0x6a, 0x75, 0xa9, 0x4d, 0xb6, 0xbb, 0xaa, 0x86, 0x67, 0xee, 0x64, + 0xa4, 0xac, 0xfc, 0x92, 0x28, 0x26, 0x53, 0xc2, 0xbe, 0xa6, 0x6f, 0x3b, 0x02, 0xf1, 0x6e, 0x36, + 0x25, 0x68, 0x19, 0x47, 0x9b, 0x85, 0x0a, 0x11, 0x45, 0xa0, 0xe2, 0x59, 0x4a, 0x56, 0xee, 0xee, + 0x74, 0xfd, 0xf5, 0x9e, 0x82, 0x71, 0x42, 0xe9, 0x55, 0x7a, 0x9a, 0x05, 0x64, 0xdd, 0x1d, 0x5f, + 0x8d, 0x0f, 0xc2, 0x51, 0x42, 0xd4, 0xc1, 0x8e, 0xda, 0x54, 0x1d, 0xd5, 0x47, 0x7d, 0x1f, 0xa5, + 0x26, 0x72, 0x5f, 0xe5, 0x2f, 0x03, 0xed, 0xb4, 0x7a, 0x5b, 0xfb, 0xae, 0x66, 0xdd, 0xcf, 0xda, + 0x49, 0xca, 0x84, 0x6e, 0xbd, 0x6d, 0x41, 0xb7, 0x54, 0x87, 0x92, 0x5f, 0xf1, 0x51, 0x01, 0x98, + 0xea, 0x57, 0x52, 0x24, 0x0a, 0x5a, 0xb8, 0xbc, 0x48, 0xe2, 0x97, 0xe7, 0x97, 0x2a, 0x69, 0x12, + 0x47, 0xad, 0x2c, 0x6f, 0x2c, 0x29, 0xf2, 0xe6, 0xa5, 0x8d, 0xe5, 0xd5, 0xa5, 0x4a, 0xc6, 0x17, + 0xb0, 0x3f, 0x95, 0xcd, 0xdf, 0x55, 0xb9, 0x5b, 0xfa, 0x56, 0x1a, 0xca, 0xc1, 0x15, 0x18, 0x7a, + 0x1c, 0x8e, 0x89, 0x74, 0x89, 0x8d, 0x1d, 0xe5, 0x9a, 0x6e, 0xd1, 0x19, 0xd9, 0x51, 0x99, 0x77, + 0x74, 0x75, 0x62, 0x9a, 0x53, 0xad, 0x63, 0xe7, 0x59, 0xdd, 0x22, 0xf3, 0xad, 0xa3, 0x3a, 0x68, + 0x05, 0x6a, 0x86, 0xa9, 0xd8, 0x8e, 0x6a, 0x34, 0x55, 0xab, 0xa9, 0x78, 0x89, 0x2a, 0x45, 0xd5, + 0x34, 0x6c, 0xdb, 0x26, 0xf3, 0x84, 0x2e, 0xca, 0xad, 0x86, 0xb9, 0xce, 0x89, 0x3d, 0x17, 0x31, + 0xcf, 0x49, 0x43, 0xfa, 0x9b, 0x19, 0xa4, 0xbf, 0xb7, 0x40, 0xa1, 0xa3, 0x76, 0x15, 0x6c, 0x38, + 0xd6, 0x3e, 0x8d, 0xbb, 0xf3, 0x72, 0xbe, 0xa3, 0x76, 0x97, 0xc8, 0xf3, 0x3b, 0xb2, 0xfc, 0x79, + 0x2a, 0x9b, 0xcf, 0x57, 0x0a, 0x4f, 0x65, 0xf3, 0x85, 0x0a, 0x48, 0xaf, 0x65, 0xa0, 0xe4, 0x8f, + 0xc3, 0xc9, 0xb2, 0x46, 0xa3, 0x2e, 0x2b, 0x45, 0x8d, 0xda, 0xa9, 0xa1, 0x51, 0xfb, 0xdc, 0x02, + 0xf1, 0x65, 0xf5, 0x1c, 0x8b, 0x8e, 0x65, 0xc6, 0x49, 0xe2, 0x08, 0xa2, 0x6c, 0x98, 0x45, 0x23, + 0x79, 0x99, 0x3f, 0xa1, 0x0b, 0x90, 0x7b, 0xc1, 0xa6, 0xd8, 0x39, 0x8a, 0x7d, 0xc7, 0x70, 0xec, + 0xa7, 0xd6, 0x29, 0x78, 0xe1, 0xa9, 0x75, 0xe5, 0xd2, 0x65, 0x79, 0x75, 0x7e, 0x45, 0xe6, 0xec, + 0xe8, 0x38, 0x64, 0xdb, 0xea, 0x4b, 0xfb, 0x41, 0xaf, 0x47, 0x8b, 0x92, 0x0e, 0xc2, 0x71, 0xc8, + 0x5e, 0xc3, 0xea, 0x6e, 0xd0, 0xd7, 0xd0, 0xa2, 0xb7, 0x71, 0x32, 0x9c, 0x81, 0x51, 0x2a, 0x2f, + 0x04, 0xc0, 0x25, 0x56, 0x19, 0x41, 0x79, 0xc8, 0x2e, 0x5c, 0x96, 0xc9, 0x84, 0xa8, 0x40, 0x89, + 0x95, 0x2a, 0x6b, 0xcb, 0x4b, 0x0b, 0x4b, 0x95, 0xb4, 0xf4, 0x10, 0xe4, 0x98, 0x10, 0xc8, 0x64, + 0x71, 0xc5, 0x50, 0x19, 0xe1, 0x8f, 0x1c, 0x23, 0x25, 0xde, 0x6e, 0xae, 0x36, 0x96, 0xe4, 0x4a, + 0x3a, 0x38, 0xd4, 0xd9, 0xca, 0xa8, 0x64, 0x43, 0xc9, 0x1f, 0x88, 0xbf, 0x33, 0x8b, 0xec, 0xaf, + 0xa7, 0xa0, 0xe8, 0x0b, 0xac, 0x49, 0x44, 0xa4, 0xb6, 0xdb, 0xe6, 0x35, 0x45, 0x6d, 0xeb, 0xaa, + 0xcd, 0x55, 0x03, 0x68, 0xd1, 0x3c, 0x29, 0x49, 0x3a, 0x74, 0xef, 0xd0, 0x14, 0x19, 0xad, 0xe4, + 0xa4, 0xcf, 0xa6, 0xa0, 0x12, 0x8e, 0x6c, 0x43, 0xcd, 0x4c, 0xfd, 0x28, 0x9b, 0x29, 0x7d, 0x3a, + 0x05, 0xe5, 0x60, 0x38, 0x1b, 0x6a, 0xde, 0xed, 0x3f, 0xd2, 0xe6, 0xfd, 0x79, 0x1a, 0xc6, 0x03, + 0x41, 0x6c, 0xd2, 0xd6, 0xbd, 0x08, 0x93, 0x7a, 0x13, 0x77, 0xba, 0xa6, 0x83, 0x0d, 0x6d, 0x5f, + 0x69, 0xe3, 0xab, 0xb8, 0x3d, 0x23, 0x51, 0xa3, 0x71, 0x66, 0x78, 0x98, 0x3c, 0xb7, 0xec, 0xf1, + 0xad, 0x10, 0xb6, 0xfa, 0xd4, 0xf2, 0xe2, 0xd2, 0xea, 0xda, 0xe5, 0x8d, 0xa5, 0x4b, 0x0b, 0x1f, + 0x50, 0x36, 0x2f, 0x3d, 0x7d, 0xe9, 0xf2, 0xb3, 0x97, 0xe4, 0x8a, 0x1e, 0x22, 0x7b, 0x1b, 0xa7, + 0xfd, 0x1a, 0x54, 0xc2, 0x8d, 0x42, 0xc7, 0x20, 0xaa, 0x59, 0x95, 0x11, 0x34, 0x05, 0x13, 0x97, + 0x2e, 0x2b, 0xeb, 0xcb, 0x8b, 0x4b, 0xca, 0xd2, 0xf9, 0xf3, 0x4b, 0x0b, 0x1b, 0xeb, 0x2c, 0xf1, + 0xe1, 0x52, 0x6f, 0x04, 0x26, 0xb8, 0xf4, 0xa9, 0x0c, 0x4c, 0x45, 0xb4, 0x04, 0xcd, 0xf3, 0x25, + 0x0b, 0x5b, 0x45, 0xdd, 0x9f, 0xa4, 0xf5, 0x73, 0x24, 0x66, 0x58, 0x53, 0x2d, 0x87, 0xaf, 0x70, + 0x4e, 0x03, 0x91, 0x92, 0xe1, 0xe8, 0xdb, 0x3a, 0xb6, 0x78, 0x9e, 0x88, 0xad, 0x63, 0x26, 0xbc, + 0x72, 0x96, 0x2a, 0xba, 0x0f, 0x50, 0xd7, 0xb4, 0x75, 0x47, 0xbf, 0x8a, 0x15, 0xdd, 0x10, 0x49, + 0xa5, 0x2c, 0xdd, 0x65, 0xaa, 0x88, 0x37, 0xcb, 0x86, 0xe3, 0x52, 0x1b, 0xb8, 0xa5, 0x86, 0xa8, + 0x89, 0x31, 0xcf, 0xc8, 0x15, 0xf1, 0xc6, 0xa5, 0xbe, 0x1d, 0x4a, 0x4d, 0xb3, 0x47, 0x82, 0x3d, + 0x46, 0x47, 0x7c, 0x47, 0x4a, 0x2e, 0xb2, 0x32, 0x97, 0x84, 0x87, 0xf1, 0x5e, 0x36, 0xab, 0x24, + 0x17, 0x59, 0x19, 0x23, 0xb9, 0x1b, 0x26, 0xd4, 0x56, 0xcb, 0x22, 0xe0, 0x02, 0x88, 0x2d, 0x4c, + 0xca, 0x6e, 0x31, 0x25, 0xac, 0x3e, 0x05, 0x79, 0x21, 0x07, 0xe2, 0xaa, 0x89, 0x24, 0x94, 0x2e, + 0x5b, 0x6d, 0xa7, 0x67, 0x0b, 0x72, 0xde, 0x10, 0x2f, 0x6f, 0x87, 0x92, 0x6e, 0x2b, 0x5e, 0x72, + 0x3e, 0x7d, 0x32, 0x3d, 0x9b, 0x97, 0x8b, 0xba, 0xed, 0x26, 0x36, 0xa5, 0x2f, 0xa4, 0xa1, 0x1c, + 0xdc, 0x5c, 0x40, 0x8b, 0x90, 0x6f, 0x9b, 0x1a, 0xdd, 0x3d, 0xe4, 0x3b, 0x5b, 0xb3, 0x31, 0xfb, + 0x11, 0x73, 0x2b, 0x9c, 0x5e, 0x76, 0x39, 0xab, 0xff, 0x21, 0x05, 0x79, 0x51, 0x8c, 0x8e, 0x42, + 0xb6, 0xab, 0x3a, 0x3b, 0x14, 0x6e, 0xb4, 0x91, 0xae, 0xa4, 0x64, 0xfa, 0x4c, 0xca, 0xed, 0xae, + 0x6a, 0x50, 0x15, 0xe0, 0xe5, 0xe4, 0x99, 0x8c, 0x6b, 0x1b, 0xab, 0x4d, 0xba, 0xea, 0x31, 0x3b, + 0x1d, 0x6c, 0x38, 0xb6, 0x18, 0x57, 0x5e, 0xbe, 0xc0, 0x8b, 0xd1, 0xbd, 0x30, 0xe9, 0x58, 0xaa, + 0xde, 0x0e, 0xd0, 0x66, 0x29, 0x6d, 0x45, 0xbc, 0x70, 0x89, 0xeb, 0x70, 0x5c, 0xe0, 0x36, 0xb1, + 0xa3, 0x6a, 0x3b, 0xb8, 0xe9, 0x31, 0xe5, 0x68, 0x76, 0xe3, 0x18, 0x27, 0x58, 0xe4, 0xef, 0x05, + 0xaf, 0xf4, 0xad, 0x14, 0x4c, 0x8a, 0x75, 0x5a, 0xd3, 0x15, 0xd6, 0x2a, 0x80, 0x6a, 0x18, 0xa6, + 0xe3, 0x17, 0x57, 0xbf, 0x2a, 0xf7, 0xf1, 0xcd, 0xcd, 0xbb, 0x4c, 0xb2, 0x0f, 0xa0, 0xda, 0x01, + 0xf0, 0xde, 0x0c, 0x14, 0x5b, 0x0d, 0x8a, 0x7c, 0xe7, 0x88, 0x6e, 0x3f, 0xb2, 0x95, 0x3d, 0xb0, + 0x22, 0xb2, 0xa0, 0x43, 0xd3, 0x30, 0xba, 0x85, 0x5b, 0xba, 0xc1, 0xf3, 0xc1, 0xec, 0x41, 0xe4, + 0x5f, 0xb2, 0x6e, 0xfe, 0xa5, 0xf1, 0xf1, 0x14, 0x4c, 0x69, 0x66, 0x27, 0xdc, 0xde, 0x46, 0x25, + 0x94, 0x5e, 0xb0, 0x2f, 0xa6, 0x9e, 0x7f, 0xc2, 0xb7, 0xd3, 0xda, 0x32, 0xdb, 0xaa, 0xd1, 0xf2, + 0xf6, 0x4f, 0xe9, 0x0f, 0xed, 0xfe, 0x16, 0x36, 0xee, 0x6f, 0x99, 0xbe, 0xdd, 0xd4, 0x73, 0xde, + 0xcf, 0xbf, 0x4e, 0xa5, 0x3e, 0x9f, 0xce, 0x5c, 0x58, 0x6b, 0x7c, 0x31, 0x5d, 0xbd, 0xc0, 0xaa, + 0x5b, 0x13, 0xe2, 0x91, 0xf1, 0x76, 0x1b, 0x6b, 0xa4, 0xcb, 0xf0, 0xbd, 0x7b, 0x61, 0xba, 0x65, + 0xb6, 0x4c, 0x8a, 0x78, 0x86, 0xfc, 0xe2, 0x3b, 0xb2, 0x05, 0xb7, 0xb4, 0x1a, 0xbb, 0x7d, 0x5b, + 0xbf, 0x04, 0x53, 0x9c, 0x58, 0xa1, 0x5b, 0x42, 0x6c, 0x61, 0x83, 0x86, 0xa6, 0xd5, 0x66, 0x7e, + 0xff, 0x3b, 0xd4, 0xa1, 0xcb, 0x93, 0x9c, 0x95, 0xbc, 0x63, 0x6b, 0x9f, 0xba, 0x0c, 0x47, 0x02, + 0x78, 0x6c, 0xda, 0x62, 0x2b, 0x06, 0xf1, 0xdf, 0x72, 0xc4, 0x29, 0x1f, 0xe2, 0x3a, 0x67, 0xad, + 0x2f, 0xc0, 0xf8, 0x61, 0xb0, 0xfe, 0x1d, 0xc7, 0x2a, 0x61, 0x3f, 0xc8, 0x05, 0x98, 0xa0, 0x20, + 0x5a, 0xcf, 0x76, 0xcc, 0x0e, 0xb5, 0x89, 0xc3, 0x61, 0xfe, 0xe8, 0x3b, 0x6c, 0x1e, 0x95, 0x09, + 0xdb, 0x82, 0xcb, 0x55, 0xaf, 0x03, 0xdd, 0x05, 0x6b, 0x62, 0xad, 0x1d, 0x83, 0xf0, 0x0d, 0xde, + 0x10, 0x97, 0xbe, 0x7e, 0x05, 0xa6, 0xc9, 0x6f, 0x6a, 0xb2, 0xfc, 0x2d, 0x89, 0xcf, 0xc1, 0xcd, + 0x7c, 0xeb, 0xe7, 0xd8, 0x54, 0x9d, 0x72, 0x01, 0x7c, 0x6d, 0xf2, 0x8d, 0x62, 0x0b, 0x3b, 0x0e, + 0xb6, 0x6c, 0x45, 0x6d, 0x47, 0x35, 0xcf, 0x97, 0xc4, 0x98, 0xf9, 0x8d, 0x37, 0x82, 0xa3, 0x78, + 0x81, 0x71, 0xce, 0xb7, 0xdb, 0xf5, 0x4d, 0x38, 0x16, 0xa1, 0x15, 0x09, 0x30, 0x3f, 0xc5, 0x31, + 0xa7, 0xfb, 0x34, 0x83, 0xc0, 0xae, 0x81, 0x28, 0x77, 0xc7, 0x32, 0x01, 0xe6, 0x6f, 0x72, 0x4c, + 0xc4, 0x79, 0xc5, 0x90, 0x12, 0xc4, 0xa7, 0x60, 0xf2, 0x2a, 0xb6, 0xb6, 0x4c, 0x9b, 0x27, 0x8e, + 0x12, 0xc0, 0x7d, 0x9a, 0xc3, 0x4d, 0x70, 0x46, 0x9a, 0x49, 0x22, 0x58, 0x8f, 0x41, 0x7e, 0x5b, + 0xd5, 0x70, 0x02, 0x88, 0xcf, 0x70, 0x88, 0x31, 0x42, 0x4f, 0x58, 0xe7, 0xa1, 0xd4, 0x32, 0xb9, + 0xd7, 0x8a, 0x67, 0xff, 0x2c, 0x67, 0x2f, 0x0a, 0x1e, 0x0e, 0xd1, 0x35, 0xbb, 0xbd, 0x36, 0x71, + 0x69, 0xf1, 0x10, 0xbf, 0x25, 0x20, 0x04, 0x0f, 0x87, 0x38, 0x84, 0x58, 0x5f, 0x15, 0x10, 0xb6, + 0x4f, 0x9e, 0x4f, 0x42, 0xd1, 0x34, 0xda, 0xfb, 0xa6, 0x91, 0xa4, 0x11, 0x9f, 0xe3, 0x08, 0xc0, + 0x59, 0x08, 0xc0, 0x39, 0x28, 0x24, 0x1d, 0x88, 0x7f, 0xf8, 0x86, 0x98, 0x1e, 0x62, 0x04, 0x2e, + 0xc0, 0x84, 0x30, 0x50, 0xba, 0x69, 0x24, 0x80, 0xf8, 0x47, 0x1c, 0xa2, 0xec, 0x63, 0xe3, 0xdd, + 0x70, 0xb0, 0xed, 0xb4, 0x70, 0x12, 0x90, 0x2f, 0x88, 0x6e, 0x70, 0x16, 0x2e, 0xca, 0x2d, 0x6c, + 0x68, 0x3b, 0xc9, 0x10, 0x7e, 0x5b, 0x88, 0x52, 0xf0, 0x10, 0x88, 0x05, 0x18, 0xef, 0xa8, 0x96, + 0xbd, 0xa3, 0xb6, 0x13, 0x0d, 0xc7, 0x3f, 0xe6, 0x18, 0x25, 0x97, 0x89, 0x4b, 0xa4, 0x67, 0x1c, + 0x06, 0xe6, 0x8b, 0x42, 0x22, 0x3e, 0x36, 0x3e, 0xf5, 0x6c, 0x87, 0x66, 0xd9, 0x0e, 0x83, 0xf6, + 0x4f, 0xc4, 0xd4, 0x63, 0xbc, 0xab, 0x7e, 0xc4, 0x73, 0x50, 0xb0, 0xf5, 0x97, 0x12, 0xc1, 0xfc, + 0x53, 0x31, 0xd2, 0x94, 0x81, 0x30, 0x7f, 0x00, 0x8e, 0x47, 0xba, 0x89, 0x04, 0x60, 0xff, 0x8c, + 0x83, 0x1d, 0x8d, 0x70, 0x15, 0xdc, 0x24, 0x1c, 0x16, 0xf2, 0x77, 0x84, 0x49, 0xc0, 0x21, 0xac, + 0x35, 0xb2, 0x8e, 0xb0, 0xd5, 0xed, 0xc3, 0x49, 0xed, 0x77, 0x85, 0xd4, 0x18, 0x6f, 0x40, 0x6a, + 0x1b, 0x70, 0x94, 0x23, 0x1e, 0x6e, 0x5c, 0x7f, 0x4f, 0x18, 0x56, 0xc6, 0xbd, 0x19, 0x1c, 0xdd, + 0x0f, 0x42, 0xd5, 0x15, 0xa7, 0x08, 0x58, 0x6d, 0xa5, 0xa3, 0x76, 0x13, 0x20, 0xff, 0x3e, 0x47, + 0x16, 0x16, 0xdf, 0x8d, 0x78, 0xed, 0x55, 0xb5, 0x4b, 0xc0, 0x9f, 0x83, 0x19, 0x01, 0xde, 0x33, + 0x2c, 0xac, 0x99, 0x2d, 0x43, 0x7f, 0x09, 0x37, 0x13, 0x40, 0xff, 0xf3, 0xd0, 0x50, 0x6d, 0xfa, + 0xd8, 0x09, 0xf2, 0x32, 0x54, 0xdc, 0x58, 0x45, 0xd1, 0x3b, 0x5d, 0xd3, 0x72, 0x62, 0x10, 0xff, + 0x85, 0x18, 0x29, 0x97, 0x6f, 0x99, 0xb2, 0xd5, 0x97, 0xa0, 0x4c, 0x1f, 0x93, 0xaa, 0xe4, 0x97, + 0x38, 0xd0, 0xb8, 0xc7, 0xc5, 0x0d, 0x87, 0x66, 0x76, 0xba, 0xaa, 0x95, 0xc4, 0xfe, 0xfd, 0x4b, + 0x61, 0x38, 0x38, 0x0b, 0x37, 0x1c, 0xce, 0x7e, 0x17, 0x13, 0x6f, 0x9f, 0x00, 0xe1, 0xcb, 0xc2, + 0x70, 0x08, 0x1e, 0x0e, 0x21, 0x02, 0x86, 0x04, 0x10, 0x5f, 0x11, 0x10, 0x82, 0x87, 0x40, 0x3c, + 0xe3, 0x39, 0x5a, 0x0b, 0xb7, 0x74, 0xdb, 0xb1, 0x58, 0x98, 0x3c, 0x1c, 0xea, 0xab, 0x6f, 0x04, + 0x83, 0x30, 0xd9, 0xc7, 0x4a, 0x2c, 0x11, 0x4f, 0xbb, 0xd2, 0x55, 0x54, 0x7c, 0xc3, 0xbe, 0x26, + 0x2c, 0x91, 0x8f, 0x8d, 0xb4, 0xcd, 0x17, 0x21, 0x12, 0xb1, 0x6b, 0x64, 0xed, 0x90, 0x00, 0xee, + 0x0f, 0x42, 0x8d, 0x5b, 0x17, 0xbc, 0x04, 0xd3, 0x17, 0xff, 0xf4, 0x8c, 0x5d, 0xbc, 0x9f, 0x48, + 0x3b, 0xff, 0x30, 0x14, 0xff, 0x6c, 0x32, 0x4e, 0x66, 0x43, 0x26, 0x42, 0xf1, 0x14, 0x8a, 0x3b, + 0x3f, 0x34, 0xf3, 0xb7, 0xdf, 0xe4, 0xfd, 0x0d, 0x86, 0x53, 0xf5, 0x15, 0xa2, 0xe4, 0xc1, 0xa0, + 0x27, 0x1e, 0xec, 0xe7, 0xde, 0x74, 0xf5, 0x3c, 0x10, 0xf3, 0xd4, 0xcf, 0xc3, 0x78, 0x20, 0xe0, + 0x89, 0x87, 0xfa, 0x79, 0x0e, 0x55, 0xf2, 0xc7, 0x3b, 0xf5, 0x87, 0x20, 0x4b, 0x82, 0x97, 0x78, + 0xf6, 0x5f, 0xe0, 0xec, 0x94, 0xbc, 0xfe, 0x3e, 0xc8, 0x8b, 0xa0, 0x25, 0x9e, 0xf5, 0x17, 0x39, + 0xab, 0xcb, 0x42, 0xd8, 0x45, 0xc0, 0x12, 0xcf, 0xfe, 0x61, 0xc1, 0x2e, 0x58, 0x08, 0x7b, 0x72, + 0x11, 0x7e, 0xfd, 0xef, 0x64, 0xb9, 0xd3, 0x11, 0xb2, 0x3b, 0x07, 0x63, 0x3c, 0x52, 0x89, 0xe7, + 0xfe, 0x28, 0xaf, 0x5c, 0x70, 0xd4, 0x1f, 0x81, 0xd1, 0x84, 0x02, 0xff, 0x65, 0xce, 0xca, 0xe8, + 0xeb, 0x0b, 0x50, 0xf4, 0x45, 0x27, 0xf1, 0xec, 0xbf, 0xc2, 0xd9, 0xfd, 0x5c, 0xa4, 0xe9, 0x3c, + 0x3a, 0x89, 0x07, 0xf8, 0xb8, 0x68, 0x3a, 0xe7, 0x20, 0x62, 0x13, 0x81, 0x49, 0x3c, 0xf7, 0x27, + 0x84, 0xd4, 0x05, 0x4b, 0xfd, 0x49, 0x28, 0xb8, 0xce, 0x26, 0x9e, 0xff, 0xef, 0x72, 0x7e, 0x8f, + 0x87, 0x48, 0xc0, 0xe7, 0xec, 0xe2, 0x21, 0x3e, 0x29, 0x24, 0xe0, 0xe3, 0x22, 0xd3, 0x28, 0x1c, + 0xc0, 0xc4, 0x23, 0xfd, 0x3d, 0x31, 0x8d, 0x42, 0xf1, 0x0b, 0x19, 0x4d, 0x6a, 0xf3, 0xe3, 0x21, + 0x7e, 0x55, 0x8c, 0x26, 0xa5, 0x27, 0xcd, 0x08, 0x47, 0x04, 0xf1, 0x18, 0x7f, 0x5f, 0x34, 0x23, + 0x14, 0x10, 0xd4, 0xd7, 0x00, 0xf5, 0x47, 0x03, 0xf1, 0x78, 0xaf, 0x70, 0xbc, 0xc9, 0xbe, 0x60, + 0xa0, 0xfe, 0x2c, 0x1c, 0x8d, 0x8e, 0x04, 0xe2, 0x51, 0x7f, 0xe3, 0xcd, 0xd0, 0xda, 0xcd, 0x1f, + 0x08, 0xd4, 0x37, 0x3c, 0x97, 0xe2, 0x8f, 0x02, 0xe2, 0x61, 0x3f, 0xf5, 0x66, 0xd0, 0x70, 0xfb, + 0x83, 0x80, 0xfa, 0x3c, 0x80, 0xe7, 0x80, 0xe3, 0xb1, 0x3e, 0xcd, 0xb1, 0x7c, 0x4c, 0x64, 0x6a, + 0x70, 0xff, 0x1b, 0xcf, 0xff, 0x19, 0x31, 0x35, 0x38, 0x07, 0x99, 0x1a, 0xc2, 0xf5, 0xc6, 0x73, + 0x7f, 0x56, 0x4c, 0x0d, 0xc1, 0x42, 0x34, 0xdb, 0xe7, 0xdd, 0xe2, 0x11, 0x3e, 0x27, 0x34, 0xdb, + 0xc7, 0x55, 0xbf, 0x04, 0x93, 0x7d, 0x0e, 0x31, 0x1e, 0xea, 0xf3, 0x1c, 0xaa, 0x12, 0xf6, 0x87, + 0x7e, 0xe7, 0xc5, 0x9d, 0x61, 0x3c, 0xda, 0x3f, 0x08, 0x39, 0x2f, 0xee, 0x0b, 0xeb, 0xe7, 0x20, + 0x6f, 0xf4, 0xda, 0x6d, 0x32, 0x79, 0xd0, 0xf0, 0x33, 0x7f, 0x33, 0xff, 0xfd, 0x87, 0x5c, 0x3a, + 0x82, 0xa1, 0xfe, 0x10, 0x8c, 0xe2, 0xce, 0x16, 0x6e, 0xc6, 0x71, 0x7e, 0xef, 0x87, 0xc2, 0x60, + 0x12, 0xea, 0xfa, 0x93, 0x00, 0x2c, 0x35, 0x42, 0xb7, 0x07, 0x63, 0x78, 0xff, 0xc7, 0x0f, 0xf9, + 0x69, 0x1c, 0x8f, 0xc5, 0x03, 0x60, 0x67, 0x7b, 0x86, 0x03, 0xbc, 0x11, 0x04, 0xa0, 0x23, 0xf2, + 0x18, 0x8c, 0xbd, 0x60, 0x9b, 0x86, 0xa3, 0xb6, 0xe2, 0xb8, 0xff, 0x27, 0xe7, 0x16, 0xf4, 0x44, + 0x60, 0x1d, 0xd3, 0xc2, 0x8e, 0xda, 0xb2, 0xe3, 0x78, 0xff, 0x17, 0xe7, 0x75, 0x19, 0x08, 0xb3, + 0xa6, 0xda, 0x4e, 0x92, 0x7e, 0xff, 0x6f, 0xc1, 0x2c, 0x18, 0x48, 0xa3, 0xc9, 0xef, 0x5d, 0xbc, + 0x1f, 0xc7, 0xfb, 0x7d, 0xd1, 0x68, 0x4e, 0x5f, 0x7f, 0x1f, 0x14, 0xc8, 0x4f, 0x76, 0xc4, 0x2e, + 0x86, 0xf9, 0xff, 0x70, 0x66, 0x8f, 0x83, 0xd4, 0x6c, 0x3b, 0x4d, 0x47, 0x8f, 0x17, 0xf6, 0x75, + 0x3e, 0xd2, 0x82, 0xbe, 0x3e, 0x0f, 0x45, 0xdb, 0x69, 0x36, 0x7b, 0x3c, 0x3e, 0x8d, 0x61, 0xff, + 0xbf, 0x3f, 0x74, 0x53, 0x16, 0x2e, 0x0f, 0x19, 0xed, 0x6b, 0xbb, 0x4e, 0xd7, 0xa4, 0x5b, 0x20, + 0x71, 0x08, 0x6f, 0x72, 0x04, 0x1f, 0x4b, 0x7d, 0x01, 0x4a, 0xa4, 0x2f, 0x16, 0xee, 0x62, 0xba, + 0x5f, 0x15, 0x03, 0xf1, 0x97, 0x5c, 0x00, 0x01, 0xa6, 0xc6, 0x4f, 0x0f, 0xba, 0x77, 0x13, 0x9d, + 0x36, 0x86, 0x0b, 0xe6, 0x05, 0x93, 0x25, 0x8c, 0x9f, 0x97, 0x02, 0xe9, 0xe2, 0x96, 0xe9, 0x65, + 0x6b, 0xdd, 0x45, 0x0e, 0xfc, 0x41, 0x1a, 0xee, 0xa4, 0xc7, 0x7d, 0xad, 0x8e, 0x6e, 0x38, 0x67, + 0x34, 0x6b, 0xbf, 0xeb, 0x98, 0x67, 0x3a, 0xd8, 0xda, 0x6d, 0x63, 0xfe, 0x87, 0x67, 0x7f, 0x67, + 0x3c, 0xb2, 0x39, 0x46, 0x36, 0xc7, 0xde, 0x57, 0x23, 0xb3, 0xc5, 0xd2, 0x02, 0x8c, 0xad, 0x59, + 0xa6, 0xb9, 0x7d, 0xb9, 0x8b, 0x10, 0x3f, 0xc1, 0xcc, 0x4f, 0xc6, 0x51, 0x35, 0xe4, 0x37, 0x9e, + 0xd2, 0xde, 0x8d, 0x27, 0x04, 0xd9, 0xa6, 0xea, 0xa8, 0x34, 0x61, 0x5e, 0x92, 0xe9, 0x6f, 0xa9, + 0x01, 0xa3, 0x14, 0x04, 0x3d, 0x06, 0x19, 0xb3, 0x6b, 0xf3, 0xec, 0xfe, 0xed, 0x73, 0x83, 0xda, + 0x32, 0xc7, 0xab, 0x6c, 0x64, 0xbf, 0x71, 0x50, 0x1b, 0x91, 0x09, 0x4f, 0x63, 0xed, 0xaf, 0xbf, + 0x7d, 0x22, 0xf5, 0xdb, 0xaf, 0x9d, 0x48, 0x0d, 0xbc, 0xc1, 0x34, 0xe7, 0x13, 0x94, 0x4f, 0x18, + 0x83, 0xe4, 0xe2, 0xde, 0x63, 0xfa, 0xa5, 0x34, 0x9c, 0xf0, 0x11, 0xb5, 0xf5, 0x2d, 0xfb, 0xcc, + 0xee, 0x55, 0x76, 0xe5, 0x89, 0x4b, 0x0d, 0xf9, 0x5a, 0x4a, 0xde, 0xcf, 0xed, 0x5e, 0x1d, 0x20, + 0xaf, 0x39, 0xc8, 0xae, 0xa9, 0xba, 0x15, 0x71, 0x15, 0x6c, 0xda, 0x3b, 0xdc, 0x4a, 0xca, 0xd8, + 0x83, 0x74, 0x16, 0xf2, 0x4f, 0x2f, 0x3f, 0xfc, 0x60, 0x12, 0x9e, 0x0c, 0xe7, 0x69, 0xc8, 0x42, + 0x14, 0x5f, 0x8d, 0x10, 0xc7, 0xd7, 0x5f, 0x3f, 0x91, 0x8a, 0xbc, 0xd4, 0x15, 0x2d, 0x12, 0xde, + 0x5b, 0x57, 0x18, 0x9f, 0x48, 0x43, 0x2d, 0xbc, 0x2b, 0x40, 0xa6, 0xa2, 0xed, 0xa8, 0x9d, 0xee, + 0xa0, 0x3b, 0x5d, 0xe7, 0xa0, 0xb0, 0x21, 0x68, 0xd0, 0x0c, 0x8c, 0xd9, 0x58, 0x33, 0x8d, 0xa6, + 0x4d, 0x7b, 0x92, 0x91, 0xc5, 0x23, 0xe9, 0x8d, 0xa1, 0x1a, 0xa6, 0xcd, 0x8f, 0x9c, 0xb2, 0x87, + 0xc6, 0xaf, 0xa7, 0x0e, 0x37, 0x37, 0xca, 0x6e, 0x55, 0x74, 0x82, 0xac, 0xa5, 0x9e, 0xbf, 0x77, + 0xd8, 0x86, 0x0a, 0xbb, 0xb9, 0xe6, 0x76, 0xc1, 0xb7, 0x7b, 0x72, 0x22, 0xbc, 0x7b, 0xf2, 0x2c, + 0x6e, 0xb7, 0x9f, 0x36, 0xcc, 0x6b, 0xc6, 0x06, 0xe1, 0x71, 0x45, 0xf2, 0xb1, 0x34, 0x9c, 0xe8, + 0xdb, 0x28, 0xe1, 0xe6, 0x65, 0x90, 0x44, 0xea, 0x90, 0x5f, 0x14, 0x56, 0xeb, 0xb0, 0x02, 0xf9, + 0xd5, 0x43, 0x0a, 0x64, 0x5c, 0xd4, 0x24, 0xe4, 0x71, 0x4f, 0xbc, 0x3c, 0x44, 0xfb, 0x6f, 0x40, + 0x1c, 0x3f, 0xff, 0x04, 0xdc, 0xee, 0x53, 0x20, 0x75, 0x4b, 0xd3, 0xf9, 0xf5, 0x40, 0xff, 0x8c, + 0x39, 0xe2, 0x9b, 0x31, 0x84, 0x64, 0x8e, 0xbe, 0x8c, 0x9e, 0x34, 0xd5, 0x64, 0xb6, 0xab, 0x1a, + 0x33, 0x4b, 0xab, 0x71, 0x8a, 0x5b, 0x8d, 0x19, 0x46, 0xe9, 0xaf, 0x46, 0x61, 0x4c, 0xdc, 0xe5, + 0x7c, 0x14, 0xb2, 0x58, 0xdb, 0x31, 0xf9, 0x69, 0x77, 0x69, 0x2e, 0xb2, 0x3f, 0x73, 0x9c, 0x7a, + 0x49, 0xdb, 0x31, 0x2f, 0x8e, 0xc8, 0x94, 0x83, 0xde, 0x01, 0x6b, 0xf7, 0xec, 0x1d, 0x7e, 0x28, + 0xf9, 0xd4, 0x70, 0xd6, 0xf3, 0x84, 0xf4, 0xe2, 0x88, 0xcc, 0x78, 0x48, 0xb5, 0xf4, 0xfe, 0x5a, + 0x36, 0x49, 0xb5, 0xcb, 0xc6, 0x36, 0xad, 0x96, 0x70, 0xa0, 0x8b, 0x00, 0x36, 0x76, 0xc4, 0x51, + 0x86, 0x51, 0xca, 0x7f, 0xf7, 0x70, 0xfe, 0x75, 0xec, 0x30, 0xb7, 0x75, 0x71, 0x44, 0x2e, 0xd8, + 0xe2, 0x81, 0x20, 0xe9, 0x86, 0xee, 0x28, 0xda, 0x8e, 0xaa, 0x1b, 0x74, 0x0f, 0x3e, 0x16, 0x69, + 0xd9, 0xd0, 0x9d, 0x05, 0x42, 0x4e, 0x90, 0x74, 0xf1, 0x40, 0x44, 0x41, 0xef, 0x8c, 0xf2, 0x4b, + 0x56, 0x31, 0xa2, 0x78, 0x86, 0x90, 0x12, 0x51, 0x50, 0x1e, 0xf4, 0x34, 0x14, 0xe9, 0x76, 0xab, + 0xb2, 0xd5, 0x36, 0xb5, 0x5d, 0x7e, 0xb3, 0x64, 0x76, 0x38, 0x44, 0x83, 0x30, 0x34, 0x08, 0xfd, + 0xc5, 0x11, 0x19, 0xb6, 0xdc, 0x27, 0xd4, 0x80, 0x3c, 0x3b, 0xf6, 0xeb, 0xec, 0xf1, 0xbb, 0x81, + 0x77, 0x0e, 0x47, 0xa2, 0x27, 0x80, 0x37, 0xf6, 0x2e, 0x8e, 0xc8, 0x63, 0x1a, 0xfb, 0x89, 0x96, + 0xa0, 0x80, 0x8d, 0x26, 0x6f, 0x4e, 0x91, 0xdf, 0xa2, 0x1a, 0xae, 0x17, 0x46, 0x53, 0x34, 0x26, + 0x8f, 0xf9, 0x6f, 0xf4, 0x04, 0xe4, 0x34, 0xb3, 0xd3, 0xd1, 0x1d, 0x7a, 0xc7, 0xb0, 0x78, 0xf6, + 0x8e, 0x98, 0x86, 0x50, 0xda, 0x8b, 0x23, 0x32, 0xe7, 0x22, 0xc3, 0xd3, 0xc4, 0x6d, 0xfd, 0x2a, + 0xb6, 0x48, 0x67, 0xa6, 0x92, 0x0c, 0xcf, 0x22, 0xa3, 0xa7, 0xdd, 0x29, 0x34, 0xc5, 0x43, 0x63, + 0x8c, 0xbb, 0x17, 0xe9, 0x6e, 0x28, 0xfa, 0x34, 0x99, 0x58, 0x2c, 0xbe, 0x02, 0xe1, 0xce, 0x5e, + 0x3c, 0x4a, 0x65, 0x28, 0xf9, 0xf5, 0x56, 0xea, 0xb8, 0x8c, 0x74, 0x13, 0x7f, 0x06, 0xc6, 0xae, + 0x62, 0xcb, 0x66, 0x3b, 0xf8, 0x94, 0x91, 0x3f, 0xa2, 0x53, 0x30, 0x4e, 0xe5, 0xa6, 0x88, 0xf7, + 0xec, 0x5a, 0x72, 0x89, 0x16, 0x5e, 0xe1, 0x44, 0x35, 0x28, 0x76, 0xcf, 0x76, 0x5d, 0x12, 0x76, + 0x37, 0x1a, 0xba, 0x67, 0xbb, 0x9c, 0x40, 0xaa, 0x43, 0x25, 0xac, 0xba, 0x7e, 0xaf, 0x59, 0x88, + 0xf0, 0x9a, 0x05, 0xe1, 0x69, 0x7f, 0x2f, 0xed, 0x32, 0xbb, 0xda, 0x4a, 0xa6, 0x1b, 0x31, 0x12, + 0x94, 0xbb, 0x78, 0xb6, 0xda, 0x17, 0xda, 0xb9, 0xbe, 0xa6, 0x91, 0x27, 0xa1, 0xc8, 0x27, 0xfe, + 0xac, 0x96, 0x92, 0x29, 0x07, 0x3a, 0x4e, 0x14, 0x4a, 0xd5, 0x0d, 0x45, 0x6f, 0x8a, 0xdb, 0xc4, + 0xf4, 0x79, 0xb9, 0x89, 0x9e, 0x81, 0x8a, 0x66, 0x1a, 0x36, 0x36, 0xec, 0x9e, 0xad, 0x74, 0x55, + 0x4b, 0xed, 0x78, 0x97, 0xee, 0xa2, 0x87, 0x69, 0x41, 0x90, 0xaf, 0x51, 0x6a, 0x79, 0x42, 0x0b, + 0x16, 0xa0, 0x15, 0x80, 0xab, 0x6a, 0x5b, 0x6f, 0xaa, 0x8e, 0x69, 0xd9, 0xfc, 0x72, 0xca, 0x20, + 0xb0, 0x2b, 0x82, 0x70, 0xb3, 0xdb, 0x54, 0x1d, 0xcc, 0x83, 0x28, 0x1f, 0x3f, 0xba, 0x0b, 0x26, + 0xd4, 0x6e, 0x57, 0xb1, 0x1d, 0xd5, 0xc1, 0xca, 0xd6, 0xbe, 0x83, 0x6d, 0x6a, 0x2f, 0x4a, 0xf2, + 0xb8, 0xda, 0xed, 0xae, 0x93, 0xd2, 0x06, 0x29, 0x94, 0x9a, 0xee, 0x68, 0xd3, 0xa9, 0xe9, 0xc6, + 0x76, 0x29, 0x2f, 0xb6, 0x23, 0x65, 0xf4, 0x68, 0x05, 0x93, 0x81, 0x38, 0x8d, 0x92, 0xdb, 0xc1, + 0x7a, 0x6b, 0x87, 0x5d, 0x6f, 0xcf, 0xc8, 0xfc, 0x89, 0x0c, 0x4c, 0xd7, 0x32, 0xaf, 0x62, 0x7e, + 0xb3, 0x9d, 0x3d, 0x48, 0xbf, 0x96, 0x86, 0xc9, 0xbe, 0xe9, 0x4b, 0x70, 0xe9, 0x01, 0x7f, 0x5e, + 0x17, 0xf9, 0x8d, 0xce, 0x11, 0x5c, 0xb5, 0xc9, 0x2f, 0xad, 0x14, 0xcf, 0xde, 0x36, 0x40, 0x02, + 0x17, 0x29, 0x11, 0xef, 0x38, 0x67, 0x41, 0x9b, 0x50, 0x69, 0xab, 0xb6, 0xa3, 0xb0, 0x59, 0xc4, + 0x6e, 0x09, 0x67, 0x86, 0x5a, 0x82, 0x15, 0x55, 0xcc, 0x3e, 0xa2, 0xdc, 0x1c, 0xae, 0xdc, 0x0e, + 0x94, 0xa2, 0xe7, 0x60, 0x7a, 0x6b, 0xff, 0x25, 0xd5, 0x70, 0x74, 0x83, 0x1e, 0x36, 0x0a, 0x8e, + 0x51, 0x6d, 0x00, 0xf4, 0xd2, 0x55, 0xbd, 0x89, 0x0d, 0x4d, 0x0c, 0xce, 0x94, 0x0b, 0xe1, 0x0e, + 0x9e, 0x2d, 0x3d, 0x07, 0xe5, 0xa0, 0x2d, 0x42, 0x65, 0x48, 0x3b, 0x7b, 0x5c, 0x22, 0x69, 0x67, + 0x0f, 0x3d, 0xcc, 0x23, 0xf2, 0x34, 0x3d, 0x2d, 0x37, 0xc8, 0x59, 0x70, 0x6e, 0xef, 0x2e, 0xa1, + 0x24, 0xb9, 0x33, 0xc1, 0x35, 0x0c, 0x61, 0x6c, 0xe9, 0x34, 0x4c, 0x84, 0x8c, 0x98, 0x6f, 0x58, + 0x53, 0xfe, 0x61, 0x95, 0x26, 0x60, 0x3c, 0x60, 0xab, 0xa4, 0x3f, 0xce, 0x41, 0xde, 0xfd, 0x46, + 0xc1, 0x45, 0x28, 0xe0, 0x3d, 0x0d, 0x77, 0x1d, 0x61, 0x15, 0x86, 0x19, 0x71, 0xc6, 0xb3, 0x24, + 0xe8, 0x89, 0xb9, 0x72, 0x99, 0xd1, 0x63, 0x01, 0x97, 0x7c, 0x2a, 0x0e, 0xc4, 0xef, 0x93, 0x1f, + 0x0f, 0xfa, 0xe4, 0x3b, 0x62, 0x78, 0x43, 0x4e, 0xf9, 0xb1, 0x80, 0x53, 0x8e, 0xab, 0x38, 0xe0, + 0x95, 0x97, 0x23, 0xbc, 0x72, 0x5c, 0xf7, 0x07, 0xb8, 0xe5, 0xe5, 0x08, 0xb7, 0x3c, 0x1b, 0xdb, + 0x96, 0x48, 0xbf, 0xfc, 0x78, 0xd0, 0x2f, 0xc7, 0x89, 0x23, 0xe4, 0x98, 0x57, 0xa2, 0x1c, 0xf3, + 0xe9, 0x18, 0x8c, 0x81, 0x9e, 0x79, 0xa1, 0xcf, 0x33, 0xdf, 0x15, 0x03, 0x15, 0xe1, 0x9a, 0x97, + 0x03, 0x3e, 0x11, 0x12, 0xc9, 0x26, 0xda, 0x29, 0xa2, 0xf3, 0xfd, 0x5e, 0xfe, 0xee, 0x38, 0x55, + 0x8b, 0x72, 0xf3, 0x4f, 0x86, 0xdc, 0xfc, 0x9d, 0x71, 0xbd, 0x0a, 0xf9, 0x79, 0xcf, 0x3b, 0x9f, + 0x26, 0xf6, 0x31, 0x34, 0x33, 0x88, 0x2d, 0xc5, 0x96, 0x65, 0x5a, 0xdc, 0xf1, 0xb1, 0x07, 0x69, + 0x96, 0x58, 0x6c, 0x4f, 0xff, 0x87, 0x78, 0x72, 0x3a, 0x69, 0x7d, 0xda, 0x2e, 0x7d, 0x35, 0xe5, + 0xf1, 0x52, 0xcb, 0xe6, 0xb7, 0xf6, 0x05, 0x6e, 0xed, 0x7d, 0x0e, 0x3e, 0x1d, 0x74, 0xf0, 0x35, + 0x28, 0x12, 0x9f, 0x12, 0xf2, 0xdd, 0x6a, 0x57, 0xf8, 0x6e, 0x74, 0x0f, 0x4c, 0x52, 0xfb, 0xcb, + 0xc2, 0x00, 0x6e, 0x48, 0xb2, 0xd4, 0x90, 0x4c, 0x90, 0x17, 0x4c, 0x82, 0xcc, 0x51, 0xdc, 0x0f, + 0x53, 0x3e, 0x5a, 0x82, 0x4b, 0x7d, 0x01, 0x73, 0x52, 0x15, 0x97, 0x7a, 0xbe, 0xdb, 0xbd, 0xa8, + 0xda, 0x3b, 0xd2, 0xaa, 0x27, 0x20, 0x2f, 0x2e, 0x40, 0x90, 0xd5, 0xcc, 0x26, 0xeb, 0xf7, 0xb8, + 0x4c, 0x7f, 0x93, 0x58, 0xa1, 0x6d, 0xb6, 0xf8, 0x09, 0x48, 0xf2, 0x93, 0x50, 0xb9, 0x53, 0xbb, + 0xc0, 0xe6, 0xac, 0xf4, 0xa5, 0x94, 0x87, 0xe7, 0x85, 0x0a, 0x51, 0x5e, 0x3d, 0x75, 0x33, 0xbd, + 0x7a, 0xfa, 0xad, 0x79, 0x75, 0xe9, 0xcd, 0x94, 0x37, 0xa4, 0xae, 0xbf, 0xbe, 0x31, 0x11, 0x10, + 0xed, 0x62, 0x37, 0xc1, 0xd9, 0x49, 0x5d, 0xf6, 0x20, 0x42, 0xad, 0x5c, 0x44, 0x82, 0x62, 0xcc, + 0x97, 0xd4, 0x40, 0x0f, 0x51, 0x3f, 0x6f, 0x6e, 0x73, 0xd3, 0x50, 0x8b, 0x49, 0xf4, 0xc8, 0x8c, + 0xda, 0xe7, 0x5f, 0x0a, 0x81, 0xb0, 0xe1, 0x56, 0x28, 0x90, 0xa6, 0xb3, 0xeb, 0x4f, 0xc0, 0xd3, + 0x8b, 0xa2, 0x40, 0x6a, 0x02, 0xea, 0xb7, 0x31, 0xe8, 0x12, 0xe4, 0xf0, 0x55, 0x7a, 0x1a, 0x95, + 0x25, 0x9b, 0x6e, 0x1d, 0xe8, 0x88, 0xb1, 0xe1, 0x34, 0x66, 0x88, 0x30, 0xbf, 0x77, 0x50, 0xab, + 0x30, 0x9e, 0xfb, 0xcc, 0x8e, 0xee, 0xe0, 0x4e, 0xd7, 0xd9, 0x97, 0x39, 0x8a, 0xf4, 0xe1, 0x34, + 0xf1, 0x87, 0x01, 0xfb, 0x13, 0x29, 0x5e, 0x31, 0x69, 0xd2, 0xbe, 0x10, 0x29, 0x99, 0xc8, 0x6f, + 0x03, 0x68, 0xa9, 0xb6, 0x72, 0x4d, 0x35, 0x1c, 0xdc, 0xe4, 0x72, 0x2f, 0xb4, 0x54, 0xfb, 0x59, + 0x5a, 0x40, 0xe2, 0x4d, 0xf2, 0xba, 0x67, 0xe3, 0x26, 0x1d, 0x80, 0x8c, 0x3c, 0xd6, 0x52, 0xed, + 0x4d, 0x1b, 0x37, 0x7d, 0x7d, 0x1d, 0xbb, 0x19, 0x7d, 0x0d, 0xca, 0x3b, 0x1f, 0x96, 0xf7, 0x47, + 0xd3, 0xde, 0xec, 0xf0, 0xc2, 0x87, 0x1f, 0x4f, 0x59, 0x7c, 0x86, 0xae, 0x29, 0x82, 0x4e, 0x00, + 0x7d, 0x00, 0x26, 0xdd, 0x59, 0xa9, 0xf4, 0xe8, 0x6c, 0x15, 0x5a, 0x78, 0xb8, 0xc9, 0x5d, 0xb9, + 0x1a, 0x2c, 0xb6, 0xd1, 0xcf, 0xc0, 0xb1, 0x90, 0x0d, 0x72, 0x2b, 0x48, 0x1f, 0xca, 0x14, 0x1d, + 0x09, 0x9a, 0x22, 0x81, 0xef, 0x49, 0x2f, 0x73, 0x53, 0x66, 0xcd, 0x1d, 0x24, 0x84, 0xf5, 0xbb, + 0xb7, 0x28, 0x9d, 0x90, 0xfe, 0x24, 0x05, 0x13, 0xa1, 0x06, 0xa2, 0x47, 0x61, 0x94, 0x79, 0xe0, + 0xd4, 0xd0, 0x44, 0x08, 0x95, 0x38, 0xef, 0x13, 0x63, 0x40, 0xf3, 0x90, 0xc7, 0x3c, 0xba, 0xe6, + 0x42, 0xb9, 0x33, 0x26, 0x08, 0xe7, 0xfc, 0x2e, 0x1b, 0x5a, 0x84, 0x82, 0x2b, 0xfa, 0x98, 0x95, + 0x9b, 0x3b, 0x72, 0x1c, 0xc4, 0x63, 0x94, 0x16, 0xa0, 0xe8, 0x6b, 0x1e, 0xbb, 0x0b, 0xb8, 0xc7, + 0x97, 0x5b, 0x2c, 0x80, 0xce, 0x77, 0xd4, 0x3d, 0xba, 0xd2, 0x42, 0xc7, 0x60, 0x8c, 0xbc, 0x6c, + 0xf1, 0xcb, 0x52, 0x19, 0x39, 0xd7, 0x51, 0xf7, 0x2e, 0xa8, 0xb6, 0xf4, 0xb1, 0x14, 0x94, 0x83, + 0xed, 0x44, 0xf7, 0x02, 0x22, 0xb4, 0x6a, 0x0b, 0x2b, 0x46, 0xaf, 0xc3, 0x7c, 0xa4, 0x40, 0x9c, + 0xe8, 0xa8, 0x7b, 0xf3, 0x2d, 0x7c, 0xa9, 0xd7, 0xa1, 0x55, 0xdb, 0x68, 0x15, 0x2a, 0x82, 0x58, + 0x24, 0xbb, 0xb8, 0x54, 0x8e, 0xf7, 0x7f, 0xaf, 0x86, 0x13, 0xb0, 0xb5, 0xee, 0x2b, 0x64, 0xad, + 0x5b, 0x66, 0x78, 0xe2, 0x8d, 0xf4, 0x10, 0x4c, 0x84, 0x7a, 0x8c, 0x24, 0x18, 0xef, 0xf6, 0xb6, + 0x94, 0x5d, 0xbc, 0x4f, 0xaf, 0xbf, 0x33, 0x55, 0x2f, 0xc8, 0xc5, 0x6e, 0x6f, 0xeb, 0x69, 0xbc, + 0x4f, 0x73, 0x87, 0x92, 0x06, 0xe5, 0xe0, 0x62, 0x8a, 0x38, 0x0e, 0xcb, 0xec, 0x19, 0x4d, 0xf1, + 0x61, 0x03, 0xfa, 0x80, 0xce, 0xc1, 0xe8, 0x55, 0x93, 0x69, 0xf3, 0xb0, 0xd5, 0xd3, 0x15, 0xd3, + 0xc1, 0xbe, 0x25, 0x19, 0xe3, 0x91, 0x6c, 0x18, 0xa5, 0x7a, 0x19, 0xb9, 0x51, 0x71, 0x05, 0x40, + 0x75, 0x1c, 0x4b, 0xdf, 0xea, 0x79, 0xf0, 0x33, 0x73, 0xfd, 0x69, 0xfd, 0xb9, 0x35, 0x55, 0xb7, + 0x1a, 0xb7, 0x72, 0xcd, 0x9e, 0xf6, 0x78, 0x7c, 0xda, 0xed, 0x43, 0x92, 0xde, 0xc8, 0x42, 0x8e, + 0x2d, 0x37, 0xd1, 0x13, 0xc1, 0xe4, 0x47, 0xf1, 0xec, 0x89, 0x41, 0xcd, 0x67, 0x54, 0xbc, 0xf5, + 0x6e, 0x04, 0x75, 0x57, 0x38, 0xa3, 0xd0, 0x28, 0xbe, 0x76, 0x50, 0x1b, 0xa3, 0xd1, 0xc7, 0xf2, + 0xa2, 0x97, 0x5e, 0x18, 0xb4, 0xba, 0x16, 0xb9, 0x8c, 0xec, 0xa1, 0x73, 0x19, 0x17, 0x61, 0xdc, + 0x17, 0x6e, 0xe9, 0x4d, 0xbe, 0x4e, 0x39, 0x31, 0x6c, 0xd2, 0x2d, 0x2f, 0xf2, 0xf6, 0x17, 0xdd, + 0x70, 0x6c, 0xb9, 0x89, 0x66, 0x83, 0x8b, 0x6c, 0x1a, 0xb5, 0xb1, 0x70, 0xc1, 0xb7, 0x6e, 0xa6, + 0x77, 0xf2, 0x6f, 0x81, 0x02, 0xbd, 0xd8, 0x4c, 0x49, 0x58, 0xf4, 0x90, 0x27, 0x05, 0xf4, 0xe5, + 0xdd, 0x30, 0xe1, 0x05, 0x36, 0x8c, 0x24, 0xcf, 0x50, 0xbc, 0x62, 0x4a, 0xf8, 0x00, 0x4c, 0xd3, + 0x0f, 0xe0, 0x85, 0xa9, 0x0b, 0x94, 0x1a, 0x91, 0x77, 0x57, 0x82, 0x1c, 0x77, 0x42, 0xd9, 0x33, + 0xa1, 0x94, 0x16, 0x58, 0xea, 0xc3, 0x2d, 0xa5, 0x64, 0xc7, 0x21, 0xef, 0x86, 0x9d, 0x45, 0xf6, + 0x65, 0x3d, 0x95, 0x45, 0x9b, 0x6e, 0x20, 0x6b, 0x61, 0xbb, 0xd7, 0x76, 0x38, 0x48, 0x89, 0xd2, + 0xd0, 0x40, 0x56, 0x66, 0xe5, 0x94, 0xf6, 0x14, 0x8c, 0x0b, 0xab, 0xc2, 0xe8, 0xc6, 0x29, 0x5d, + 0x49, 0x14, 0x52, 0xa2, 0xd3, 0x50, 0xe9, 0x5a, 0x66, 0xd7, 0xb4, 0xb1, 0xa5, 0xa8, 0xcd, 0xa6, + 0x85, 0x6d, 0x7b, 0xa6, 0xcc, 0xf0, 0x44, 0xf9, 0x3c, 0x2b, 0x96, 0xde, 0x03, 0x63, 0x22, 0x9e, + 0x9e, 0x86, 0xd1, 0x86, 0x6b, 0x21, 0xb3, 0x32, 0x7b, 0x20, 0xfe, 0x75, 0xbe, 0xdb, 0xe5, 0xd9, + 0x35, 0xf2, 0x53, 0x6a, 0xc3, 0x18, 0x1f, 0xb0, 0xc8, 0x9c, 0xca, 0x2a, 0x94, 0xba, 0xaa, 0x45, + 0xba, 0xe1, 0xcf, 0xac, 0x0c, 0x5a, 0x11, 0xae, 0xa9, 0x96, 0xb3, 0x8e, 0x9d, 0x40, 0x82, 0xa5, + 0x48, 0xf9, 0x59, 0x91, 0xf4, 0x18, 0x8c, 0x07, 0x68, 0xbc, 0xef, 0x10, 0xf2, 0x89, 0x4e, 0x1f, + 0xdc, 0x96, 0xa4, 0xbd, 0x96, 0x48, 0xe7, 0xa0, 0xe0, 0x8e, 0x15, 0x59, 0x68, 0x08, 0x51, 0xf0, + 0x0f, 0x1b, 0xf2, 0x47, 0x9a, 0x44, 0x32, 0xaf, 0xf1, 0x4f, 0x34, 0x65, 0x64, 0xf6, 0x20, 0x61, + 0x9f, 0x61, 0x62, 0xde, 0x0c, 0x3d, 0x0e, 0x63, 0xdc, 0x30, 0xf1, 0xf9, 0x38, 0x28, 0x5d, 0xb4, + 0x46, 0x2d, 0x95, 0x48, 0x17, 0x31, 0xbb, 0xe5, 0x55, 0x93, 0xf6, 0x57, 0xf3, 0x21, 0xc8, 0x0b, + 0xe3, 0x13, 0xf4, 0x12, 0xac, 0x86, 0x93, 0x71, 0x5e, 0x82, 0x57, 0xe2, 0x31, 0x12, 0x6d, 0xb2, + 0xf5, 0x96, 0x81, 0x9b, 0x8a, 0x37, 0x05, 0xf9, 0x85, 0xd9, 0x09, 0xf6, 0x62, 0x45, 0xcc, 0x2f, + 0xe9, 0x01, 0xc8, 0xb1, 0xb6, 0x46, 0x9a, 0xb8, 0x28, 0xd7, 0xfa, 0x9d, 0x14, 0xe4, 0x85, 0xfb, + 0x88, 0x64, 0x0a, 0x74, 0x22, 0x7d, 0xa3, 0x9d, 0xb8, 0xf9, 0x26, 0xe9, 0x3e, 0x40, 0x54, 0x53, + 0x94, 0xab, 0xa6, 0xa3, 0x1b, 0x2d, 0x85, 0x8d, 0x05, 0xbf, 0x37, 0x48, 0xdf, 0x5c, 0xa1, 0x2f, + 0xd6, 0x48, 0xf9, 0x3d, 0xa7, 0xa0, 0xe8, 0xcb, 0x72, 0xa1, 0x31, 0xc8, 0x5c, 0xc2, 0xd7, 0x2a, + 0x23, 0xa8, 0x08, 0x63, 0x32, 0xa6, 0x39, 0x82, 0x4a, 0xea, 0xec, 0x1b, 0x63, 0x30, 0x31, 0xdf, + 0x58, 0x58, 0x9e, 0xef, 0x76, 0xdb, 0x3a, 0xbf, 0x4f, 0x77, 0x19, 0xb2, 0x74, 0x9d, 0x9c, 0x60, + 0x7f, 0xa7, 0x9a, 0x24, 0xe1, 0x84, 0x64, 0x18, 0xa5, 0xcb, 0x69, 0x94, 0x64, 0xdb, 0xa7, 0x9a, + 0x28, 0x0f, 0x45, 0x1a, 0x49, 0x15, 0x2e, 0xc1, 0x6e, 0x50, 0x35, 0x49, 0x72, 0x0a, 0xfd, 0x0c, + 0x14, 0xbc, 0x75, 0x72, 0xd2, 0x3d, 0xa2, 0x6a, 0xe2, 0xb4, 0x15, 0xc1, 0xf7, 0x56, 0x06, 0x49, + 0xb7, 0x26, 0xaa, 0x89, 0xf3, 0x35, 0xe8, 0x39, 0x18, 0x13, 0x6b, 0xb0, 0x64, 0xbb, 0x38, 0xd5, + 0x84, 0x29, 0x25, 0x32, 0x7c, 0x6c, 0xe9, 0x9c, 0x64, 0xab, 0xaa, 0x9a, 0x28, 0x6f, 0x86, 0x36, + 0x21, 0xc7, 0x83, 0xdf, 0x44, 0x3b, 0x3d, 0xd5, 0x64, 0x89, 0x22, 0x22, 0x64, 0x2f, 0x39, 0x91, + 0x74, 0x7b, 0xae, 0x9a, 0x38, 0x61, 0x88, 0x54, 0x00, 0xdf, 0x7a, 0x3a, 0xf1, 0xbe, 0x5b, 0x35, + 0x79, 0x22, 0x10, 0x7d, 0x10, 0xf2, 0xee, 0xaa, 0x29, 0xe1, 0x4e, 0x5a, 0x35, 0x69, 0x2e, 0xae, + 0xb1, 0x99, 0xf8, 0x94, 0xc4, 0xbd, 0xb1, 0xa7, 0x24, 0xbc, 0x4d, 0x6e, 0x77, 0x1b, 0xfc, 0x2f, + 0x53, 0x70, 0x3c, 0xbc, 0x9d, 0xac, 0x1a, 0xfb, 0x03, 0x0e, 0x04, 0x0c, 0x38, 0x2d, 0xf2, 0x38, + 0x64, 0xe6, 0x8d, 0x7d, 0x12, 0x6c, 0xd0, 0x6f, 0xfb, 0xf5, 0xac, 0xb6, 0x48, 0xd3, 0x91, 0xe7, + 0x4d, 0xab, 0x1d, 0x7d, 0x6a, 0xa4, 0x9e, 0xfd, 0xfe, 0xe7, 0x6a, 0x23, 0x8d, 0xdd, 0x88, 0x5e, + 0xc5, 0x9c, 0x15, 0xc8, 0xcf, 0x1b, 0xfb, 0xe2, 0x98, 0xc0, 0x28, 0xed, 0xd0, 0x61, 0xb7, 0xff, + 0x5f, 0x2f, 0x11, 0x64, 0xdf, 0xf7, 0x81, 0x79, 0x8f, 0x73, 0xec, 0x69, 0xc0, 0x0e, 0x7f, 0xfc, + 0x89, 0x81, 0xea, 0x60, 0x69, 0x4a, 0x17, 0x20, 0xbb, 0x60, 0xea, 0x34, 0xe4, 0x69, 0x62, 0xc3, + 0xec, 0x88, 0x9c, 0x27, 0x7d, 0x40, 0xa7, 0x20, 0xa7, 0x76, 0xcc, 0x9e, 0xe1, 0x88, 0xa8, 0x99, + 0xb8, 0x92, 0xff, 0x7a, 0x50, 0xcb, 0x2c, 0x1b, 0x8e, 0xcc, 0x5f, 0xd5, 0xb3, 0xdf, 0x7d, 0xb5, + 0x96, 0x92, 0x9e, 0x82, 0xb1, 0x45, 0xac, 0xdd, 0x08, 0xd6, 0x22, 0xd6, 0x42, 0x58, 0xa7, 0x21, + 0xbf, 0x6c, 0x38, 0xec, 0xa3, 0x61, 0xb7, 0x41, 0x46, 0x37, 0xd8, 0xb6, 0x48, 0xa8, 0x7e, 0x52, + 0x4e, 0x48, 0x17, 0xb1, 0xe6, 0x92, 0x36, 0xb1, 0x16, 0x26, 0x25, 0xf0, 0xa4, 0x5c, 0x6a, 0x40, + 0xe9, 0x8a, 0xda, 0xe6, 0xe1, 0x1e, 0xb6, 0xd1, 0x7d, 0x50, 0x50, 0xc5, 0x03, 0x5d, 0x59, 0x95, + 0x1a, 0xe5, 0x1f, 0x1c, 0xd4, 0xc0, 0x23, 0x92, 0x3d, 0x82, 0x7a, 0xf6, 0xe5, 0xff, 0x76, 0x32, + 0x25, 0x99, 0x30, 0x76, 0x41, 0xb5, 0xa9, 0xa5, 0x7f, 0x30, 0x90, 0x48, 0xa1, 0x91, 0x62, 0xe3, + 0xc8, 0xf5, 0x83, 0xda, 0xe4, 0xbe, 0xda, 0x69, 0xd7, 0x25, 0xef, 0x9d, 0xe4, 0xcf, 0xaf, 0xcc, + 0xf9, 0xf2, 0x2b, 0x34, 0x92, 0x6c, 0x4c, 0x5d, 0x3f, 0xa8, 0x4d, 0x78, 0x3c, 0xe4, 0x8d, 0xe4, + 0x26, 0x5d, 0xa4, 0x2e, 0xe4, 0x58, 0xd0, 0x1b, 0xb9, 0x43, 0xc8, 0x53, 0x3e, 0x69, 0x2f, 0xe5, + 0x53, 0x3f, 0x54, 0x9a, 0x81, 0xc7, 0x65, 0x8c, 0xa3, 0x9e, 0xfd, 0xc8, 0xab, 0xb5, 0x11, 0xc9, + 0x02, 0xb4, 0xae, 0x77, 0x7a, 0x6d, 0x76, 0xf1, 0x5b, 0x6c, 0x35, 0x3d, 0xc8, 0xda, 0x4d, 0xd3, + 0x49, 0x2c, 0x20, 0x9b, 0x98, 0xe3, 0x4a, 0xca, 0x05, 0xc2, 0xe2, 0x8c, 0x6f, 0x1e, 0xd4, 0x52, + 0xb4, 0xf5, 0x54, 0x46, 0x77, 0x41, 0x8e, 0x85, 0xf2, 0x3c, 0xfe, 0x29, 0x0b, 0x1e, 0xd6, 0x27, + 0x99, 0xbf, 0x95, 0x9e, 0x80, 0xb1, 0x55, 0xbb, 0xb5, 0x48, 0xba, 0x74, 0x1c, 0xf2, 0x1d, 0xbb, + 0xa5, 0xf8, 0xa2, 0xa9, 0xb1, 0x8e, 0xdd, 0xda, 0x18, 0x10, 0x85, 0xf1, 0x61, 0x79, 0x2f, 0xe4, + 0x36, 0xf6, 0x28, 0xfb, 0x29, 0x57, 0x4a, 0x19, 0x7f, 0x1b, 0x39, 0x7a, 0x80, 0xe9, 0xe7, 0x33, + 0x00, 0x1b, 0x7b, 0x6e, 0x0f, 0x07, 0x6c, 0xc1, 0x21, 0x09, 0x72, 0xce, 0x9e, 0x1b, 0x51, 0x17, + 0x1a, 0xf0, 0xda, 0x41, 0x2d, 0xb7, 0xb1, 0x47, 0x96, 0x17, 0x32, 0x7f, 0x13, 0x4c, 0x65, 0x65, + 0x42, 0xa9, 0x2c, 0x37, 0x81, 0x97, 0x8d, 0x48, 0xe0, 0x8d, 0xfa, 0x76, 0x00, 0x8e, 0xc1, 0x98, + 0xa5, 0x5e, 0x53, 0xc8, 0x88, 0xb2, 0xaf, 0x90, 0xe6, 0x2c, 0xf5, 0xda, 0x8a, 0xd9, 0x42, 0x0b, + 0x90, 0x6d, 0x9b, 0x2d, 0x91, 0x77, 0x3b, 0x2a, 0x3a, 0x45, 0x22, 0x2e, 0x7e, 0x9a, 0x78, 0xc5, + 0x6c, 0x35, 0x8e, 0x11, 0xf9, 0x7f, 0xf1, 0xcf, 0x6a, 0x13, 0xc1, 0x72, 0x5b, 0xa6, 0xcc, 0x6e, + 0x32, 0x30, 0x3f, 0x30, 0x19, 0x58, 0x18, 0x96, 0x0c, 0x84, 0x60, 0x32, 0xf0, 0x0e, 0xba, 0xa7, + 0xc9, 0xf6, 0x70, 0xa6, 0xfb, 0x82, 0xcf, 0x79, 0x63, 0x9f, 0xee, 0xa2, 0xde, 0x0a, 0x05, 0xf7, + 0xa0, 0x10, 0xff, 0xec, 0xb3, 0x57, 0xc0, 0xf5, 0xed, 0x23, 0x29, 0x28, 0x07, 0x5b, 0x4c, 0xf3, + 0x39, 0x76, 0x8b, 0x7f, 0x30, 0x95, 0xa5, 0x3d, 0x89, 0x52, 0x2c, 0x8b, 0x4c, 0x79, 0x48, 0xe7, + 0xe7, 0x43, 0x3a, 0x3f, 0x25, 0x04, 0xc4, 0xee, 0xee, 0x30, 0x55, 0x9f, 0xe6, 0xd2, 0x29, 0xf9, + 0x0a, 0x6d, 0x4f, 0xf5, 0xa9, 0x46, 0xfc, 0x2c, 0x14, 0x7d, 0x6f, 0x23, 0x83, 0xfa, 0x47, 0x22, + 0x92, 0x1d, 0x93, 0xee, 0x80, 0x88, 0x37, 0x62, 0x0b, 0xc1, 0x23, 0x75, 0x15, 0xb5, 0xe0, 0x12, + 0x25, 0x3d, 0x5e, 0xd1, 0x58, 0xfc, 0xd3, 0x6f, 0x9f, 0x18, 0x79, 0xf9, 0xb5, 0x13, 0x23, 0x03, + 0xcf, 0x67, 0x4a, 0xf1, 0x5f, 0x98, 0x77, 0xbd, 0xcc, 0x47, 0xdf, 0x0f, 0xb7, 0x72, 0x1a, 0xdb, + 0x51, 0x77, 0x75, 0xa3, 0x25, 0xfe, 0x72, 0x77, 0x53, 0xe6, 0xbd, 0xe1, 0xa5, 0x37, 0xee, 0x76, + 0xde, 0xea, 0xa1, 0xb1, 0x6a, 0x94, 0x37, 0x94, 0x0e, 0xb2, 0x80, 0x56, 0xed, 0xd6, 0x82, 0x85, + 0xd9, 0xc7, 0x46, 0xf8, 0x3a, 0x29, 0x78, 0xd9, 0x87, 0xdb, 0xa8, 0x5b, 0xe6, 0x82, 0x7d, 0x71, + 0xbf, 0x1b, 0xed, 0xe5, 0x88, 0x02, 0x57, 0x84, 0x96, 0x00, 0x68, 0x7a, 0xc5, 0xb6, 0xbd, 0x64, + 0x5e, 0x2d, 0x8c, 0xb1, 0xe0, 0x52, 0xc8, 0xaa, 0x83, 0x6d, 0x31, 0xd6, 0x1e, 0x23, 0xfa, 0x10, + 0x4c, 0x75, 0x74, 0x43, 0xb1, 0x71, 0x7b, 0x5b, 0x69, 0xe2, 0x36, 0xfd, 0x14, 0x0b, 0xdf, 0xb8, + 0x2b, 0x34, 0x56, 0xb8, 0x63, 0xba, 0x2b, 0x7e, 0xcc, 0xe6, 0x96, 0x0d, 0xe7, 0xfa, 0x41, 0xad, + 0xca, 0xbc, 0x43, 0x04, 0xa4, 0x24, 0x4f, 0x76, 0x74, 0x63, 0x1d, 0xb7, 0xb7, 0x17, 0xdd, 0x32, + 0xf4, 0x12, 0x4c, 0x72, 0x0a, 0xd3, 0x4b, 0x7a, 0x10, 0xdb, 0x53, 0x6a, 0xac, 0x5e, 0x3f, 0xa8, + 0xcd, 0x30, 0xb4, 0x3e, 0x12, 0xe9, 0x07, 0x07, 0xb5, 0xfb, 0x13, 0xb4, 0x69, 0x5e, 0xd3, 0x84, + 0x7b, 0xac, 0xb8, 0x20, 0xbc, 0x84, 0xd4, 0xed, 0x25, 0xe8, 0x45, 0xdd, 0xa3, 0xe1, 0xba, 0xfb, + 0x48, 0x92, 0xd6, 0xed, 0x73, 0xcd, 0x5e, 0x06, 0x5f, 0xd4, 0x7d, 0x14, 0x72, 0xdd, 0xde, 0x96, + 0xd8, 0x45, 0x2b, 0xc8, 0xfc, 0x09, 0xcd, 0xfa, 0x37, 0xd2, 0x8a, 0x67, 0x4b, 0x62, 0x3c, 0x49, + 0xac, 0xe2, 0xa6, 0x39, 0x59, 0xec, 0x47, 0xa3, 0x8f, 0xaf, 0x66, 0xa0, 0xb2, 0x6a, 0xb7, 0x96, + 0x9a, 0xba, 0x73, 0x93, 0xd5, 0xab, 0x1b, 0x25, 0x1d, 0xea, 0xcd, 0x1a, 0x0b, 0xd7, 0x0f, 0x6a, + 0x65, 0x26, 0x9d, 0x9b, 0x29, 0x93, 0x0e, 0x4c, 0x78, 0x7a, 0xa9, 0x58, 0xaa, 0xc3, 0xdd, 0x53, + 0x63, 0x31, 0xa1, 0x06, 0x2e, 0x62, 0xed, 0xfa, 0x41, 0xed, 0x28, 0x6b, 0x59, 0x08, 0x4a, 0x92, + 0xcb, 0x5a, 0x60, 0x2e, 0xa0, 0xbd, 0x68, 0xc5, 0xa7, 0xfb, 0x4f, 0x8d, 0x8b, 0x6f, 0xa3, 0xd2, + 0xf3, 0xa1, 0xfb, 0x4a, 0x1a, 0x8a, 0xc4, 0xd5, 0xb3, 0x72, 0x1c, 0x3d, 0x15, 0x52, 0x3f, 0xc2, + 0xa9, 0x90, 0x7e, 0x67, 0xa6, 0xc2, 0x3d, 0x6e, 0xac, 0x9d, 0x19, 0xa8, 0xf3, 0xc1, 0x90, 0xfb, + 0x3f, 0x66, 0xa8, 0x55, 0xa5, 0x2b, 0x48, 0x19, 0x37, 0xdf, 0x0d, 0x02, 0xfc, 0x85, 0x14, 0x1c, + 0xf1, 0xc4, 0x63, 0x5b, 0x5a, 0x48, 0x8a, 0xcf, 0x5c, 0x3f, 0xa8, 0xdd, 0x1a, 0x96, 0xa2, 0x8f, + 0xec, 0x06, 0x24, 0x39, 0xe5, 0x02, 0xad, 0x5b, 0x5a, 0x74, 0x3b, 0x9a, 0xb6, 0xe3, 0xb6, 0x23, + 0x33, 0xb8, 0x1d, 0x3e, 0xb2, 0xb7, 0xd4, 0x8e, 0x45, 0xdb, 0xe9, 0x1f, 0xd4, 0x6c, 0xc2, 0x41, + 0xfd, 0x5a, 0x1a, 0xc6, 0x57, 0xed, 0xd6, 0xa6, 0xd1, 0xfc, 0xc9, 0x84, 0x38, 0xec, 0x84, 0xf8, + 0x58, 0x0a, 0xca, 0x17, 0x75, 0xdb, 0x31, 0x2d, 0x5d, 0x53, 0xdb, 0x74, 0x35, 0xe3, 0x9d, 0x91, + 0x4c, 0x1d, 0xfe, 0x8c, 0xe4, 0x23, 0x90, 0xbb, 0xaa, 0xb6, 0xd9, 0xbf, 0x2b, 0xca, 0xd0, 0x3d, + 0xc2, 0x90, 0xef, 0x08, 0xe7, 0x80, 0x39, 0x39, 0x6f, 0xce, 0xef, 0xa6, 0x61, 0x22, 0x14, 0x78, + 0xa0, 0x06, 0x64, 0xa9, 0x45, 0x67, 0x0b, 0xde, 0xb9, 0x43, 0xc4, 0x15, 0x64, 0x4d, 0x4c, 0x79, + 0xd1, 0x4f, 0x41, 0xbe, 0xa3, 0xee, 0x31, 0xcf, 0xc0, 0xd6, 0x37, 0xf3, 0x87, 0xc3, 0xf1, 0x56, + 0xaf, 0x02, 0x47, 0x92, 0xc7, 0x3a, 0xea, 0x1e, 0xf5, 0x07, 0x5d, 0x98, 0x20, 0xa5, 0xda, 0x8e, + 0x6a, 0xb4, 0xb0, 0xdf, 0xfd, 0x5c, 0x3c, 0x74, 0x25, 0x47, 0xbd, 0x4a, 0x7c, 0x70, 0x92, 0x3c, + 0xde, 0x51, 0xf7, 0x16, 0x68, 0x01, 0xa9, 0xb1, 0x9e, 0x7f, 0xe5, 0xd5, 0xda, 0x08, 0x95, 0xd8, + 0xbf, 0x4f, 0x01, 0x78, 0x12, 0x43, 0x1b, 0x50, 0x09, 0xb9, 0x2f, 0x71, 0xc6, 0x28, 0x36, 0xc0, + 0xf3, 0x16, 0xb6, 0x13, 0x5a, 0x68, 0x08, 0x3e, 0x08, 0x45, 0x76, 0x4a, 0x40, 0xa1, 0xc9, 0xf8, + 0x74, 0x6c, 0x32, 0xfe, 0x04, 0xc1, 0xba, 0x7e, 0x50, 0x43, 0xac, 0x3b, 0x3e, 0x66, 0x89, 0xa6, + 0xe8, 0x81, 0x95, 0x10, 0x86, 0x60, 0x5f, 0x8a, 0xbe, 0xd8, 0x82, 0x9e, 0x3d, 0x33, 0x0d, 0x7d, + 0x17, 0x5b, 0xee, 0x1a, 0x99, 0x3d, 0xa2, 0x2a, 0xe4, 0xd9, 0x57, 0x05, 0x9d, 0x7d, 0xf1, 0xef, + 0x2a, 0xc4, 0x33, 0xe1, 0xba, 0x86, 0xb7, 0x6c, 0x5d, 0x8c, 0x82, 0x2c, 0x1e, 0xd1, 0x79, 0xa8, + 0xd8, 0x58, 0xeb, 0x59, 0xba, 0xb3, 0xaf, 0x68, 0xa6, 0xe1, 0xa8, 0x9a, 0xc3, 0x9d, 0xf6, 0x2d, + 0xd7, 0x0f, 0x6a, 0xc7, 0x58, 0x5b, 0xc3, 0x14, 0x92, 0x3c, 0x21, 0x8a, 0x16, 0x58, 0x09, 0xa9, + 0xa1, 0x89, 0x1d, 0x55, 0x6f, 0xdb, 0x7c, 0x61, 0x2b, 0x1e, 0x7d, 0x7d, 0xf9, 0x9d, 0x31, 0xff, + 0x66, 0xd4, 0x35, 0xa8, 0x98, 0x5d, 0x6c, 0x45, 0xd8, 0xa3, 0x15, 0xaf, 0xe6, 0x30, 0xc5, 0x0d, + 0x98, 0x84, 0x09, 0x81, 0x21, 0x2c, 0xc2, 0xf9, 0xc0, 0x99, 0x33, 0x16, 0x37, 0xa6, 0xc3, 0x5d, + 0x0e, 0x53, 0x48, 0xfe, 0x83, 0x66, 0x2c, 0xba, 0x3c, 0x0a, 0xb9, 0x17, 0x54, 0xbd, 0x2d, 0x3e, + 0xb5, 0x2a, 0xf3, 0x27, 0xb4, 0x0c, 0x39, 0xdb, 0x51, 0x9d, 0x1e, 0x0b, 0xbd, 0x47, 0x1b, 0xef, + 0x49, 0xd8, 0xe6, 0x86, 0x69, 0x34, 0xd7, 0x29, 0xa3, 0xcc, 0x01, 0xd0, 0x79, 0xc8, 0x39, 0xe6, + 0x2e, 0x36, 0xb8, 0x50, 0x0f, 0x35, 0xd3, 0x69, 0xa2, 0x8e, 0x71, 0x23, 0x07, 0x3c, 0xa3, 0xac, + 0xd8, 0x3b, 0xaa, 0x85, 0x6d, 0x16, 0x2a, 0x37, 0x96, 0x0f, 0x3d, 0x1d, 0x8f, 0x85, 0x3d, 0x05, + 0xc3, 0x93, 0xe4, 0x09, 0xb7, 0x68, 0x9d, 0x96, 0x84, 0x23, 0xe7, 0xb1, 0x1b, 0x8a, 0x9c, 0xcf, + 0x43, 0xa5, 0x67, 0x6c, 0x99, 0x06, 0xfd, 0x2c, 0x22, 0x4f, 0xd3, 0xe4, 0x4f, 0xa6, 0x66, 0x33, + 0xfe, 0xd1, 0x0a, 0x53, 0x48, 0xf2, 0x84, 0x5b, 0xc4, 0x4f, 0x3f, 0x36, 0xa1, 0xec, 0x51, 0xd1, + 0x29, 0x5b, 0x88, 0x9d, 0xb2, 0xb7, 0xf3, 0x29, 0x7b, 0x24, 0x5c, 0x8b, 0x37, 0x6b, 0xc7, 0xdd, + 0x42, 0xc2, 0x86, 0xde, 0x1f, 0x58, 0x46, 0x02, 0xaf, 0x61, 0xa0, 0x95, 0x49, 0xbe, 0x82, 0x2c, + 0xbe, 0x23, 0x2b, 0xc8, 0x7a, 0xe9, 0x23, 0xaf, 0xd6, 0x46, 0xdc, 0x09, 0xfb, 0x4b, 0x69, 0xc8, + 0x2d, 0x5e, 0xa1, 0xd7, 0x28, 0x7f, 0x4c, 0xc3, 0x07, 0x9f, 0xf5, 0x7a, 0x1f, 0x8c, 0x31, 0x59, + 0xd8, 0xe8, 0x2c, 0x8c, 0x76, 0xc9, 0x0f, 0x9e, 0x6b, 0x3c, 0xda, 0xa7, 0xd2, 0x94, 0x4e, 0xac, + 0x30, 0x29, 0xa9, 0xf4, 0xf9, 0x0c, 0xc0, 0xe2, 0x95, 0x2b, 0x1b, 0x96, 0xde, 0x6d, 0x63, 0xe7, + 0x27, 0xe1, 0xf5, 0xbb, 0x27, 0xbc, 0xf6, 0x8d, 0xf1, 0xd3, 0x50, 0xf4, 0xc6, 0xc8, 0x46, 0x8f, + 0x43, 0xde, 0xe1, 0xbf, 0xf9, 0x50, 0x57, 0xfb, 0x87, 0x5a, 0x90, 0xf3, 0xe1, 0x76, 0x39, 0xa4, + 0xff, 0x92, 0x06, 0x88, 0x4b, 0xce, 0xfc, 0x18, 0x04, 0xe0, 0xe7, 0x21, 0xc7, 0x3d, 0x4e, 0xe6, + 0x86, 0xa2, 0x55, 0xce, 0xed, 0x1b, 0xa5, 0x6f, 0xa7, 0x61, 0x6a, 0x53, 0x98, 0xdd, 0x9f, 0x48, + 0x18, 0x5d, 0x84, 0x31, 0x6c, 0x38, 0x96, 0x8e, 0x45, 0x1a, 0x7c, 0x36, 0xac, 0xa5, 0x11, 0xd2, + 0xa2, 0xff, 0x2e, 0x41, 0x9c, 0x96, 0xe3, 0xec, 0x3e, 0x19, 0x7f, 0x3c, 0x03, 0x33, 0x83, 0xb8, + 0xd0, 0x02, 0x4c, 0x68, 0x16, 0xa6, 0x05, 0x8a, 0x7f, 0xe7, 0xa4, 0x51, 0xf5, 0x65, 0x8c, 0x82, + 0x04, 0x92, 0x5c, 0x16, 0x25, 0xdc, 0x21, 0xb7, 0x68, 0x82, 0x8a, 0x4c, 0x15, 0x42, 0x95, 0x30, + 0x88, 0x96, 0xb8, 0x47, 0xf6, 0xd2, 0x52, 0x7e, 0x00, 0xe6, 0x92, 0xcb, 0x5e, 0x29, 0xf5, 0xc9, + 0x2f, 0xc2, 0x84, 0x6e, 0xe8, 0x8e, 0xae, 0xb6, 0x95, 0x2d, 0xb5, 0xad, 0x1a, 0xda, 0x8d, 0x2c, + 0x45, 0x98, 0x37, 0xe5, 0xd5, 0x86, 0xe0, 0x24, 0xb9, 0xcc, 0x4b, 0x1a, 0xac, 0x80, 0x8c, 0x88, + 0xa8, 0x2a, 0x7b, 0x43, 0x81, 0x9b, 0x60, 0xf7, 0x8d, 0xc8, 0x2f, 0x67, 0x60, 0xd2, 0xcd, 0xcf, + 0xfc, 0x64, 0x28, 0x92, 0x0e, 0xc5, 0x2a, 0x00, 0x33, 0x20, 0xc4, 0x73, 0xdc, 0xc0, 0x68, 0x10, + 0x13, 0x54, 0x60, 0x08, 0x8b, 0xb6, 0xe3, 0x1b, 0x8f, 0xbf, 0xc8, 0x40, 0xc9, 0x3f, 0x1e, 0x3f, + 0x71, 0xe9, 0xef, 0xa2, 0x8c, 0xd9, 0xbc, 0x67, 0x12, 0xb3, 0xfc, 0xbb, 0x28, 0x21, 0x93, 0xd8, + 0x37, 0x95, 0x06, 0xdb, 0xc2, 0xbf, 0x4a, 0x43, 0x8e, 0x9f, 0xcb, 0xd6, 0xfa, 0x56, 0x11, 0xa9, + 0xb8, 0x73, 0xdf, 0xc3, 0x17, 0x11, 0xaf, 0x44, 0x2e, 0x22, 0xca, 0x1d, 0x75, 0x4f, 0x09, 0xdc, + 0x62, 0x4a, 0xcd, 0x8e, 0x37, 0x8e, 0x7b, 0x28, 0xc1, 0xf7, 0x2c, 0x17, 0xe2, 0x9d, 0xc9, 0x45, + 0x8f, 0x40, 0x91, 0x50, 0x78, 0x5e, 0x81, 0xb0, 0x1f, 0xf5, 0x92, 0x0f, 0xbe, 0x97, 0x92, 0x0c, + 0x1d, 0x75, 0x6f, 0x89, 0x3d, 0xa0, 0x15, 0x40, 0x3b, 0x6e, 0xea, 0x4b, 0xf1, 0x44, 0x48, 0xf8, + 0x6f, 0xbb, 0x7e, 0x50, 0x3b, 0xce, 0xf8, 0xfb, 0x69, 0x24, 0x79, 0xd2, 0x2b, 0x14, 0x68, 0x0f, + 0x02, 0x90, 0x7e, 0x29, 0xec, 0x4c, 0x08, 0x5b, 0xc2, 0xfa, 0x0e, 0x4a, 0x78, 0xef, 0x24, 0xb9, + 0x40, 0x1e, 0x16, 0xc9, 0x6f, 0x9f, 0xe0, 0x7f, 0x25, 0x05, 0xc8, 0xf3, 0x3d, 0xee, 0x7e, 0xfd, + 0xfb, 0xe9, 0xbd, 0x44, 0xb1, 0x32, 0x4a, 0x45, 0x2f, 0xb2, 0x3c, 0x3e, 0xb1, 0xc8, 0xf2, 0x4d, + 0xd5, 0xfb, 0x3c, 0xfb, 0x9c, 0x1e, 0x98, 0x15, 0x8c, 0xb0, 0xc1, 0xff, 0x3a, 0x05, 0xc7, 0xfb, + 0x14, 0xc7, 0x6d, 0xd7, 0x15, 0x40, 0x96, 0xef, 0x25, 0xff, 0x0f, 0x45, 0x29, 0xfe, 0x1f, 0xff, + 0x12, 0xea, 0xdf, 0xa4, 0xd5, 0x67, 0xe3, 0x6f, 0x9e, 0x37, 0xe1, 0x19, 0xc5, 0x14, 0x4c, 0xfb, + 0xab, 0x77, 0x3b, 0x70, 0x1e, 0x4a, 0xfe, 0xda, 0x79, 0xd3, 0x6f, 0x1d, 0xd6, 0x74, 0xde, 0xea, + 0x00, 0x1f, 0x5a, 0xf6, 0x66, 0x9f, 0xf8, 0xa7, 0x93, 0x71, 0xbd, 0x77, 0x0f, 0xb2, 0x85, 0x66, + 0x21, 0x6b, 0xf1, 0xff, 0x4b, 0x41, 0x76, 0xcd, 0x34, 0xdb, 0xc8, 0x84, 0x49, 0xc3, 0x74, 0x14, + 0xa2, 0x2c, 0xb8, 0xa9, 0xf0, 0xdc, 0x08, 0xcb, 0x82, 0x2e, 0x1c, 0x4e, 0x28, 0xdf, 0x3b, 0xa8, + 0xf5, 0x43, 0xc9, 0x13, 0x86, 0xe9, 0x34, 0x68, 0xc9, 0x06, 0xcb, 0x9c, 0x7c, 0x08, 0xc6, 0x83, + 0x95, 0xb1, 0x4c, 0xd1, 0xb3, 0x87, 0xae, 0x2c, 0x08, 0x73, 0xfd, 0xa0, 0x36, 0xed, 0x4d, 0x02, + 0xb7, 0x58, 0x92, 0x4b, 0x5b, 0xbe, 0xda, 0xeb, 0x79, 0xd2, 0xfb, 0xef, 0xbf, 0x5a, 0x4b, 0x35, + 0xce, 0x0f, 0x3c, 0x01, 0x70, 0xdf, 0xd0, 0x26, 0xec, 0xb9, 0x5b, 0xfd, 0xc1, 0xb3, 0x00, 0xdf, + 0x3d, 0x03, 0xd5, 0xd0, 0x59, 0x00, 0x7a, 0x0f, 0x79, 0xc0, 0x49, 0x80, 0xe1, 0xff, 0xc0, 0x7f, + 0xc0, 0x41, 0x81, 0xa1, 0x87, 0x0d, 0xa4, 0x5d, 0x38, 0x4a, 0x8f, 0x72, 0x7a, 0x66, 0x4b, 0x7c, + 0x25, 0xe6, 0xa8, 0x9b, 0x40, 0x4b, 0xf1, 0xff, 0x17, 0xce, 0xb2, 0x61, 0x8f, 0x01, 0x78, 0x35, + 0xbb, 0x17, 0x6e, 0x78, 0x4b, 0x59, 0xeb, 0xd9, 0x3f, 0xf2, 0xa7, 0x30, 0xb2, 0x8f, 0x58, 0xfa, + 0xf5, 0x14, 0x1c, 0xeb, 0xab, 0x8d, 0x6b, 0xfd, 0x93, 0x81, 0x0b, 0xa3, 0xa9, 0x64, 0x39, 0x7a, + 0xff, 0x97, 0x1f, 0xea, 0x11, 0xed, 0xaa, 0x46, 0xb5, 0x8b, 0x55, 0x18, 0x68, 0xd8, 0x8b, 0x70, + 0x24, 0xd8, 0x2e, 0x21, 0x84, 0xe7, 0xa0, 0x1c, 0x5c, 0x2d, 0xf0, 0x50, 0xe2, 0x3d, 0x87, 0xf7, + 0x90, 0xe3, 0x81, 0x15, 0x83, 0xf4, 0x6c, 0x58, 0xf0, 0xae, 0x24, 0xde, 0xd7, 0x7f, 0xf8, 0x3e, + 0x56, 0x10, 0xbe, 0xbb, 0x59, 0x5f, 0x49, 0xc1, 0xc9, 0x20, 0xb2, 0x67, 0x84, 0xed, 0xb7, 0xbd, + 0x5f, 0x6f, 0x45, 0x3d, 0xfe, 0x53, 0x0a, 0x6e, 0x1f, 0xd2, 0x72, 0x2e, 0x1e, 0x0b, 0xa6, 0x7d, + 0xd6, 0xdd, 0xe2, 0xc5, 0x42, 0x65, 0xa4, 0xc1, 0x1e, 0xc8, 0x35, 0x6e, 0xb7, 0xf0, 0xa3, 0x48, + 0x53, 0xfd, 0xef, 0x6c, 0x79, 0xaa, 0xdf, 0x22, 0xbf, 0x35, 0xdd, 0xfa, 0x7a, 0x0a, 0x4e, 0x07, + 0x7b, 0x15, 0xb1, 0xa2, 0x7b, 0x77, 0x0f, 0xcc, 0xbf, 0x49, 0xc1, 0x3d, 0x49, 0xba, 0xc0, 0x47, + 0xe8, 0x79, 0x98, 0xf2, 0xe2, 0xab, 0xf0, 0x00, 0x9d, 0x4a, 0xb0, 0x2a, 0xe6, 0x4a, 0x8d, 0x5c, + 0x94, 0x9b, 0x33, 0x12, 0x7f, 0x9c, 0xe2, 0x73, 0xce, 0x3f, 0xee, 0xae, 0xd8, 0x83, 0x4b, 0x82, + 0x43, 0x8a, 0xdd, 0xb7, 0x2c, 0x18, 0x0f, 0x2c, 0x0b, 0x22, 0x06, 0x34, 0x7d, 0x93, 0x2c, 0xc8, + 0x2f, 0x0a, 0x6b, 0x1a, 0x11, 0x9c, 0xed, 0xc2, 0x54, 0xc4, 0x24, 0x71, 0x6f, 0x9c, 0xc6, 0xcf, + 0x91, 0xa3, 0x3f, 0x38, 0xa8, 0x45, 0x44, 0x7d, 0x32, 0xea, 0x9f, 0x1e, 0xd2, 0x7f, 0x4e, 0x41, + 0x8d, 0x36, 0x24, 0x62, 0x28, 0xff, 0x26, 0x0b, 0x18, 0x73, 0x43, 0x1a, 0xd9, 0x2d, 0x2e, 0xe8, + 0x79, 0xc8, 0x31, 0x2d, 0xe5, 0xb2, 0x3d, 0x84, 0x7a, 0x73, 0x46, 0xcf, 0x60, 0x2f, 0x8a, 0x7e, + 0x45, 0xdb, 0x85, 0xb7, 0x49, 0x7e, 0x6f, 0xc1, 0x2e, 0xfc, 0x2b, 0x61, 0xb0, 0xa3, 0x5b, 0xce, + 0x45, 0xf4, 0xc1, 0xb7, 0x6c, 0xb0, 0xf9, 0x97, 0x84, 0xde, 0x36, 0xcb, 0xec, 0x36, 0x3f, 0xc6, + 0x32, 0xbf, 0xfb, 0x46, 0xc0, 0xb5, 0xcc, 0x31, 0x5d, 0x78, 0x97, 0x5b, 0xe6, 0xeb, 0x69, 0x38, + 0x4e, 0xbb, 0xe1, 0x5f, 0x91, 0xbc, 0x03, 0x92, 0x57, 0x00, 0xd9, 0x96, 0xa6, 0xdc, 0x2c, 0xfb, + 0x51, 0xb1, 0x2d, 0xed, 0x4a, 0xc0, 0xe9, 0x2a, 0x80, 0x9a, 0xb6, 0x13, 0xae, 0x20, 0x73, 0xc3, + 0x15, 0x34, 0x6d, 0xe7, 0xca, 0x10, 0xaf, 0x9e, 0x3d, 0x8c, 0xee, 0xfc, 0x61, 0x0a, 0xaa, 0x51, + 0x42, 0xe7, 0xba, 0xa2, 0xc2, 0xd1, 0xc0, 0x3a, 0x3a, 0xac, 0x2e, 0x77, 0x0c, 0x5b, 0x4d, 0x86, + 0xa6, 0xee, 0x11, 0x0b, 0xdf, 0xec, 0xc9, 0xfb, 0x65, 0xe1, 0x74, 0x5c, 0xcd, 0xef, 0x5f, 0xc2, + 0xbc, 0x2b, 0xa7, 0xec, 0x6f, 0xf5, 0x99, 0xfb, 0x77, 0xdb, 0x6a, 0xe8, 0x4f, 0x52, 0x70, 0x62, + 0x40, 0x0b, 0xff, 0x26, 0xbb, 0xf3, 0x9f, 0x1d, 0xa8, 0x30, 0x37, 0x6b, 0xe9, 0xf5, 0x20, 0x9f, + 0x50, 0xc1, 0x73, 0x6b, 0xbe, 0x05, 0x75, 0xe4, 0x37, 0xe6, 0x9e, 0x81, 0x5b, 0x22, 0xb9, 0x78, + 0x9b, 0xce, 0x42, 0x76, 0x47, 0xb7, 0x1d, 0xf7, 0xc3, 0x0b, 0xa1, 0xe6, 0x84, 0xb8, 0x28, 0xad, + 0x84, 0xa0, 0x42, 0x21, 0xd7, 0x4c, 0xb3, 0xcd, 0xab, 0x97, 0x16, 0x60, 0xd2, 0x57, 0xc6, 0xc1, + 0xe7, 0x20, 0xdb, 0x35, 0xcd, 0x36, 0x07, 0x9f, 0x0e, 0x83, 0x13, 0x5a, 0xde, 0x4d, 0x4a, 0x27, + 0x4d, 0x03, 0x62, 0x20, 0xec, 0x93, 0x20, 0x1c, 0xfa, 0xc3, 0x29, 0x98, 0x0a, 0x14, 0xbb, 0x97, + 0x96, 0x72, 0x81, 0xaf, 0x49, 0xf5, 0x6d, 0xd1, 0x33, 0x7a, 0xf7, 0x7a, 0x3a, 0xcb, 0xee, 0xbe, + 0x05, 0xd5, 0x3d, 0xfb, 0x47, 0x25, 0x71, 0xcb, 0x55, 0x01, 0xf0, 0xa5, 0x62, 0xef, 0x0a, 0xd7, + 0x1c, 0x9d, 0xf4, 0xa8, 0xde, 0x1d, 0x4b, 0xc7, 0x63, 0xde, 0x11, 0xf4, 0x53, 0xfe, 0x63, 0x54, + 0x77, 0x0e, 0xe7, 0x13, 0xf0, 0x77, 0xc5, 0x91, 0xb9, 0xe8, 0x7f, 0x0b, 0xa6, 0xa3, 0x56, 0xc1, + 0xe8, 0x81, 0xe1, 0x08, 0xfd, 0x71, 0x4b, 0xf5, 0x3d, 0x87, 0xe0, 0x70, 0xab, 0x7f, 0x25, 0x05, + 0xb7, 0x0d, 0x5d, 0xec, 0xa1, 0xc7, 0x86, 0xc3, 0x0e, 0x89, 0xa4, 0xaa, 0xf5, 0x1b, 0x61, 0x75, + 0x9b, 0xa6, 0x04, 0xf6, 0xf3, 0xa3, 0x25, 0xda, 0xb7, 0xfe, 0x18, 0x30, 0xb0, 0xfd, 0xb1, 0xa6, + 0x34, 0x82, 0x5e, 0x8a, 0xde, 0xd7, 0x3e, 0x13, 0x89, 0x30, 0x78, 0xc9, 0x53, 0x7d, 0x20, 0x39, + 0x83, 0x7f, 0xd8, 0xa3, 0x62, 0xe9, 0x01, 0xc3, 0x3e, 0x64, 0xc1, 0x30, 0x60, 0xd8, 0x87, 0x05, + 0xea, 0x7c, 0xd8, 0x87, 0x46, 0x92, 0x03, 0x86, 0x3d, 0x49, 0x00, 0x3d, 0x60, 0xd8, 0x13, 0x05, + 0xae, 0xd2, 0x08, 0xda, 0x81, 0xf1, 0x40, 0x9c, 0x82, 0x4e, 0x47, 0xc2, 0x45, 0x05, 0x90, 0xd5, + 0x7b, 0x92, 0x90, 0xfa, 0xc7, 0x3f, 0xc2, 0x35, 0x0f, 0x18, 0xff, 0xc1, 0xd1, 0x47, 0xf5, 0x81, + 0xe4, 0x0c, 0x6e, 0xdd, 0xd7, 0xdc, 0xad, 0x16, 0x1f, 0x01, 0x9a, 0x4b, 0x88, 0x24, 0x6a, 0x3e, + 0x93, 0x98, 0xde, 0xad, 0x78, 0xb7, 0xef, 0xb4, 0x75, 0xb4, 0xd0, 0x22, 0x5d, 0x5b, 0xf5, 0xde, + 0x44, 0xb4, 0x6e, 0x65, 0xab, 0x7c, 0x1f, 0xe1, 0x64, 0x24, 0x9b, 0xcf, 0x69, 0x55, 0x6f, 0x1f, + 0x42, 0xe1, 0xc2, 0xad, 0xbb, 0x1b, 0x83, 0x52, 0x34, 0xb9, 0xdf, 0x59, 0x55, 0x4f, 0x0d, 0xa5, + 0x11, 0xa0, 0x37, 0x3d, 0xd5, 0xff, 0xa5, 0x7c, 0xdf, 0xb5, 0xbf, 0x16, 0x36, 0xb0, 0xad, 0xdb, + 0x87, 0xba, 0xf6, 0x37, 0x3c, 0x9b, 0xff, 0x8b, 0x39, 0x28, 0x5d, 0x60, 0xa8, 0xf4, 0x5b, 0xc7, + 0xe8, 0x89, 0x84, 0x1e, 0xb8, 0x4c, 0x3c, 0xf0, 0x0f, 0x0e, 0x6a, 0x5c, 0x90, 0xae, 0x2f, 0xb6, + 0xf9, 0x47, 0x8f, 0xd8, 0x07, 0x4b, 0xbc, 0xaf, 0xc6, 0x94, 0x0e, 0x75, 0x64, 0x95, 0x9d, 0x15, + 0xe0, 0xa7, 0x44, 0xc3, 0x78, 0x12, 0xfb, 0x7e, 0xd2, 0x06, 0x29, 0xa1, 0x9f, 0x3c, 0x41, 0x9f, + 0x4c, 0xc1, 0x11, 0x4a, 0xe5, 0x05, 0x82, 0x94, 0x52, 0x1c, 0xac, 0xe9, 0x1b, 0xe5, 0x15, 0xd5, + 0xb7, 0x2c, 0xa2, 0x18, 0x8d, 0x3a, 0xdf, 0xef, 0xbd, 0xd5, 0x57, 0x69, 0x18, 0x4e, 0xfa, 0xc1, + 0x41, 0x0d, 0xf5, 0xf3, 0xca, 0xf4, 0x03, 0x9d, 0xc1, 0xb2, 0xe8, 0xcf, 0x54, 0x0f, 0x89, 0x0d, + 0x27, 0xb9, 0x40, 0xbd, 0x18, 0x21, 0x10, 0x9e, 0xaf, 0x41, 0xd1, 0x67, 0x7c, 0x66, 0x46, 0x07, + 0x1c, 0x6b, 0xf3, 0xd6, 0xdd, 0x88, 0xe3, 0xf9, 0x7c, 0x9f, 0xec, 0x87, 0x40, 0xbf, 0x96, 0x82, + 0x23, 0xde, 0xda, 0xde, 0x0f, 0x9e, 0x4b, 0xbe, 0xba, 0x3f, 0x17, 0x94, 0x5a, 0x24, 0x1e, 0x91, + 0x5a, 0x94, 0x83, 0x94, 0xa7, 0x7b, 0x51, 0x0e, 0xe3, 0x39, 0x18, 0xf7, 0x2f, 0xfe, 0xbc, 0x8f, + 0x17, 0x0e, 0xdb, 0xce, 0x9c, 0xe6, 0xbd, 0x0d, 0x1c, 0xed, 0x90, 0x83, 0x40, 0xa8, 0x0a, 0x79, + 0xbc, 0xd7, 0x35, 0x2d, 0x07, 0x37, 0xe9, 0x59, 0xe4, 0xbc, 0xec, 0x3e, 0x4b, 0xd7, 0x20, 0x62, + 0x60, 0xd1, 0xd3, 0xa1, 0x2f, 0x2f, 0xdd, 0xc8, 0xa2, 0xa2, 0xff, 0x63, 0x4d, 0xfe, 0xaf, 0x28, + 0xdd, 0x6c, 0xb3, 0xf1, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x73, 0x3c, 0xb3, 0x75, 0xb7, 0x9b, + 0x00, 0x00, } r := bytes.NewReader(gzipped) gzipr, err := compress_gzip.NewReader(r) From f20b583787bb3b42c7314f89b32b1b0bf8819aef Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 29 Jul 2020 00:51:06 +0200 Subject: [PATCH 04/41] fix validation --- x/ibc-transfer/types/msgs.go | 28 +++++++++++++++++++++++++++- x/ibc-transfer/types/packet.go | 4 ++-- x/ibc-transfer/types/trace.go | 6 +++++- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/x/ibc-transfer/types/msgs.go b/x/ibc-transfer/types/msgs.go index ad352a2c8175..60f1df9d9678 100644 --- a/x/ibc-transfer/types/msgs.go +++ b/x/ibc-transfer/types/msgs.go @@ -1,6 +1,9 @@ package types import ( + "bytes" + fmt "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" @@ -14,13 +17,15 @@ const ( // NewMsgTransfer creates a new MsgTransfer instance func NewMsgTransfer( sourcePort, sourceChannel string, - amount sdk.Coins, sender sdk.AccAddress, receiver string, + amount sdk.Coins, trace DenomTrace, + sender sdk.AccAddress, receiver string, timeoutHeight, timeoutTimestamp uint64, ) *MsgTransfer { return &MsgTransfer{ SourcePort: sourcePort, SourceChannel: sourceChannel, Amount: amount, + Trace: trace, Sender: sender, Receiver: receiver, TimeoutHeight: timeoutHeight, @@ -53,6 +58,27 @@ func (msg MsgTransfer) ValidateBasic() error { if !msg.Amount.IsValid() { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } + if err := msg.Trace.Validate(); err != nil { + return err + } + // Only validate the ibc denomination when trace info is not provided + if msg.Trace.Trace != "" { + denomTraceHash, err := ValidateIBCDenom(msg.Amount[0].Denom) + if err != nil { + return err + } + traceHash := msg.Trace.Hash() + if !bytes.Equal(traceHash.Bytes(), denomTraceHash.Bytes()) { + return fmt.Errorf("token denomination trace hash mismatch, expected %s got %s", traceHash, denomTraceHash) + } + } else if msg.Trace.BaseDenom != msg.Amount[0].Denom { + // otherwise, validate that denominations are equal + return sdkerrors.Wrapf( + ErrInvalidDenomForTransfer, + "token denom must match the trace base denom (%s ≠ %s)", + msg.Amount, msg.Trace.BaseDenom, + ) + } if msg.Sender.Empty() { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") } diff --git a/x/ibc-transfer/types/packet.go b/x/ibc-transfer/types/packet.go index c5be13059595..9f407bc65896 100644 --- a/x/ibc-transfer/types/packet.go +++ b/x/ibc-transfer/types/packet.go @@ -46,7 +46,7 @@ func (ftpd FungibleTokenPacketData) ValidateBasic() error { return err } // Only validate the ibc denomination when trace info is not provided - if ftpd.Trace.Trace == "" { + if ftpd.Trace.Trace != "" { denomTraceHash, err := ValidateIBCDenom(ftpd.Amount[0].Denom) if err != nil { return err @@ -57,13 +57,13 @@ func (ftpd FungibleTokenPacketData) ValidateBasic() error { return fmt.Errorf("token denomination trace hash mismatch, expected %s got %s", traceHash, denomTraceHash) } } else if ftpd.Trace.BaseDenom != ftpd.Amount[0].Denom { + // otherwise, validate that denominations are equal return sdkerrors.Wrapf( ErrInvalidDenomForTransfer, "token denom must match the trace base denom (%s ≠ %s)", ftpd.Amount, ftpd.Trace.BaseDenom, ) } - if strings.TrimSpace(ftpd.Sender) == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be blank") } diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 13794b5b573f..8b0138572391 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -62,8 +62,12 @@ func (dt *DenomTrace) RemovePrefix() error { func (dt DenomTrace) validateTrace() error { // empty trace is accepted when token lives on the original chain - if dt.Trace == "" { + + switch { + case dt.Trace == "" && dt.BaseDenom != "": return nil + case strings.TrimSpace(dt.Trace == ""): + return fmt.Errorf("cannot have an empty trace and empty base denomination") } traceSplit := strings.Split(dt.Trace, "/") From fa9efa5e3e777d70344e924ee75350821d580d3e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 29 Jul 2020 11:48:53 +0200 Subject: [PATCH 05/41] import export genesis --- proto/ibc/transfer/genesis.proto | 2 +- proto/ibc/transfer/query.proto | 8 +- proto/ibc/transfer/transfer.proto | 13 +- x/ibc-transfer/genesis.go | 38 --- x/ibc-transfer/keeper/genesis.go | 42 +++ x/ibc-transfer/keeper/keeper.go | 42 ++- x/ibc-transfer/module.go | 10 +- x/ibc-transfer/types/genesis.pb.go | 26 +- x/ibc-transfer/types/query.pb.go | 56 ++-- x/ibc-transfer/types/trace.go | 21 +- x/ibc-transfer/types/transfer.pb.go | 417 ++++------------------------ 11 files changed, 200 insertions(+), 475 deletions(-) delete mode 100644 x/ibc-transfer/genesis.go create mode 100644 x/ibc-transfer/keeper/genesis.go diff --git a/proto/ibc/transfer/genesis.proto b/proto/ibc/transfer/genesis.proto index 5700f19d5ea7..7dbd8ddf191d 100644 --- a/proto/ibc/transfer/genesis.proto +++ b/proto/ibc/transfer/genesis.proto @@ -12,7 +12,7 @@ message GenesisState{ (gogoproto.customname) = "PortID", (gogoproto.moretags) = "yaml:\"port_id\"" ]; - repeated IdentifiedDenomTrace denom_traces = 2 [ + repeated DenomTrace denom_traces = 2 [ (gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"denom_traces\"" diff --git a/proto/ibc/transfer/query.proto b/proto/ibc/transfer/query.proto index f3d33ccee29c..a52f7594153d 100644 --- a/proto/ibc/transfer/query.proto +++ b/proto/ibc/transfer/query.proto @@ -1,6 +1,7 @@ syntax = "proto3"; package ibc.transfer; +import "gogoproto/gogo.proto"; import "cosmos/query/pagination.proto"; import "ibc/transfer/transfer.proto"; @@ -24,7 +25,7 @@ message QueryDenomTraceRequest { // QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC method. message QueryDenomTraceResponse { // denomination trace associated with the request hash - ibc.transfer.DenomTrace denom_trace = 1; + DenomTrace denom_trace = 1; } // QueryConnectionsRequest is the request type for the Query/Connections RPC method @@ -35,7 +36,10 @@ message QueryDenomTracesRequest { // QueryConnectionsResponse is the response type for the Query/Connections RPC method. message QueryDenomTracesResponse { // list of stored connections of the chain. - repeated ibc.transfer.IdentifiedDenomTrace denom_traces = 1; + repeated DenomTrace denom_traces = 1 [ + (gogoproto.castrepeated) = "Traces", + (gogoproto.nullable) = false + ]; // pagination response cosmos.query.PageResponse pagination = 2; } diff --git a/proto/ibc/transfer/transfer.proto b/proto/ibc/transfer/transfer.proto index 5478e6287152..442cb08c6546 100644 --- a/proto/ibc/transfer/transfer.proto +++ b/proto/ibc/transfer/transfer.proto @@ -23,7 +23,7 @@ message MsgTransfer { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; // fungible token denomination trace info for source tracking - DenomTrace trace = 4; + DenomTrace trace = 4 [(gogoproto.nullable) = false]; // the sender address bytes sender = 5 [ (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress" @@ -70,14 +70,3 @@ message DenomTrace { // base denomination of the relayed fungible token string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; } - - -// IdentifiedDenomTrace contains DenomTrace and the hash used for the IBC fungible denom map. -message IdentifiedDenomTrace { - // chain of port/channel identifiers used for tracing the source of the fungible token - string trace = 1; - // base denomination of the relayed fungible token - string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; - // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) - string hash = 3; -} diff --git a/x/ibc-transfer/genesis.go b/x/ibc-transfer/genesis.go deleted file mode 100644 index 99aaa4ea9fed..000000000000 --- a/x/ibc-transfer/genesis.go +++ /dev/null @@ -1,38 +0,0 @@ -package transfer - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc-transfer/keeper" - "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" -) - -// InitGenesis binds to portid from genesis state -func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { - keeper.SetPort(ctx, state.PortID) - - // Only try to bind to port if it is not already bound, since we may already own - // port capability from capability InitGenesis - if !keeper.IsBound(ctx, state.PortID) { - // transfer module binds to the transfer port on InitChain - // and claims the returned capability - err := keeper.BindPort(ctx, state.PortID) - if err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) - } - } - - // check if the module account exists - moduleAcc := keeper.GetTransferAccount(ctx) - if moduleAcc == nil { - panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) - } -} - -// ExportGenesis exports transfer module's portID into its geneis state -func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) types.GenesisState { - return types.GenesisState{ - PortID: keeper.GetPort(ctx), - } -} diff --git a/x/ibc-transfer/keeper/genesis.go b/x/ibc-transfer/keeper/genesis.go new file mode 100644 index 000000000000..a20235b90396 --- /dev/null +++ b/x/ibc-transfer/keeper/genesis.go @@ -0,0 +1,42 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" +) + +// InitGenesis initializes the ibc-transfer state and binds to PortID. +func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { + k.SetPort(ctx, state.PortID) + + for _, trace := range state.DenomTraces { + k.SetDenomTrace(ctx, trace) + } + + // Only try to bind to port if it is not already bound, since we may already own + // port capability from capability InitGenesis + if !k.IsBound(ctx, state.PortID) { + // transfer module binds to the transfer port on InitChain + // and claims the returned capability + err := k.BindPort(ctx, state.PortID) + if err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } + } + + // check if the module account exists + moduleAcc := k.GetTransferAccount(ctx) + if moduleAcc == nil { + panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) + } +} + +// ExportGenesis exports ibc-transfer module's portID and denom trace info into its genesis state. +func (k Keeper) ExportGenesis(ctx sdk.Context) types.GenesisState { + return types.GenesisState{ + PortID: k.GetPort(ctx), + DenomTraces: k.GetAllDenomTraces(ctx), + } +} diff --git a/x/ibc-transfer/keeper/keeper.go b/x/ibc-transfer/keeper/keeper.go index 6b063603b3c2..65f9b8ee604b 100644 --- a/x/ibc-transfer/keeper/keeper.go +++ b/x/ibc-transfer/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "fmt" + tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" @@ -111,11 +112,11 @@ func (k Keeper) SetPort(ctx sdk.Context, portID string) { } // GetDenomTrace retreives the full identifiers trace and base denomination from the store. -func (k Keeper) GetDenomTrace(ctx Context, denomTraceHash []byte) (types.DenomTrace, bool) { +func (k Keeper) GetDenomTrace(ctx sdk.Context, denomTraceHash []byte) (types.DenomTrace, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) - bz := store.Get(traceHash) + bz := store.Get(denomTraceHash) if bz == nil { - return &types.DenomTrace, false + return types.DenomTrace{}, false } var denomTrace types.DenomTrace @@ -124,16 +125,45 @@ func (k Keeper) GetDenomTrace(ctx Context, denomTraceHash []byte) (types.DenomTr } // HasDenomTrace checks if a the key with the given denomination trace hash exists on the store. -func (k Keeper) HasDenomTrace(ctx Context, denomTraceHash []byte) bool { +func (k Keeper) HasDenomTrace(ctx sdk.Context, denomTraceHash []byte) bool { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) return store.Has(denomTraceHash) } // SetDenomTrace sets a new {trace hash -> denom trace} pair to the store. -func (k Keeper) SetDenomTrace(ctx Context, denomTraceHash []byte, denomTrace types.DenomTrace) { +func (k Keeper) SetDenomTrace(ctx sdk.Context, denomTrace types.DenomTrace) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) bz := k.cdc.MustMarshalBinaryBare(&denomTrace) - store.Set(denomTraceHash, bz) + store.Set(denomTrace.Hash(), bz) +} + +// GetAllDenomTraces returns the trace information for all the denominations. +func (k Keeper) GetAllDenomTraces(ctx sdk.Context) types.Traces { + traces := types.Traces{} + k.IterateDenomTraces(ctx, func(_ tmbytes.HexBytes, denomTrace types.DenomTrace) bool { + traces = append(traces, denomTrace) + return false + }) + + return traces +} + +// IterateDenomTraces iterates over the denomination traces in the store +// and performs a callback function. +func (k Keeper) IterateDenomTraces(ctx sdk.Context, cb func(hash tmbytes.HexBytes, denomTrace types.DenomTrace) bool) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.DenomTraceKey) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + + var denomTrace types.DenomTrace + k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &denomTrace) + + if cb(iterator.Key(), denomTrace) { + break + } + } } // ClaimCapability allows the transfer module that can claim a capability that IBC module diff --git a/x/ibc-transfer/module.go b/x/ibc-transfer/module.go index 1b1b72da2929..8e604e43d842 100644 --- a/x/ibc-transfer/module.go +++ b/x/ibc-transfer/module.go @@ -122,19 +122,19 @@ func (am AppModule) LegacyQuerierHandler(codec.JSONMarshaler) sdk.Querier { // module-specific GRPC queries. func (am AppModule) RegisterQueryService(grpc.Server) {} -// InitGenesis performs genesis initialization for the ibc transfer module. It returns +// InitGenesis performs genesis initialization for the ibc-transfer module. It returns // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - - // TODO: check if the IBC transfer module account is set - InitGenesis(ctx, am.keeper, genesisState) + am.keeper.InitGenesis(ctx, genesisState) return []abci.ValidatorUpdate{} } +// ExportGenesis returns the exported genesis state as raw bytes for the ibc-transfer +// module. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper) + gs := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(gs) } diff --git a/x/ibc-transfer/types/genesis.pb.go b/x/ibc-transfer/types/genesis.pb.go index 8ea3002cf0e0..fc7decc1841e 100644 --- a/x/ibc-transfer/types/genesis.pb.go +++ b/x/ibc-transfer/types/genesis.pb.go @@ -83,25 +83,25 @@ func init() { func init() { proto.RegisterFile("ibc/transfer/genesis.proto", fileDescriptor_c13b8463155e05c2) } var fileDescriptor_c13b8463155e05c2 = []byte{ - // 286 bytes of a gzipped FileDescriptorProto + // 276 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xca, 0x4c, 0x4a, 0xd6, 0x2f, 0x29, 0x4a, 0xcc, 0x2b, 0x4e, 0x4b, 0x2d, 0xd2, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xc9, 0x4c, 0x4a, 0xd6, 0x83, 0xc9, 0x49, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf4, 0x41, 0x2c, 0x88, 0x1a, 0x29, 0x69, 0x14, 0xfd, 0x30, - 0x06, 0x44, 0x52, 0x69, 0x33, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xc8, 0xe0, 0x92, 0xc4, 0x92, 0x54, + 0x06, 0x44, 0x52, 0x69, 0x25, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xc8, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, 0x53, 0x2e, 0xf6, 0x82, 0xfc, 0xa2, 0x92, 0xf8, 0xcc, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0x99, 0x47, 0xf7, 0xe4, 0xd9, 0x02, 0xf2, 0x8b, 0x4a, 0x3c, 0x5d, 0x3e, 0xdd, 0x93, 0xe7, 0xab, 0x4c, 0xcc, 0xcd, 0xb1, 0x52, 0x82, 0x2a, 0x51, 0x0a, 0x62, 0x03, 0xb1, 0x3c, 0x53, - 0x84, 0x72, 0xb8, 0x78, 0x52, 0x52, 0xf3, 0xf2, 0x73, 0xe3, 0x4b, 0x8a, 0x12, 0x93, 0x53, 0x8b, - 0x25, 0x98, 0x14, 0x98, 0x35, 0xb8, 0x8d, 0x94, 0xf4, 0x90, 0xdd, 0xa7, 0xe7, 0x99, 0x92, 0x9a, - 0x57, 0x92, 0x99, 0x96, 0x99, 0x9a, 0xe2, 0x02, 0x52, 0x1b, 0x02, 0x52, 0xea, 0xa4, 0x7a, 0xe2, - 0x9e, 0x3c, 0xc3, 0xa7, 0x7b, 0xf2, 0xc2, 0x10, 0x93, 0x91, 0x4d, 0x51, 0x5a, 0x75, 0x5f, 0x9e, - 0x0d, 0xac, 0xaa, 0x38, 0x88, 0x3b, 0x05, 0xae, 0xa5, 0xd8, 0xc9, 0xfb, 0xc4, 0x23, 0x39, 0xc6, - 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, - 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x0c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, - 0x73, 0xf5, 0x93, 0xf3, 0x8b, 0x73, 0xf3, 0x8b, 0xa1, 0x94, 0x6e, 0x71, 0x4a, 0xb6, 0x7e, 0x85, - 0x7e, 0x66, 0x52, 0xb2, 0x2e, 0x22, 0x2c, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0x21, 0x61, - 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x82, 0xc6, 0x21, 0x88, 0x68, 0x01, 0x00, 0x00, + 0x84, 0x92, 0xb8, 0x78, 0x52, 0x52, 0xf3, 0xf2, 0x73, 0xe3, 0x4b, 0x8a, 0x12, 0x93, 0x53, 0x8b, + 0x25, 0x98, 0x14, 0x98, 0x35, 0xb8, 0x8d, 0x24, 0xf4, 0x90, 0xdd, 0xa7, 0xe7, 0x02, 0x52, 0x11, + 0x02, 0x52, 0xe0, 0xa4, 0x7a, 0xe2, 0x9e, 0x3c, 0xc3, 0xa7, 0x7b, 0xf2, 0xc2, 0x10, 0xf3, 0x90, + 0xf5, 0x2a, 0xad, 0xba, 0x2f, 0xcf, 0x06, 0x56, 0x55, 0x1c, 0xc4, 0x9d, 0x02, 0xd7, 0x52, 0xec, + 0xe4, 0x7d, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, + 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x86, 0xe9, 0x99, 0x25, + 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0x50, 0x4a, + 0xb7, 0x38, 0x25, 0x5b, 0xbf, 0x42, 0x3f, 0x33, 0x29, 0x59, 0x17, 0x11, 0x02, 0x95, 0x05, 0xa9, + 0xc5, 0x49, 0x6c, 0x60, 0xff, 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x55, 0xdf, 0xab, 0xa7, + 0x5e, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -274,7 +274,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DenomTraces = append(m.DenomTraces, IdentifiedDenomTrace{}) + m.DenomTraces = append(m.DenomTraces, DenomTrace{}) if err := m.DenomTraces[len(m.DenomTraces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/x/ibc-transfer/types/query.pb.go b/x/ibc-transfer/types/query.pb.go index 60dd8c808d4e..fe68c4c91c9a 100644 --- a/x/ibc-transfer/types/query.pb.go +++ b/x/ibc-transfer/types/query.pb.go @@ -7,6 +7,7 @@ import ( context "context" fmt "fmt" query "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" grpc "google.golang.org/grpc" @@ -168,7 +169,7 @@ func (m *QueryDenomTracesRequest) GetPagination() *query.PageRequest { // QueryConnectionsResponse is the response type for the Query/Connections RPC method. type QueryDenomTracesResponse struct { // list of stored connections of the chain. - DenomTraces []*IdentifiedDenomTrace `protobuf:"bytes,1,rep,name=denom_traces,json=denomTraces,proto3" json:"denom_traces,omitempty"` + DenomTraces Traces `protobuf:"bytes,1,rep,name=denom_traces,json=denomTraces,proto3,castrepeated=Traces" json:"denom_traces"` // pagination response Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -206,7 +207,7 @@ func (m *QueryDenomTracesResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryDenomTracesResponse proto.InternalMessageInfo -func (m *QueryDenomTracesResponse) GetDenomTraces() []*IdentifiedDenomTrace { +func (m *QueryDenomTracesResponse) GetDenomTraces() Traces { if m != nil { return m.DenomTraces } @@ -230,30 +231,31 @@ func init() { func init() { proto.RegisterFile("ibc/transfer/query.proto", fileDescriptor_26b3e8b4e9dff1c1) } var fileDescriptor_26b3e8b4e9dff1c1 = []byte{ - // 364 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xbd, 0x4e, 0xc3, 0x30, - 0x14, 0x85, 0x63, 0xfe, 0x24, 0x6e, 0x3a, 0x79, 0x80, 0x10, 0x44, 0x54, 0x45, 0x80, 0x3a, 0x50, - 0x47, 0x94, 0xa9, 0x8c, 0x08, 0x06, 0xc4, 0x02, 0x55, 0x27, 0x90, 0x40, 0xf9, 0x71, 0x5b, 0x0b, - 0x35, 0x4e, 0x63, 0x57, 0xa2, 0x6f, 0xc1, 0x0b, 0xf0, 0x36, 0x0c, 0x8c, 0x1d, 0x19, 0x51, 0xfb, - 0x22, 0xa8, 0x71, 0x43, 0x1c, 0x35, 0xa2, 0x53, 0xae, 0xec, 0x73, 0xce, 0xfd, 0x7c, 0x73, 0xc1, - 0x62, 0x41, 0xe8, 0xc9, 0xd4, 0x8f, 0x45, 0x8f, 0xa6, 0xde, 0x68, 0x4c, 0xd3, 0x09, 0x49, 0x52, - 0x2e, 0x39, 0xae, 0xb1, 0x20, 0x24, 0xf9, 0x8d, 0x7d, 0x14, 0x72, 0x31, 0xe4, 0x42, 0x29, 0xbc, - 0xc4, 0xef, 0xb3, 0xd8, 0x97, 0x8c, 0xc7, 0x4a, 0x6c, 0x1f, 0x96, 0x62, 0xf2, 0x42, 0x5d, 0xba, - 0x67, 0xb0, 0xf7, 0xb0, 0xb0, 0x5d, 0xd3, 0x98, 0x0f, 0xbb, 0xa9, 0x1f, 0xd2, 0x0e, 0x1d, 0x8d, - 0xa9, 0x90, 0x18, 0xc3, 0xd6, 0xc0, 0x17, 0x03, 0x0b, 0xd5, 0x51, 0x63, 0xb7, 0x93, 0xd5, 0x6e, - 0x17, 0xf6, 0x57, 0xd4, 0x22, 0xe1, 0xb1, 0xa0, 0xb8, 0x0d, 0x66, 0xb4, 0x38, 0x7d, 0x91, 0x8b, - 0xe3, 0xcc, 0x65, 0xb6, 0x2c, 0xa2, 0x83, 0x12, 0xcd, 0x06, 0xd1, 0x5f, 0x5d, 0x91, 0x2a, 0x72, - 0x88, 0x36, 0x40, 0xf1, 0x9e, 0x65, 0xe8, 0x01, 0x51, 0xef, 0x25, 0x6a, 0x22, 0xf7, 0x7e, 0x3f, - 0x67, 0xee, 0x68, 0x62, 0xf7, 0x03, 0x81, 0xb5, 0x1a, 0xbb, 0xa4, 0xbd, 0x81, 0x9a, 0x46, 0x2b, - 0x2c, 0x54, 0xdf, 0x6c, 0x98, 0x2d, 0xb7, 0x8c, 0x7b, 0x1b, 0xd1, 0x58, 0xb2, 0x1e, 0xa3, 0x91, - 0x06, 0x6e, 0x16, 0xe0, 0x02, 0x5f, 0x96, 0xf0, 0x36, 0x32, 0x3c, 0xbb, 0x0a, 0x4f, 0xb5, 0xd5, - 0xf9, 0x5a, 0x9f, 0x08, 0xb6, 0x33, 0x3e, 0xfc, 0x04, 0x50, 0x34, 0xc0, 0xc7, 0x65, 0x88, 0xea, - 0xbf, 0x63, 0x9f, 0xac, 0x51, 0xa9, 0x86, 0xae, 0x81, 0x9f, 0xc1, 0xd4, 0x06, 0x80, 0xff, 0xf7, - 0xe5, 0x73, 0xb7, 0x4f, 0xd7, 0xc9, 0xf2, 0xfc, 0xab, 0xbb, 0xaf, 0x99, 0x83, 0xa6, 0x33, 0x07, - 0xfd, 0xcc, 0x1c, 0xf4, 0x3e, 0x77, 0x8c, 0xe9, 0xdc, 0x31, 0xbe, 0xe7, 0x8e, 0xf1, 0x78, 0xde, - 0x67, 0x72, 0x30, 0x0e, 0x48, 0xc8, 0x87, 0xde, 0x72, 0x43, 0xd5, 0xa7, 0x29, 0xa2, 0x57, 0xef, - 0xcd, 0x63, 0x41, 0xd8, 0x2c, 0xd6, 0x72, 0x92, 0x50, 0x11, 0xec, 0x64, 0x4b, 0x79, 0xf1, 0x1b, - 0x00, 0x00, 0xff, 0xff, 0xbc, 0xb2, 0x05, 0x8d, 0xfa, 0x02, 0x00, 0x00, + // 375 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xcf, 0x4e, 0xc2, 0x40, + 0x10, 0xc6, 0xbb, 0xfe, 0x21, 0x71, 0x4a, 0x3c, 0x6c, 0x8c, 0xd6, 0x1a, 0x0b, 0x69, 0xd4, 0x78, + 0x90, 0xdd, 0x88, 0x27, 0x3c, 0x12, 0x6f, 0x5c, 0x94, 0x70, 0xd2, 0x44, 0xd3, 0x96, 0xb5, 0x34, + 0x86, 0x6e, 0xe9, 0x96, 0x44, 0xde, 0xc2, 0x77, 0xf0, 0xe6, 0x73, 0x78, 0xe0, 0xc8, 0xd1, 0x93, + 0x1a, 0x78, 0x11, 0xd3, 0x6e, 0x6b, 0x4b, 0x20, 0x70, 0xea, 0x64, 0xe7, 0xfb, 0xbe, 0xfd, 0xed, + 0x74, 0x40, 0xf3, 0x6c, 0x87, 0x46, 0xa1, 0xe5, 0x8b, 0x67, 0x16, 0xd2, 0xc1, 0x90, 0x85, 0x23, + 0x12, 0x84, 0x3c, 0xe2, 0xb8, 0xec, 0xd9, 0x0e, 0xc9, 0x3a, 0xfa, 0x9e, 0xcb, 0x5d, 0x9e, 0x34, + 0x68, 0x5c, 0x49, 0x8d, 0x7e, 0xec, 0x70, 0xd1, 0xe7, 0x42, 0xfa, 0x68, 0x60, 0xb9, 0x9e, 0x6f, + 0x45, 0x1e, 0xf7, 0xd3, 0xf6, 0xd1, 0x5c, 0x78, 0x56, 0xc8, 0xa6, 0x79, 0x01, 0xfb, 0x77, 0xb1, + 0xed, 0x86, 0xf9, 0xbc, 0xdf, 0x09, 0x2d, 0x87, 0xb5, 0xd9, 0x60, 0xc8, 0x44, 0x84, 0x31, 0x6c, + 0xf5, 0x2c, 0xd1, 0xd3, 0x50, 0x15, 0x9d, 0xef, 0xb4, 0x93, 0xda, 0xec, 0xc0, 0xc1, 0x82, 0x5a, + 0x04, 0xdc, 0x17, 0x0c, 0x37, 0x40, 0xed, 0xc6, 0xa7, 0x4f, 0x51, 0x7c, 0x9c, 0xb8, 0xd4, 0xba, + 0x46, 0x8a, 0xf8, 0xa4, 0x60, 0x83, 0xee, 0x7f, 0xbd, 0x24, 0x55, 0x64, 0x10, 0x0d, 0x80, 0xfc, + 0x3d, 0x69, 0xe8, 0x21, 0x91, 0xef, 0x25, 0x72, 0x4e, 0xb7, 0x96, 0x9b, 0x31, 0xb7, 0x0b, 0x62, + 0xf3, 0x1d, 0x81, 0xb6, 0x18, 0x9b, 0xd2, 0xb6, 0xa0, 0x5c, 0xa0, 0x15, 0x1a, 0xaa, 0x6e, 0xae, + 0xc2, 0x6d, 0xee, 0x8e, 0xbf, 0x2b, 0xca, 0xc7, 0x4f, 0xa5, 0x94, 0xe6, 0xa8, 0x39, 0xbe, 0xc0, + 0xd7, 0x73, 0x90, 0x1b, 0x09, 0xa4, 0xbe, 0x0c, 0x52, 0x5e, 0x5e, 0xa4, 0xac, 0x7f, 0x22, 0xd8, + 0x4e, 0x28, 0xf1, 0x03, 0x40, 0x7e, 0x21, 0x3e, 0x99, 0x47, 0x59, 0xfe, 0x8f, 0xf4, 0xd3, 0x35, + 0x2a, 0x79, 0xa1, 0xa9, 0xe0, 0x47, 0x50, 0x0b, 0x63, 0xc0, 0xab, 0x7d, 0xd9, 0xf4, 0xf5, 0xb3, + 0x75, 0xb2, 0x2c, 0xbf, 0xd9, 0x1a, 0x4f, 0x0d, 0x34, 0x99, 0x1a, 0xe8, 0x77, 0x6a, 0xa0, 0xb7, + 0x99, 0xa1, 0x4c, 0x66, 0x86, 0xf2, 0x35, 0x33, 0x94, 0xfb, 0x4b, 0xd7, 0x8b, 0x7a, 0x43, 0x9b, + 0x38, 0xbc, 0x4f, 0xd3, 0x3d, 0x95, 0x9f, 0x9a, 0xe8, 0xbe, 0xd0, 0x57, 0xea, 0xd9, 0x4e, 0x2d, + 0x5f, 0xce, 0x51, 0xc0, 0x84, 0x5d, 0x4a, 0x56, 0xf3, 0xea, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xb4, + 0xbd, 0x3c, 0xde, 0x16, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -921,7 +923,7 @@ func (m *QueryDenomTracesResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DenomTraces = append(m.DenomTraces, &IdentifiedDenomTrace{}) + m.DenomTraces = append(m.DenomTraces, DenomTrace{}) if err := m.DenomTraces[len(m.DenomTraces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 8b0138572391..5318211186da 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -1,7 +1,6 @@ package types import ( - "bytes" fmt "fmt" "strings" @@ -66,7 +65,7 @@ func (dt DenomTrace) validateTrace() error { switch { case dt.Trace == "" && dt.BaseDenom != "": return nil - case strings.TrimSpace(dt.Trace == ""): + case strings.TrimSpace(dt.Trace) == "": return fmt.Errorf("cannot have an empty trace and empty base denomination") } @@ -101,29 +100,21 @@ func (dt DenomTrace) Validate() error { } // Traces defines a wrapper type for a slice of IdentifiedDenomTraces. -type Traces []IdentifiedDenomTrace +type Traces []DenomTrace // Validate performs a basic validation of each denomination trace info. func (t Traces) Validate() error { seenTraces := make(map[string]bool) for i, trace := range t { - if seenTraces[trace.Hash] { + hash := trace.Hash().String() + if seenTraces[hash] { return fmt.Errorf("duplicated denomination trace with hash %s", trace.Hash) } - hash := tmhash.Sum([]byte(trace.Trace + "/" + trace.BaseDenom)) - if !bytes.Equal(tmbytes.HexBytes(trace.Hash), hash) { - return fmt.Errorf("trace hash mismatch, expected %s got %s", trace.Hash, hash) - } - - denomTrace := DenomTrace{ - Trace: trace.Trace, - BaseDenom: trace.BaseDenom, - } - if err := denomTrace.Validate(); err != nil { + if err := trace.Validate(); err != nil { sdkerrors.Wrapf(err, "failed denom trace %d validation", i) } - seenTraces[trace.Hash] = true + seenTraces[hash] = true } return nil } diff --git a/x/ibc-transfer/types/transfer.pb.go b/x/ibc-transfer/types/transfer.pb.go index 4a171bc9d723..ec01867c1444 100644 --- a/x/ibc-transfer/types/transfer.pb.go +++ b/x/ibc-transfer/types/transfer.pb.go @@ -35,7 +35,7 @@ type MsgTransfer struct { // the tokens to be transferred Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` // fungible token denomination trace info for source tracking - Trace *DenomTrace `protobuf:"bytes,4,opt,name=trace,proto3" json:"trace,omitempty"` + Trace DenomTrace `protobuf:"bytes,4,opt,name=trace,proto3" json:"trace"` // the sender address Sender github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,5,opt,name=sender,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"sender,omitempty"` // the recipient address on the destination chain @@ -102,11 +102,11 @@ func (m *MsgTransfer) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { return nil } -func (m *MsgTransfer) GetTrace() *DenomTrace { +func (m *MsgTransfer) GetTrace() DenomTrace { if m != nil { return m.Trace } - return nil + return DenomTrace{} } func (m *MsgTransfer) GetSender() github_com_cosmos_cosmos_sdk_types.AccAddress { @@ -143,7 +143,7 @@ type FungibleTokenPacketData struct { // the tokens to be transferred Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` // fungible token denomination trace info for source tracking - Trace *DenomTrace `protobuf:"bytes,2,opt,name=trace,proto3" json:"trace,omitempty"` + Trace DenomTrace `protobuf:"bytes,2,opt,name=trace,proto3" json:"trace"` // the sender address Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` // the recipient address on the destination chain @@ -190,11 +190,11 @@ func (m *FungibleTokenPacketData) GetAmount() github_com_cosmos_cosmos_sdk_types return nil } -func (m *FungibleTokenPacketData) GetTrace() *DenomTrace { +func (m *FungibleTokenPacketData) GetTrace() DenomTrace { if m != nil { return m.Trace } - return nil + return DenomTrace{} } func (m *FungibleTokenPacketData) GetSender() string { @@ -322,119 +322,52 @@ func (m *DenomTrace) GetBaseDenom() string { return "" } -// IdentifiedDenomTrace contains DenomTrace and the hash used for the IBC fungible denom map. -type IdentifiedDenomTrace struct { - // chain of port/channel identifiers used for tracing the source of the fungible token - Trace string `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` - // base denomination of the relayed fungible token - BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty" yaml:"base_denom"` - // SHA256 hash of the trace and the base denom: hash(trace + "/" + baseDenom) - Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` -} - -func (m *IdentifiedDenomTrace) Reset() { *m = IdentifiedDenomTrace{} } -func (m *IdentifiedDenomTrace) String() string { return proto.CompactTextString(m) } -func (*IdentifiedDenomTrace) ProtoMessage() {} -func (*IdentifiedDenomTrace) Descriptor() ([]byte, []int) { - return fileDescriptor_08134a70fd29e656, []int{4} -} -func (m *IdentifiedDenomTrace) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *IdentifiedDenomTrace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_IdentifiedDenomTrace.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 *IdentifiedDenomTrace) XXX_Merge(src proto.Message) { - xxx_messageInfo_IdentifiedDenomTrace.Merge(m, src) -} -func (m *IdentifiedDenomTrace) XXX_Size() int { - return m.Size() -} -func (m *IdentifiedDenomTrace) XXX_DiscardUnknown() { - xxx_messageInfo_IdentifiedDenomTrace.DiscardUnknown(m) -} - -var xxx_messageInfo_IdentifiedDenomTrace proto.InternalMessageInfo - -func (m *IdentifiedDenomTrace) GetTrace() string { - if m != nil { - return m.Trace - } - return "" -} - -func (m *IdentifiedDenomTrace) GetBaseDenom() string { - if m != nil { - return m.BaseDenom - } - return "" -} - -func (m *IdentifiedDenomTrace) GetHash() string { - if m != nil { - return m.Hash - } - return "" -} - func init() { proto.RegisterType((*MsgTransfer)(nil), "ibc.transfer.MsgTransfer") proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.transfer.FungibleTokenPacketData") proto.RegisterType((*FungibleTokenPacketAcknowledgement)(nil), "ibc.transfer.FungibleTokenPacketAcknowledgement") proto.RegisterType((*DenomTrace)(nil), "ibc.transfer.DenomTrace") - proto.RegisterType((*IdentifiedDenomTrace)(nil), "ibc.transfer.IdentifiedDenomTrace") } func init() { proto.RegisterFile("ibc/transfer/transfer.proto", fileDescriptor_08134a70fd29e656) } var fileDescriptor_08134a70fd29e656 = []byte{ - // 579 bytes of a gzipped FileDescriptorProto + // 560 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xcd, 0x6e, 0xd3, 0x40, - 0x18, 0x8c, 0xdb, 0x34, 0x6d, 0x37, 0x2d, 0xa2, 0x4b, 0x5b, 0x4c, 0x41, 0x76, 0xe4, 0x93, 0x2f, - 0xb5, 0x69, 0x41, 0x42, 0xe2, 0x44, 0xd3, 0x0a, 0x11, 0x21, 0xa4, 0xca, 0x8a, 0x10, 0xe2, 0x12, - 0xd9, 0xeb, 0xaf, 0xb6, 0x95, 0x78, 0x37, 0xda, 0x5d, 0x17, 0x7a, 0xe7, 0x01, 0x78, 0x0e, 0x9e, - 0xa4, 0xc7, 0x5e, 0x90, 0x38, 0x19, 0x94, 0xbc, 0x41, 0x8e, 0x9c, 0x90, 0xbd, 0xce, 0x9f, 0x54, - 0xa1, 0x5e, 0x7a, 0xf2, 0xce, 0x37, 0xf3, 0x7d, 0xde, 0x9d, 0xb1, 0x17, 0x3d, 0x4d, 0x02, 0xe2, - 0x4a, 0xee, 0x53, 0x71, 0x01, 0x7c, 0xb6, 0x70, 0x86, 0x9c, 0x49, 0x86, 0xb7, 0x92, 0x80, 0x38, - 0xd3, 0xda, 0xc1, 0x6e, 0xc4, 0x22, 0x56, 0x12, 0x6e, 0xb1, 0x52, 0x9a, 0x83, 0x47, 0x84, 0x89, - 0x94, 0x09, 0x57, 0x3d, 0x54, 0xd1, 0xfa, 0x56, 0x47, 0xcd, 0x0f, 0x22, 0xea, 0x56, 0xad, 0xf8, - 0x15, 0x6a, 0x0a, 0x96, 0x71, 0x02, 0xbd, 0x21, 0xe3, 0x52, 0xd7, 0x5a, 0x9a, 0xbd, 0xd9, 0xde, - 0x9f, 0xe4, 0x26, 0xbe, 0xf2, 0xd3, 0xc1, 0x6b, 0x6b, 0x81, 0xb4, 0x3c, 0xa4, 0xd0, 0x39, 0xe3, - 0x12, 0xbf, 0x41, 0x0f, 0x2a, 0x8e, 0xc4, 0x3e, 0xa5, 0x30, 0xd0, 0x57, 0xca, 0xde, 0x27, 0x93, - 0xdc, 0xdc, 0x5b, 0xea, 0xad, 0x78, 0xcb, 0xdb, 0x56, 0x85, 0x53, 0x85, 0xf1, 0x47, 0xd4, 0xf0, - 0x53, 0x96, 0x51, 0xa9, 0xaf, 0xb6, 0x56, 0xed, 0xe6, 0xf1, 0x96, 0x53, 0xed, 0xf4, 0x94, 0x25, - 0xb4, 0xfd, 0xfc, 0x3a, 0x37, 0x6b, 0x3f, 0x7e, 0x9b, 0x76, 0x94, 0xc8, 0x38, 0x0b, 0x1c, 0xc2, - 0x52, 0x77, 0xe9, 0x40, 0x87, 0x22, 0xec, 0xbb, 0xf2, 0x6a, 0x08, 0xaa, 0x41, 0x78, 0xd5, 0x34, - 0xec, 0xa0, 0x35, 0xc9, 0x7d, 0x02, 0x7a, 0xbd, 0xa5, 0xd9, 0xcd, 0x63, 0xdd, 0x59, 0xf4, 0xca, - 0x39, 0x03, 0xca, 0xd2, 0x6e, 0xc1, 0x7b, 0x4a, 0x86, 0x3b, 0xa8, 0x21, 0x80, 0x86, 0xc0, 0xf5, - 0xb5, 0x96, 0x66, 0x6f, 0xb5, 0x8f, 0xfe, 0xe6, 0xe6, 0xe1, 0x1d, 0xde, 0x7a, 0x42, 0xc8, 0x49, - 0x18, 0x72, 0x10, 0xc2, 0xab, 0x06, 0xe0, 0x03, 0xb4, 0xc1, 0x81, 0x40, 0x72, 0x09, 0x5c, 0x6f, - 0x14, 0x76, 0x78, 0x33, 0x5c, 0x18, 0x26, 0x93, 0x14, 0x58, 0x26, 0x7b, 0x31, 0x24, 0x51, 0x2c, - 0xf5, 0xf5, 0x96, 0x66, 0xd7, 0x17, 0x0d, 0x5b, 0xe6, 0x2d, 0x6f, 0xbb, 0x2a, 0xbc, 0x2b, 0x31, - 0xee, 0xa0, 0x9d, 0xa9, 0xa2, 0x78, 0x0a, 0xe9, 0xa7, 0x43, 0x7d, 0xa3, 0x1c, 0xf2, 0x6c, 0x92, - 0x9b, 0xfa, 0xf2, 0x90, 0x99, 0xc4, 0xf2, 0x1e, 0x56, 0xb5, 0xee, 0xac, 0xf4, 0x53, 0x43, 0x8f, - 0xdf, 0x66, 0x34, 0x4a, 0x82, 0x01, 0x74, 0x59, 0x1f, 0xe8, 0xb9, 0x4f, 0xfa, 0x20, 0xcf, 0x7c, - 0xe9, 0x2f, 0xe4, 0xa2, 0xdd, 0x4f, 0x2e, 0x2b, 0x77, 0xcb, 0x65, 0x7f, 0x96, 0xcb, 0x6a, 0x69, - 0xe5, 0x6d, 0x26, 0xd7, 0x97, 0x4d, 0xb6, 0xba, 0xc8, 0xba, 0xe5, 0x58, 0x27, 0xa4, 0x4f, 0xd9, - 0x97, 0x01, 0x84, 0x11, 0xa4, 0x40, 0x25, 0xd6, 0xd1, 0xba, 0xc8, 0x08, 0x01, 0x21, 0xca, 0x0f, - 0x7e, 0xc3, 0x9b, 0x42, 0xbc, 0x8b, 0xd6, 0x80, 0x73, 0xc6, 0xd5, 0xc7, 0xec, 0x29, 0x60, 0x7d, - 0x42, 0x68, 0xbe, 0xbd, 0x42, 0xa3, 0xce, 0xa1, 0x29, 0x8d, 0xda, 0xed, 0x4b, 0x84, 0x02, 0x5f, - 0x40, 0x2f, 0x2c, 0x84, 0xd5, 0xbf, 0xb0, 0x37, 0xc9, 0xcd, 0x1d, 0x95, 0xca, 0x9c, 0xb3, 0xbc, - 0xcd, 0x02, 0x94, 0x03, 0xad, 0x4b, 0xb4, 0xdb, 0x09, 0x81, 0xca, 0xe4, 0x22, 0x81, 0xf0, 0x7e, - 0xde, 0x81, 0x31, 0xaa, 0xc7, 0xbe, 0x88, 0x2b, 0x17, 0xcb, 0x75, 0xfb, 0xfd, 0xf5, 0xc8, 0xd0, - 0x6e, 0x46, 0x86, 0xf6, 0x67, 0x64, 0x68, 0xdf, 0xc7, 0x46, 0xed, 0x66, 0x6c, 0xd4, 0x7e, 0x8d, - 0x8d, 0xda, 0xe7, 0xa3, 0xff, 0xe6, 0xfa, 0xd5, 0x4d, 0x02, 0x72, 0x38, 0xbf, 0x95, 0x8a, 0x98, - 0x83, 0x46, 0x79, 0xb5, 0xbc, 0xf8, 0x17, 0x00, 0x00, 0xff, 0xff, 0x17, 0x3b, 0xa0, 0x4a, 0xb2, - 0x04, 0x00, 0x00, + 0x10, 0x8e, 0xdb, 0x34, 0x6d, 0x37, 0x29, 0xa2, 0xa6, 0x2d, 0x26, 0x20, 0x3b, 0xf2, 0xc9, 0x97, + 0xd8, 0xb4, 0x54, 0x42, 0xe2, 0x44, 0xd2, 0x0a, 0x51, 0x21, 0xa4, 0x6a, 0x15, 0x21, 0xc4, 0x25, + 0xb2, 0xd7, 0x83, 0x63, 0x25, 0xde, 0x8d, 0x76, 0xd7, 0x40, 0x5f, 0x81, 0x13, 0xcf, 0xc1, 0x93, + 0xf4, 0xd8, 0x23, 0x12, 0x92, 0x41, 0xc9, 0x1b, 0xe4, 0xc8, 0x09, 0xd9, 0xeb, 0xfc, 0x49, 0x15, + 0x82, 0x03, 0x27, 0xef, 0x37, 0xdf, 0x37, 0xb3, 0x3b, 0xdf, 0xec, 0x1a, 0x3d, 0x8c, 0x03, 0xe2, + 0x49, 0xee, 0x53, 0xf1, 0x1e, 0xf8, 0x62, 0xe1, 0x8e, 0x39, 0x93, 0x4c, 0x6f, 0xc4, 0x01, 0x71, + 0xe7, 0xb1, 0xe6, 0x41, 0xc4, 0x22, 0x56, 0x10, 0x5e, 0xbe, 0x52, 0x9a, 0xe6, 0x3d, 0xc2, 0x44, + 0xc2, 0x84, 0xa7, 0x3e, 0x2a, 0x68, 0x7f, 0xae, 0xa2, 0xfa, 0x6b, 0x11, 0xf5, 0xca, 0x54, 0xfd, + 0x29, 0xaa, 0x0b, 0x96, 0x72, 0x02, 0xfd, 0x31, 0xe3, 0xd2, 0xd0, 0x5a, 0x9a, 0xb3, 0xdb, 0x3d, + 0x9a, 0x65, 0x96, 0x7e, 0xe5, 0x27, 0xa3, 0x67, 0xf6, 0x0a, 0x69, 0x63, 0xa4, 0xd0, 0x25, 0xe3, + 0x52, 0x7f, 0x8e, 0xee, 0x94, 0x1c, 0x19, 0xf8, 0x94, 0xc2, 0xc8, 0xd8, 0x28, 0x72, 0x1f, 0xcc, + 0x32, 0xeb, 0x70, 0x2d, 0xb7, 0xe4, 0x6d, 0xbc, 0xa7, 0x02, 0x67, 0x0a, 0xeb, 0x6f, 0x50, 0xcd, + 0x4f, 0x58, 0x4a, 0xa5, 0xb1, 0xd9, 0xda, 0x74, 0xea, 0x27, 0x0d, 0xb7, 0x3c, 0xe9, 0x19, 0x8b, + 0x69, 0xf7, 0xf1, 0x75, 0x66, 0x55, 0xbe, 0xfe, 0xb0, 0x9c, 0x28, 0x96, 0x83, 0x34, 0x70, 0x09, + 0x4b, 0xbc, 0xb5, 0x86, 0xda, 0x22, 0x1c, 0x7a, 0xf2, 0x6a, 0x0c, 0x2a, 0x41, 0xe0, 0xb2, 0x9a, + 0x7e, 0x8a, 0xb6, 0x24, 0xf7, 0x09, 0x18, 0xd5, 0x96, 0xe6, 0xd4, 0x4f, 0x0c, 0x77, 0xd5, 0x2b, + 0xf7, 0x1c, 0x28, 0x4b, 0x7a, 0x39, 0xdf, 0xad, 0xe6, 0x5b, 0x60, 0x25, 0xd6, 0x2f, 0x50, 0x4d, + 0x00, 0x0d, 0x81, 0x1b, 0x5b, 0x2d, 0xcd, 0x69, 0x74, 0x8f, 0x7f, 0x65, 0x56, 0xfb, 0x2f, 0xf6, + 0xee, 0x10, 0xd2, 0x09, 0x43, 0x0e, 0x42, 0xe0, 0xb2, 0x80, 0xde, 0x44, 0x3b, 0x1c, 0x08, 0xc4, + 0x1f, 0x80, 0x1b, 0xb5, 0xdc, 0x14, 0xbc, 0xc0, 0xb9, 0x6d, 0x32, 0x4e, 0x80, 0xa5, 0xb2, 0x3f, + 0x80, 0x38, 0x1a, 0x48, 0x63, 0xbb, 0xa5, 0x39, 0xd5, 0x55, 0xdb, 0xd6, 0x79, 0x1b, 0xef, 0x95, + 0x81, 0x97, 0x05, 0xd6, 0x2f, 0xd0, 0xfe, 0x5c, 0x91, 0x7f, 0x85, 0xf4, 0x93, 0xb1, 0xb1, 0x53, + 0x14, 0x79, 0x34, 0xcb, 0x2c, 0x63, 0xbd, 0xc8, 0x42, 0x62, 0xe3, 0xbb, 0x65, 0xac, 0xb7, 0x08, + 0x7d, 0xd7, 0xd0, 0xfd, 0x17, 0x29, 0x8d, 0xe2, 0x60, 0x04, 0x3d, 0x36, 0x04, 0x7a, 0xe9, 0x93, + 0x21, 0xc8, 0x73, 0x5f, 0xfa, 0x2b, 0xd3, 0xd1, 0xfe, 0xcf, 0x74, 0x36, 0xfe, 0x65, 0x3a, 0x47, + 0x8b, 0xe9, 0x6c, 0x16, 0x86, 0xde, 0x66, 0x75, 0x75, 0xdd, 0x6a, 0xbb, 0x87, 0xec, 0x5b, 0x9a, + 0xeb, 0x90, 0x21, 0x65, 0x1f, 0x47, 0x10, 0x46, 0x90, 0x00, 0x95, 0xba, 0x81, 0xb6, 0x45, 0x4a, + 0x08, 0x08, 0x51, 0x5c, 0xfe, 0x1d, 0x3c, 0x87, 0xfa, 0x01, 0xda, 0x02, 0xce, 0x19, 0x57, 0x17, + 0x1b, 0x2b, 0x60, 0xbf, 0x45, 0x68, 0x79, 0xc8, 0x5c, 0xa3, 0xba, 0xd1, 0x94, 0x46, 0x9d, 0xf6, + 0x14, 0xa1, 0xc0, 0x17, 0xd0, 0x0f, 0x73, 0x61, 0xf9, 0x2e, 0x0e, 0x67, 0x99, 0xb5, 0xaf, 0x66, + 0xb3, 0xe4, 0x6c, 0xbc, 0x9b, 0x83, 0xa2, 0x60, 0xf7, 0xd5, 0xf5, 0xc4, 0xd4, 0x6e, 0x26, 0xa6, + 0xf6, 0x73, 0x62, 0x6a, 0x5f, 0xa6, 0x66, 0xe5, 0x66, 0x6a, 0x56, 0xbe, 0x4d, 0xcd, 0xca, 0xbb, + 0xe3, 0x3f, 0xba, 0xfc, 0xc9, 0x8b, 0x03, 0xd2, 0x5e, 0xfe, 0x29, 0x72, 0xd3, 0x83, 0x5a, 0xf1, + 0xdc, 0x9f, 0xfc, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xcf, 0x28, 0x95, 0x0e, 0x46, 0x04, 0x00, 0x00, } func (m *MsgTransfer) Marshal() (dAtA []byte, err error) { @@ -481,18 +414,16 @@ func (m *MsgTransfer) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x2a } - if m.Trace != nil { - { - size, err := m.Trace.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTransfer(dAtA, i, uint64(size)) + { + size, err := m.Trace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x22 + i -= size + i = encodeVarintTransfer(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x22 if len(m.Amount) > 0 { for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { { @@ -558,18 +489,16 @@ func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) i-- dAtA[i] = 0x1a } - if m.Trace != nil { - { - size, err := m.Trace.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTransfer(dAtA, i, uint64(size)) + { + size, err := m.Trace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x12 + i -= size + i = encodeVarintTransfer(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x12 if len(m.Amount) > 0 { for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { { @@ -664,50 +593,6 @@ func (m *DenomTrace) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *IdentifiedDenomTrace) 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 *IdentifiedDenomTrace) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *IdentifiedDenomTrace) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Hash) > 0 { - i -= len(m.Hash) - copy(dAtA[i:], m.Hash) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.Hash))) - i-- - dAtA[i] = 0x1a - } - if len(m.BaseDenom) > 0 { - i -= len(m.BaseDenom) - copy(dAtA[i:], m.BaseDenom) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.BaseDenom))) - i-- - dAtA[i] = 0x12 - } - if len(m.Trace) > 0 { - i -= len(m.Trace) - copy(dAtA[i:], m.Trace) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.Trace))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintTransfer(dAtA []byte, offset int, v uint64) int { offset -= sovTransfer(v) base := offset @@ -739,10 +624,8 @@ func (m *MsgTransfer) Size() (n int) { n += 1 + l + sovTransfer(uint64(l)) } } - if m.Trace != nil { - l = m.Trace.Size() - n += 1 + l + sovTransfer(uint64(l)) - } + l = m.Trace.Size() + n += 1 + l + sovTransfer(uint64(l)) l = len(m.Sender) if l > 0 { n += 1 + l + sovTransfer(uint64(l)) @@ -772,10 +655,8 @@ func (m *FungibleTokenPacketData) Size() (n int) { n += 1 + l + sovTransfer(uint64(l)) } } - if m.Trace != nil { - l = m.Trace.Size() - n += 1 + l + sovTransfer(uint64(l)) - } + l = m.Trace.Size() + n += 1 + l + sovTransfer(uint64(l)) l = len(m.Sender) if l > 0 { n += 1 + l + sovTransfer(uint64(l)) @@ -820,27 +701,6 @@ func (m *DenomTrace) Size() (n int) { return n } -func (m *IdentifiedDenomTrace) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Trace) - if l > 0 { - n += 1 + l + sovTransfer(uint64(l)) - } - l = len(m.BaseDenom) - if l > 0 { - n += 1 + l + sovTransfer(uint64(l)) - } - l = len(m.Hash) - if l > 0 { - n += 1 + l + sovTransfer(uint64(l)) - } - return n -} - func sovTransfer(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1003,9 +863,6 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Trace == nil { - m.Trace = &DenomTrace{} - } if err := m.Trace.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -1230,9 +1087,6 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Trace == nil { - m.Trace = &DenomTrace{} - } if err := m.Trace.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -1547,155 +1401,6 @@ func (m *DenomTrace) Unmarshal(dAtA []byte) error { } return nil } -func (m *IdentifiedDenomTrace) 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 ErrIntOverflowTransfer - } - 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: IdentifiedDenomTrace: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: IdentifiedDenomTrace: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - 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 ErrInvalidLengthTransfer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Trace = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BaseDenom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - 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 ErrInvalidLengthTransfer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.BaseDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - 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 ErrInvalidLengthTransfer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Hash = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTransfer(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthTransfer - } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthTransfer - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipTransfer(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 1e9d878cf3396773736f2c1ec981d9bf3805373f Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 29 Jul 2020 11:52:57 +0200 Subject: [PATCH 06/41] relay.go updates --- x/ibc-transfer/handler.go | 2 +- x/ibc-transfer/keeper/relay.go | 6 ++++-- x/ibc-transfer/types/keys.go | 9 --------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/x/ibc-transfer/handler.go b/x/ibc-transfer/handler.go index 08c3df9dd485..8b7ee2f82d5a 100644 --- a/x/ibc-transfer/handler.go +++ b/x/ibc-transfer/handler.go @@ -24,7 +24,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { // See createOutgoingPacket in spec:https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay func handleMsgTransfer(ctx sdk.Context, k keeper.Keeper, msg *types.MsgTransfer) (*sdk.Result, error) { if err := k.SendTransfer( - ctx, msg.SourcePort, msg.SourceChannel, msg.Amount, msg.Sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, + ctx, msg.SourcePort, msg.SourceChannel, msg.Amount, msg.Trace, msg.Sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, ); err != nil { return nil, err } diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index e5b89fe59412..a0b79a59b7ab 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -25,6 +25,7 @@ func (k Keeper) SendTransfer( sourcePort, sourceChannel string, amount sdk.Coins, + denomTrace types.DenomTrace, sender sdk.AccAddress, receiver string, timeoutHeight, @@ -49,7 +50,7 @@ func (k Keeper) SendTransfer( return k.createOutgoingPacket( ctx, sequence, sourcePort, sourceChannel, destinationPort, destinationChannel, - amount, sender, receiver, timeoutHeight, timeoutTimestamp, + amount, denomTrace, sender, receiver, timeoutHeight, timeoutTimestamp, ) } @@ -60,6 +61,7 @@ func (k Keeper) createOutgoingPacket( sourcePort, sourceChannel, destinationPort, destinationChannel string, amount sdk.Coins, + denomTrace types.DenomTrace, sender sdk.AccAddress, receiver string, timeoutHeight, timeoutTimestamp uint64, @@ -131,7 +133,7 @@ func (k Keeper) createOutgoingPacket( } packetData := types.NewFungibleTokenPacketData( - amount, sender.String(), receiver, + amount, denomTrace, sender.String(), receiver, ) packet := channeltypes.NewPacket( diff --git a/x/ibc-transfer/types/keys.go b/x/ibc-transfer/types/keys.go index 094dcc0d4e16..b9d4b3085eac 100644 --- a/x/ibc-transfer/types/keys.go +++ b/x/ibc-transfer/types/keys.go @@ -42,12 +42,3 @@ var ( func GetEscrowAddress(portID, channelID string) sdk.AccAddress { return sdk.AccAddress(crypto.AddressHash([]byte(portID + channelID))) } - -// GetPrefixedCoins creates a copy of the given coins with the denom updated with the prefix. -func GetPrefixedCoins(portID, channelID string, coins ...sdk.Coin) sdk.Coins { - prefixedCoins := make(sdk.Coins, len(coins)) - for i := range coins { - prefixedCoins[i] = sdk.NewCoin(GetDenomPrefix(portID, channelID)+coins[i].Denom, coins[i].Amount) - } - return prefixedCoins -} From 7ef0f14eac77ba5da3c0c7c3d682bcc7874d8d61 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 29 Jul 2020 12:38:18 +0200 Subject: [PATCH 07/41] gRPC service methods --- x/ibc-transfer/keeper/grpc_query.go | 74 +++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 x/ibc-transfer/keeper/grpc_query.go diff --git a/x/ibc-transfer/keeper/grpc_query.go b/x/ibc-transfer/keeper/grpc_query.go new file mode 100644 index 000000000000..78bac9056267 --- /dev/null +++ b/x/ibc-transfer/keeper/grpc_query.go @@ -0,0 +1,74 @@ +package keeper + +import ( + "context" + "fmt" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" +) + +var _ types.QueryServer = Keeper{} + +// DenomTrace implements the Query/DenomTrace gRPC method +func (q Keeper) DenomTrace(c context.Context, req *types.QueryDenomTraceRequest) (*types.QueryDenomTraceResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + if err := tmtypes.ValidateHash([]byte(req.Hash)); err != nil { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid denom trace hash %s, %s", req.Hash, err)) + } + + ctx := sdk.UnwrapSDKContext(c) + denomTrace, found := q.GetDenomTrace(ctx, []byte(req.Hash)) + if !found { + return nil, status.Error( + codes.NotFound, + sdkerrors.Wrap(types.ErrInvalidDenomForTransfer, req.Hash).Error(), // TODO: update error + ) + } + + return &types.QueryDenomTraceResponse{ + DenomTrace: &denomTrace, + }, nil +} + +// DenomTraces implements the Query/DenomTraces gRPC method +func (q Keeper) DenomTraces(c context.Context, req *types.QueryDenomTracesRequest) (*types.QueryDenomTracesResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + traces := types.Traces{} + store := prefix.NewStore(ctx.KVStore(q.storeKey), types.DenomTraceKey) + + pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { + var result types.DenomTrace + if err := q.cdc.UnmarshalBinaryBare(value, &result); err != nil { + return err + } + + traces = append(traces, result) + return nil + }) + + if err != nil { + return nil, err + } + + return &types.QueryDenomTracesResponse{ + DenomTraces: traces, + Pagination: pageRes, + }, nil +} From 41af31482fc6fadaeaea7f0221abaae2d957ca65 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Wed, 29 Jul 2020 13:06:20 +0200 Subject: [PATCH 08/41] client CLI --- x/ibc-transfer/client/cli/cli.go | 17 ++++++ x/ibc-transfer/client/cli/query.go | 87 ++++++++++++++++++++++++++++++ x/ibc-transfer/client/cli/tx.go | 11 ++-- x/ibc-transfer/client/rest/rest.go | 12 +++-- x/ibc-transfer/client/rest/tx.go | 1 + x/ibc-transfer/module.go | 6 ++- x/ibc-transfer/types/trace.go | 19 +++++-- 7 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 x/ibc-transfer/client/cli/query.go diff --git a/x/ibc-transfer/client/cli/cli.go b/x/ibc-transfer/client/cli/cli.go index e8850d9eff5b..9686afaa189a 100644 --- a/x/ibc-transfer/client/cli/cli.go +++ b/x/ibc-transfer/client/cli/cli.go @@ -6,6 +6,23 @@ import ( "github.com/cosmos/cosmos-sdk/client" ) +// GetQueryCmd returns the query commands for IBC connections +func GetQueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: "ibc-transfer", + Short: "IBC fungible token transfer query subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + queryCmd.AddCommand( + GetCmdQueryDenomTrace(), + GetCmdQueryDenomTraces(), + ) + + return queryCmd +} + // NewTxCmd returns the transaction commands for IBC fungible token transfer func NewTxCmd() *cobra.Command { txCmd := &cobra.Command{ diff --git a/x/ibc-transfer/client/cli/query.go b/x/ibc-transfer/client/cli/query.go new file mode 100644 index 000000000000..cdf5f575b6a1 --- /dev/null +++ b/x/ibc-transfer/client/cli/query.go @@ -0,0 +1,87 @@ +package cli + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" +) + +// GetCmdQueryDenomTraces defines the command to query all the denomination trace infos +// that this chain mantains. +func GetCmdQueryDenomTraces() *cobra.Command { + cmd := &cobra.Command{ + Use: "denom-traces", + Short: "Query the trace info for all token denominations", + Long: "Query the trace info for all token denominations", + Example: fmt.Sprintf("%s query ibc-transfer denom-traces", version.AppName), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.ReadQueryCommandFlags(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryDenomTracesRequest{ + Pagination: pageReq, + } + + res, err := queryClient.DenomTraces(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintOutput(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "denominations trace") + + return cmd +} + +// GetCmdQueryDenomTrace defines the command to query a a denomination trace from a given hash. +func GetCmdQueryDenomTrace() *cobra.Command { + cmd := &cobra.Command{ + Use: "denom-trace [hash]", + Short: "Query the denom trace info from a given trace hash", + Long: "Query the denom trace info from a given trace hash", + Example: fmt.Sprintf("%s query ibc-transfer denom-trace [hash]", version.AppName), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.ReadQueryCommandFlags(clientCtx, cmd.Flags()) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryDenomTraceRequest{ + Hash: args[0], + } + + res, err := queryClient.DenomTrace(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintOutput(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/ibc-transfer/client/cli/tx.go b/x/ibc-transfer/client/cli/tx.go index 451245d74d38..5e05487df0d5 100644 --- a/x/ibc-transfer/client/cli/tx.go +++ b/x/ibc-transfer/client/cli/tx.go @@ -24,14 +24,14 @@ const ( // NewTransferTxCmd returns the command to create a NewMsgTransfer transaction func NewTransferTxCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "transfer [src-port] [src-channel] [receiver] [amount]", + Use: "transfer [src-port] [src-channel] [receiver] [amount] [denom-trace]", Short: "Transfer a fungible token through IBC", Long: strings.TrimSpace(`Transfer a fungible token through IBC. Timeouts can be specified as absolute or relative using the "absolute-timeouts" flag. Relative timeouts are added to the block height and block timestamp queried from the latest consensus state corresponding to the counterparty channel. Any timeout set to 0 is disabled.`), Example: fmt.Sprintf("%s tx ibc-transfer transfer [src-port] [src-channel] [receiver] [amount]", version.AppName), - Args: cobra.ExactArgs(4), + Args: cobra.ExactArgs(5), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags()) @@ -49,6 +49,11 @@ to the counterparty channel. Any timeout set to 0 is disabled.`), return err } + denomTrace, err := types.ParseDenomTrace(args[4]) + if err != nil { + return err + } + timeoutHeight, err := cmd.Flags().GetUint64(flagTimeoutHeight) if err != nil { return err @@ -82,7 +87,7 @@ to the counterparty channel. Any timeout set to 0 is disabled.`), } msg := types.NewMsgTransfer( - srcPort, srcChannel, coins, sender, receiver, timeoutHeight, timeoutTimestamp, + srcPort, srcChannel, coins, denomTrace, sender, receiver, timeoutHeight, timeoutTimestamp, ) if err := msg.ValidateBasic(); err != nil { return err diff --git a/x/ibc-transfer/client/rest/rest.go b/x/ibc-transfer/client/rest/rest.go index 4a498ba3bbd9..a0aac4733af6 100644 --- a/x/ibc-transfer/client/rest/rest.go +++ b/x/ibc-transfer/client/rest/rest.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" ) const ( @@ -20,9 +21,10 @@ func RegisterRoutes(clientCtx client.Context, r *mux.Router) { // TransferTxReq defines the properties of a transfer tx request's body. type TransferTxReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Amount sdk.Coins `json:"amount" yaml:"amount"` - Receiver string `json:"receiver" yaml:"receiver"` - TimeoutHeight uint64 `json:"timeout_height" yaml:"timeout_height"` - TimeoutTimestamp uint64 `json:"timeout_timestamp" yaml:"timeout_timestamp"` + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Amount sdk.Coins `json:"amount" yaml:"amount"` + DenomTrace types.DenomTrace `json:"denom_trace" yaml:"denom_trace"` + Receiver string `json:"receiver" yaml:"receiver"` + TimeoutHeight uint64 `json:"timeout_height" yaml:"timeout_height"` + TimeoutTimestamp uint64 `json:"timeout_timestamp" yaml:"timeout_timestamp"` } diff --git a/x/ibc-transfer/client/rest/tx.go b/x/ibc-transfer/client/rest/tx.go index 7e57f26db660..077156505a2b 100644 --- a/x/ibc-transfer/client/rest/tx.go +++ b/x/ibc-transfer/client/rest/tx.go @@ -57,6 +57,7 @@ func transferHandlerFn(clientCtx client.Context) http.HandlerFunc { portID, channelID, req.Amount, + req.DenomTrace, fromAddr, req.Receiver, req.TimeoutHeight, diff --git a/x/ibc-transfer/module.go b/x/ibc-transfer/module.go index 8e604e43d842..d754de659920 100644 --- a/x/ibc-transfer/module.go +++ b/x/ibc-transfer/module.go @@ -77,7 +77,7 @@ func (AppModuleBasic) GetTxCmd() *cobra.Command { // GetQueryCmd implements AppModuleBasic interface func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil + return cli.GetQueryCmd() } // RegisterInterfaces registers module concrete types into protobuf Any. @@ -120,7 +120,9 @@ func (am AppModule) LegacyQuerierHandler(codec.JSONMarshaler) sdk.Querier { // RegisterQueryService registers a GRPC query service to respond to the // module-specific GRPC queries. -func (am AppModule) RegisterQueryService(grpc.Server) {} +func (am AppModule) RegisterQueryService(server grpc.Server) { + types.RegisterQueryServer(server, am.keeper) +} // InitGenesis performs genesis initialization for the ibc-transfer module. It returns // no validator updates. diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 5318211186da..00cc64666a65 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -6,6 +6,7 @@ import ( "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" + tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -108,7 +109,7 @@ func (t Traces) Validate() error { for i, trace := range t { hash := trace.Hash().String() if seenTraces[hash] { - return fmt.Errorf("duplicated denomination trace with hash %s", trace.Hash) + return fmt.Errorf("duplicated denomination trace with hash %s", trace.Hash()) } if err := trace.Validate(); err != nil { @@ -131,8 +132,8 @@ func ValidateIBCDenom(denom string) (tmbytes.HexBytes, error) { err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) case denomSplit[0] != "ibc": err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination %s must start with 'ibc'", denom) - case len(denomSplit) == 2 && len(denomSplit[1]) != tmhash.Size: - err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid SHA256 hash %s length, expected %d, got %d", denomSplit[1], tmhash.Size, len(denomSplit[1])) + case len(denomSplit) == 2: + err = tmtypes.ValidateHash([]byte(denomSplit[1])) default: err = sdkerrors.Wrap(ErrInvalidDenomForTransfer, denom) } @@ -143,3 +144,15 @@ func ValidateIBCDenom(denom string) (tmbytes.HexBytes, error) { return tmbytes.HexBytes(denomSplit[1]), nil } + +// ParseDenomTrace parses a string with the ibc prefix (denom trace) and the base denomination +// into a DenomTrace type. The parsing will fail if the base denom is invalid or if the trace is not correctly constructed +// in pairs of valid port and channel identifiers. +// +// Valid examples: +// - "portidone/channelidone/uatom" => DenomTrace{Trace: "portidone/channelidone", BaseDenom: "uatom"} +// - "uatom" => DenomTrace{Trace: "", BaseDenom: "uatom"} +func ParseDenomTrace(trace string) (DenomTrace, error) { + // TODO: use ParseCoin as reference + return DenomTrace{}, nil +} From 1c1273d1932df8396f8530988db69458424a85db Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 15:42:21 +0200 Subject: [PATCH 09/41] update implementation --- .../adr-001-coin-source-tracing.md | 14 +-- proto/ibc/transfer/transfer.proto | 5 +- types/coin.go | 2 +- x/ibc-transfer/handler.go | 2 +- x/ibc-transfer/keeper/relay.go | 17 ++- x/ibc-transfer/module.go | 2 + x/ibc-transfer/types/msgs.go | 28 +---- x/ibc-transfer/types/packet.go | 8 +- x/ibc-transfer/types/trace.go | 115 ++++++++---------- 9 files changed, 77 insertions(+), 116 deletions(-) diff --git a/docs/architecture/adr-001-coin-source-tracing.md b/docs/architecture/adr-001-coin-source-tracing.md index d0d2d6d5337b..a6efad1e4fd4 100644 --- a/docs/architecture/adr-001-coin-source-tracing.md +++ b/docs/architecture/adr-001-coin-source-tracing.md @@ -277,19 +277,13 @@ The denomination trace info only needs to be updated when token is received: // NOTE: We use SourcePort and SourceChannel here, because the counterparty // chain would have prefixed with DestPort and DestChannel when originally // receiving this coin as seen in the "sender chain is the source" condition. -voucherPrefix := GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) - if ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) { // sender chain is not the source, unescrow tokens // remove prefix added by sender chain - if err := denomTrace.RemovePrefix(); err != nil { - return err - } - - // NOTE: since the sender is a sink chain, we already know the unprefixed denomination trace info - - token := sdk.NewCoin(denomTrace.IBCDenom(), sdk.NewIntFromUint64(data.Amount)) + voucherPrefix := types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) + unprefixedDenom := data.Denom[len(voucherPrefix):] + token := sdk.NewCoin(unprefixedDenom, sdk.NewIntFromUint64(data.Amount)) // unescrow tokens escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) @@ -299,7 +293,7 @@ if ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data // sender chain is the source, mint vouchers // construct the denomination trace from the full raw denomination -denomTrace := NewDenomTraceFromRawDenom(data.Denom) +denomTrace := NewDenomTrace(data.Denom) // since SendPacket did not prefix the denomination with the voucherPrefix, we must add it here denomTrace.AddPrefix(packet.GetDestPort(), packet.GetDestChannel()) diff --git a/proto/ibc/transfer/transfer.proto b/proto/ibc/transfer/transfer.proto index 64029dcb84ec..dbf4bd53d15e 100644 --- a/proto/ibc/transfer/transfer.proto +++ b/proto/ibc/transfer/transfer.proto @@ -57,11 +57,10 @@ message FungibleTokenPacketAcknowledgement { string error = 2; } -// DenomTrace contains the base denomination for ICS20 fungible tokens and the souce tracing +// DenomTrace contains the base denomination for ICS20 fungible tokens and the source tracing // information message DenomTrace { // chain of port/channel identifiers used for tracing the source of the fungible token string trace = 1; // base denomination of the relayed fungible token - string base_denom = 2 [(gogoproto.moretags) = "yaml:\"base_denom\""]; -} + string base_denom = 2; diff --git a/types/coin.go b/types/coin.go index ad287a0a785b..20217dbc4de9 100644 --- a/types/coin.go +++ b/types/coin.go @@ -577,7 +577,7 @@ func (coins Coins) Sort() Coins { var ( // Denominations can be 3 ~ 64 characters long. - reDnmString = `[a-z][a-z0-9/]{2,63}` + reDnmString = `[a-z][a-zA-Z0-9/]{2,63}` reAmt = `[[:digit:]]+` reDecAmt = `[[:digit:]]*\.[[:digit:]]+` reSpc = `[[:space:]]*` diff --git a/x/ibc-transfer/handler.go b/x/ibc-transfer/handler.go index 7e8d51eb24ed..2e7fd10dd383 100644 --- a/x/ibc-transfer/handler.go +++ b/x/ibc-transfer/handler.go @@ -29,7 +29,7 @@ func handleMsgTransfer(ctx sdk.Context, k keeper.Keeper, msg *types.MsgTransfer) return nil, err } - k.Logger(ctx).Info("IBC transfer: %s from %s to %s", msg.Token, msg.Sender, msg.Receiver) + k.Logger(ctx).Info("IBC fungible token transfer", "token", msg.Token, "sender", msg.Sender, "receiver", msg.Receiver) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index d7c13b6a271d..5cb6cc3da740 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -40,13 +40,11 @@ import ( // 4. A -> C : sender chain is sink zone. Denom upon receiving: 'C/B/denom' // 5. C -> B : sender chain is sink zone. Denom upon receiving: 'B/denom' // 6. B -> A : sender chain is sink zone. Denom upon receiving: 'denom' - func (k Keeper) SendTransfer( ctx sdk.Context, sourcePort, sourceChannel string, token sdk.Coin, - denomTrace types.DenomTrace, sender sdk.AccAddress, receiver string, timeoutHeight, @@ -134,7 +132,10 @@ func (k Keeper) SendTransfer( // back tokens this chain originally transferred to it, the tokens are // unescrowed and sent to the receiving address. func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData) error { - // NOTE: packet data type already checked in handler.go + // validate packet data upon receiving + if err := data.ValidateBasic(); err != nil { + return err + } // decode the receiver address receiver, err := sdk.AccAddressFromBech32(data.Receiver) @@ -169,7 +170,15 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t sourcePrefix := types.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel()) // NOTE: sourcePrefix contains the trailing "/" prefixedDenom := sourcePrefix + data.Denom - voucher := sdk.NewCoin(prefixedDenom, sdk.NewIntFromUint64(data.Amount)) + + denomTrace := types.ParseDenomTrace(prefixedDenom) + + traceHash := denomTrace.Hash() + if !k.HasDenomTrace(ctx, traceHash) { + k.SetDenomTrace(ctx, denomTrace) + } + + voucher := sdk.NewCoin(denomTrace.IBCDenom(), sdk.NewIntFromUint64(data.Amount)) // mint new tokens if the source of the transfer is the same chain if err := k.bankKeeper.MintCoins( diff --git a/x/ibc-transfer/module.go b/x/ibc-transfer/module.go index c6c54d452b0e..9a4b6e0fc4a0 100644 --- a/x/ibc-transfer/module.go +++ b/x/ibc-transfer/module.go @@ -290,10 +290,12 @@ func (am AppModule) OnRecvPacket( if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) } + acknowledgement := types.FungibleTokenPacketAcknowledgement{ Success: true, Error: "", } + if err := am.keeper.OnRecvPacket(ctx, packet, data); err != nil { acknowledgement = types.FungibleTokenPacketAcknowledgement{ Success: false, diff --git a/x/ibc-transfer/types/msgs.go b/x/ibc-transfer/types/msgs.go index beafe05c758b..d12714c6d2ee 100644 --- a/x/ibc-transfer/types/msgs.go +++ b/x/ibc-transfer/types/msgs.go @@ -1,9 +1,6 @@ package types import ( - "bytes" - fmt "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" @@ -17,15 +14,13 @@ const ( // NewMsgTransfer creates a new MsgTransfer instance func NewMsgTransfer( sourcePort, sourceChannel string, - token sdk.Coin, trace DenomTrace, - sender sdk.AccAddress, receiver string, + token sdk.Coin, sender sdk.AccAddress, receiver string, timeoutHeight, timeoutTimestamp uint64, ) *MsgTransfer { return &MsgTransfer{ SourcePort: sourcePort, SourceChannel: sourceChannel, Token: token, - Trace: trace, Sender: sender, Receiver: receiver, TimeoutHeight: timeoutHeight, @@ -58,27 +53,6 @@ func (msg MsgTransfer) ValidateBasic() error { if !msg.Token.IsPositive() { return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, msg.Token.String()) } - if err := msg.Trace.Validate(); err != nil { - return err - } - // Only validate the ibc denomination when trace info is not provided - if msg.Trace.Trace != "" { - denomTraceHash, err := ValidateIBCDenom(msg.Token.Denom) - if err != nil { - return err - } - traceHash := msg.Trace.Hash() - if !bytes.Equal(traceHash.Bytes(), denomTraceHash.Bytes()) { - return fmt.Errorf("token denomination trace hash mismatch, expected %s got %s", traceHash, denomTraceHash) - } - } else if msg.Trace.BaseDenom != msg.Token.Denom { - // otherwise, validate that denominations are equal - return sdkerrors.Wrapf( - ErrInvalidDenomForTransfer, - "token denom must match the trace base denom (%s ≠ %s)", - msg.Amount, msg.Trace.BaseDenom, - ) - } if msg.Sender.Empty() { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") } diff --git a/x/ibc-transfer/types/packet.go b/x/ibc-transfer/types/packet.go index 4e8fcaba4451..649bacd2bc93 100644 --- a/x/ibc-transfer/types/packet.go +++ b/x/ibc-transfer/types/packet.go @@ -36,22 +36,16 @@ func NewFungibleTokenPacketData( // ValidateBasic is used for validating the token transfer func (ftpd FungibleTokenPacketData) ValidateBasic() error { - if strings.TrimSpace(ftpd.Denom) == "" { - return sdkerrors.Wrap(ErrInvalidDenomForTransfer, "denom cannot be empty") - } if ftpd.Amount == 0 { return sdkerrors.Wrap(ErrInvalidAmount, "amount cannot be 0") } - if err := ftpd.Trace.Validate(); err != nil { - return err - } if strings.TrimSpace(ftpd.Sender) == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be blank") } if strings.TrimSpace(ftpd.Receiver) == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "receiver address cannot be blank") } - return nil + return ValidateIBCDenom(ftpd.Denom) } // GetBytes is a helper for serialising diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 00cc64666a65..d2066993bca5 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -6,13 +6,34 @@ import ( "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" - tmtypes "github.com/tendermint/tendermint/types" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) +// ParseDenomTrace parses a string with the ibc prefix (denom trace) and the base denomination +// into a DenomTrace type. +// +// Examples: +// +// - "portidone/channelidone/uatom" => DenomTrace{Trace: "portidone/channelidone", BaseDenom: "uatom"} +// - "uatom" => DenomTrace{Trace: "", BaseDenom: "uatom"} +func ParseDenomTrace(rawDenom string) DenomTrace { + denomSplit := strings.Split(denom, "/") + + if denomSplit[0] == denom { + return DenomTrace{ + Trace: "", + BaseDenom: denom, + } + } + + return DenomTrace{ + Trace: strings.Join(denomSplit[:len(denomSplit)-1], "/"), + BaseDenom: denomSplit[len(denomSplit)-1], + } +} + // Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula: // // hash = sha256(trace + "/" + baseDenom) @@ -25,7 +46,8 @@ func (dt DenomTrace) GetPrefix() string { return dt.Trace + "/" } -// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + "/" + baseDenom)}'. If the trace is empty, it will return the base denomination. +// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + +// baseDenom)}'. If the trace is empty, it will return the base denomination. func (dt DenomTrace) IBCDenom() string { if dt.Trace != "" { return fmt.Sprintf("ibc/%s", dt.Hash()) @@ -33,7 +55,9 @@ func (dt DenomTrace) IBCDenom() string { return dt.BaseDenom } -// RemovePrefix trims the first portID/channelID pair from the trace info. If the trace is already empty it will perform a no-op. If the trace is incorrectly constructed or doesn't have separators it will return an error. +// RemovePrefix trims the first portID/channelID pair from the trace info. If the trace is already +// empty it will perform a no-op. If the trace is incorrectly constructed or doesn't have separators +// it will return an error. func (dt *DenomTrace) RemovePrefix() error { if dt.Trace == "" { return nil @@ -43,10 +67,7 @@ func (dt *DenomTrace) RemovePrefix() error { var err error switch { - case len(traceSplit) == 0, traceSplit[0] == dt.Trace: - err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "trace info %s must contain '/' separators", dt.Trace) - case len(traceSplit) == 1: - err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "trace info %s must come in pairs of '{portID}/channelID}'", dt.Trace) + // NOTE: other cases are checked during msg validation case len(traceSplit) == 2: dt.Trace = "" case len(traceSplit) == 3: @@ -60,31 +81,17 @@ func (dt *DenomTrace) RemovePrefix() error { return nil } -func (dt DenomTrace) validateTrace() error { - // empty trace is accepted when token lives on the original chain - - switch { - case dt.Trace == "" && dt.BaseDenom != "": - return nil - case strings.TrimSpace(dt.Trace) == "": - return fmt.Errorf("cannot have an empty trace and empty base denomination") - } - - traceSplit := strings.Split(dt.Trace, "/") - - switch { - case traceSplit[0] == dt.Trace: - return fmt.Errorf("trace %s must contain '/' separators", dt.Trace) - case len(traceSplit)%2 != 0: +func validateTraceIdentifiers(identifiers []string) error { + if len(identifiers)%2 != 0 { return fmt.Errorf("trace info %s must come in pairs of port and channel identifiers '{portID}/{channelID}'", dt.Trace) } // validate correctness of port and channel identifiers - for i := 0; i < len(traceSplit); i += 2 { - if err := host.PortIdentifierValidator(traceSplit[i]); err != nil { + for i := 0; i < len(identifiers); i += 2 { + if err := host.PortIdentifierValidator(identifiers[i]); err != nil { return sdkerrors.Wrapf(err, "invalid port ID at position %d", i) } - if err := host.ChannelIdentifierValidator(traceSplit[i+1]); err != nil { + if err := host.ChannelIdentifierValidator(identifiers[i+1]); err != nil { return sdkerrors.Wrapf(err, "invalid channel ID at position %d", i) } } @@ -93,11 +100,18 @@ func (dt DenomTrace) validateTrace() error { // Validate performs a basic validation of the DenomTrace fields. func (dt DenomTrace) Validate() error { - if err := sdk.ValidateDenom(dt.BaseDenom); err != nil { - return err + // empty trace is accepted when token lives on the original chain + switch { + case dt.Trace == "" && dt.BaseDenom != "": + return nil + case strings.TrimSpace(dt.Trace) == "" && strings.TrimSpace(dt.BaseDenom) == "": + return fmt.Errorf("cannot have an empty trace and empty base denomination") } - return dt.validateTrace() + // NOTE: no base denomination validation + + identifiers := strings.Split(dt.Trace, "/") + return validateTraceIdentifiers(identifiers) } // Traces defines a wrapper type for a slice of IdentifiedDenomTraces. @@ -120,39 +134,14 @@ func (t Traces) Validate() error { return nil } -// ValidateIBCDenom checks that the denomination for an IBC fungible token is valid. -func ValidateIBCDenom(denom string) (tmbytes.HexBytes, error) { - denomSplit := strings.SplitN(denom, "/", 3) - - var err error - switch { - case len(denomSplit) == 0: - err = sdkerrors.Wrap(ErrInvalidDenomForTransfer, denom) - case denomSplit[0] == denom: - err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) - case denomSplit[0] != "ibc": - err = sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination %s must start with 'ibc'", denom) - case len(denomSplit) == 2: - err = tmtypes.ValidateHash([]byte(denomSplit[1])) - default: - err = sdkerrors.Wrap(ErrInvalidDenomForTransfer, denom) - } - - if err != nil { - return nil, err +// ValidateIBCDenom checks that the denomination for an IBC fungible token packet denom is valid. +func ValidateIBCDenom(denom string) error { + denomSplit := strings.Split(denom, "/") + if denomSplit[0] == denom { + // NOTE: no base denomination validation + return nil } - return tmbytes.HexBytes(denomSplit[1]), nil -} - -// ParseDenomTrace parses a string with the ibc prefix (denom trace) and the base denomination -// into a DenomTrace type. The parsing will fail if the base denom is invalid or if the trace is not correctly constructed -// in pairs of valid port and channel identifiers. -// -// Valid examples: -// - "portidone/channelidone/uatom" => DenomTrace{Trace: "portidone/channelidone", BaseDenom: "uatom"} -// - "uatom" => DenomTrace{Trace: "", BaseDenom: "uatom"} -func ParseDenomTrace(trace string) (DenomTrace, error) { - // TODO: use ParseCoin as reference - return DenomTrace{}, nil + identifiers := denomSplit[:len(denomSplit)-1] + return validateTraceIdentifiers(identifiers) } From b42f1a8cd5bf97259e76fc43fced0374f660448d Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 17:28:26 +0200 Subject: [PATCH 10/41] build --- x/ibc-transfer/client/cli/tx.go | 9 ++------- x/ibc-transfer/client/rest/rest.go | 12 +++++------- x/ibc-transfer/client/rest/tx.go | 3 +-- x/ibc-transfer/handler.go | 2 +- x/ibc-transfer/keeper/keeper.go | 7 +++---- x/ibc-transfer/keeper/relay.go | 11 ++++++++++- x/ibc-transfer/types/events.go | 2 ++ x/ibc-transfer/types/trace.go | 9 +++++---- 8 files changed, 29 insertions(+), 26 deletions(-) diff --git a/x/ibc-transfer/client/cli/tx.go b/x/ibc-transfer/client/cli/tx.go index 8889ebf00cea..e1fc445d64ff 100644 --- a/x/ibc-transfer/client/cli/tx.go +++ b/x/ibc-transfer/client/cli/tx.go @@ -24,7 +24,7 @@ const ( // NewTransferTxCmd returns the command to create a NewMsgTransfer transaction func NewTransferTxCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "transfer [src-port] [src-channel] [receiver] [amount] [denom-trace]", + Use: "transfer [src-port] [src-channel] [receiver] [amount]", Short: "Transfer a fungible token through IBC", Long: strings.TrimSpace(`Transfer a fungible token through IBC. Timeouts can be specified as absolute or relative using the "absolute-timeouts" flag. Relative timeouts are added to @@ -49,11 +49,6 @@ to the counterparty channel. Any timeout set to 0 is disabled.`), return err } - denomTrace, err := types.ParseDenomTrace(args[4]) - if err != nil { - return err - } - timeoutHeight, err := cmd.Flags().GetUint64(flagTimeoutHeight) if err != nil { return err @@ -87,7 +82,7 @@ to the counterparty channel. Any timeout set to 0 is disabled.`), } msg := types.NewMsgTransfer( - srcPort, srcChannel, coin, denomTrace, sender, receiver, timeoutHeight, timeoutTimestamp, + srcPort, srcChannel, coin, sender, receiver, timeoutHeight, timeoutTimestamp, ) if err := msg.ValidateBasic(); err != nil { return err diff --git a/x/ibc-transfer/client/rest/rest.go b/x/ibc-transfer/client/rest/rest.go index ed80cbd70eee..e624b2fae550 100644 --- a/x/ibc-transfer/client/rest/rest.go +++ b/x/ibc-transfer/client/rest/rest.go @@ -6,7 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" ) const ( @@ -21,10 +20,9 @@ func RegisterRoutes(clientCtx client.Context, r *mux.Router) { // TransferTxReq defines the properties of a transfer tx request's body. type TransferTxReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Token sdk.Coin `json:"token" yaml:"token"` - DenomTrace types.DenomTrace `json:"denom_trace" yaml:"denom_trace"` - Receiver string `json:"receiver" yaml:"receiver"` - TimeoutHeight uint64 `json:"timeout_height" yaml:"timeout_height"` - TimeoutTimestamp uint64 `json:"timeout_timestamp" yaml:"timeout_timestamp"` + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Token sdk.Coin `json:"token" yaml:"token"` + Receiver string `json:"receiver" yaml:"receiver"` + TimeoutHeight uint64 `json:"timeout_height" yaml:"timeout_height"` + TimeoutTimestamp uint64 `json:"timeout_timestamp" yaml:"timeout_timestamp"` } diff --git a/x/ibc-transfer/client/rest/tx.go b/x/ibc-transfer/client/rest/tx.go index 077156505a2b..09216b731762 100644 --- a/x/ibc-transfer/client/rest/tx.go +++ b/x/ibc-transfer/client/rest/tx.go @@ -56,8 +56,7 @@ func transferHandlerFn(clientCtx client.Context) http.HandlerFunc { msg := types.NewMsgTransfer( portID, channelID, - req.Amount, - req.DenomTrace, + req.Token, fromAddr, req.Receiver, req.TimeoutHeight, diff --git a/x/ibc-transfer/handler.go b/x/ibc-transfer/handler.go index 2e7fd10dd383..9c4a6807aba7 100644 --- a/x/ibc-transfer/handler.go +++ b/x/ibc-transfer/handler.go @@ -24,7 +24,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { // See createOutgoingPacket in spec:https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay func handleMsgTransfer(ctx sdk.Context, k keeper.Keeper, msg *types.MsgTransfer) (*sdk.Result, error) { if err := k.SendTransfer( - ctx, msg.SourcePort, msg.SourceChannel, msg.Token, msg.Trace, msg.Sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, + ctx, msg.SourcePort, msg.SourceChannel, msg.Token, msg.Sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, ); err != nil { return nil, err } diff --git a/x/ibc-transfer/keeper/keeper.go b/x/ibc-transfer/keeper/keeper.go index 65f9b8ee604b..5f5b50993c0e 100644 --- a/x/ibc-transfer/keeper/keeper.go +++ b/x/ibc-transfer/keeper/keeper.go @@ -3,7 +3,6 @@ package keeper import ( "fmt" - tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" @@ -140,7 +139,7 @@ func (k Keeper) SetDenomTrace(ctx sdk.Context, denomTrace types.DenomTrace) { // GetAllDenomTraces returns the trace information for all the denominations. func (k Keeper) GetAllDenomTraces(ctx sdk.Context) types.Traces { traces := types.Traces{} - k.IterateDenomTraces(ctx, func(_ tmbytes.HexBytes, denomTrace types.DenomTrace) bool { + k.IterateDenomTraces(ctx, func(denomTrace types.DenomTrace) bool { traces = append(traces, denomTrace) return false }) @@ -150,7 +149,7 @@ func (k Keeper) GetAllDenomTraces(ctx sdk.Context) types.Traces { // IterateDenomTraces iterates over the denomination traces in the store // and performs a callback function. -func (k Keeper) IterateDenomTraces(ctx sdk.Context, cb func(hash tmbytes.HexBytes, denomTrace types.DenomTrace) bool) { +func (k Keeper) IterateDenomTraces(ctx sdk.Context, cb func(denomTrace types.DenomTrace) bool) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, types.DenomTraceKey) @@ -160,7 +159,7 @@ func (k Keeper) IterateDenomTraces(ctx sdk.Context, cb func(hash tmbytes.HexByte var denomTrace types.DenomTrace k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &denomTrace) - if cb(iterator.Key(), denomTrace) { + if cb(denomTrace) { break } } diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index 5cb6cc3da740..8943c409c802 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -178,7 +178,16 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t k.SetDenomTrace(ctx, denomTrace) } - voucher := sdk.NewCoin(denomTrace.IBCDenom(), sdk.NewIntFromUint64(data.Amount)) + voucherDenom := denomTrace.IBCDenom() + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeDenomTrace, + sdk.NewAttribute(types.AttributeKeyTraceHash, traceHash.String()), + sdk.NewAttribute(types.AttributeKeyDenom, voucherDenom), + ), + ) + + voucher := sdk.NewCoin(voucherDenom, sdk.NewIntFromUint64(data.Amount)) // mint new tokens if the source of the transfer is the same chain if err := k.bankKeeper.MintCoins( diff --git a/x/ibc-transfer/types/events.go b/x/ibc-transfer/types/events.go index 900460a50591..68832f937ded 100644 --- a/x/ibc-transfer/types/events.go +++ b/x/ibc-transfer/types/events.go @@ -6,6 +6,7 @@ const ( EventTypePacket = "fungible_token_packet" EventTypeTransfer = "ibc_transfer" EventTypeChannelClose = "channel_closed" + EventTypeDenomTrace = "denomination_trace" AttributeKeyReceiver = "receiver" AttributeKeyDenom = "denom" @@ -15,4 +16,5 @@ const ( AttributeKeyRefundAmount = "refund_amount" AttributeKeyAckSuccess = "success" AttributeKeyAckError = "error" + AttributeKeyTraceHash = "trace_hash" ) diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index d2066993bca5..1d17b77d6f47 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -1,6 +1,7 @@ package types import ( + "errors" fmt "fmt" "strings" @@ -19,12 +20,12 @@ import ( // - "portidone/channelidone/uatom" => DenomTrace{Trace: "portidone/channelidone", BaseDenom: "uatom"} // - "uatom" => DenomTrace{Trace: "", BaseDenom: "uatom"} func ParseDenomTrace(rawDenom string) DenomTrace { - denomSplit := strings.Split(denom, "/") + denomSplit := strings.Split(rawDenom, "/") - if denomSplit[0] == denom { + if denomSplit[0] == rawDenom { return DenomTrace{ Trace: "", - BaseDenom: denom, + BaseDenom: rawDenom, } } @@ -83,7 +84,7 @@ func (dt *DenomTrace) RemovePrefix() error { func validateTraceIdentifiers(identifiers []string) error { if len(identifiers)%2 != 0 { - return fmt.Errorf("trace info %s must come in pairs of port and channel identifiers '{portID}/{channelID}'", dt.Trace) + return errors.New("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}'") } // validate correctness of port and channel identifiers From 9fb1c95565d62e9152c0ac1598d0c47543af7234 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 18:02:39 +0200 Subject: [PATCH 11/41] trace test --- x/ibc-transfer/types/trace.go | 19 ++++--- x/ibc-transfer/types/trace_test.go | 83 ++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 x/ibc-transfer/types/trace_test.go diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 1d17b77d6f47..b6406c53de75 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -59,14 +59,13 @@ func (dt DenomTrace) IBCDenom() string { // RemovePrefix trims the first portID/channelID pair from the trace info. If the trace is already // empty it will perform a no-op. If the trace is incorrectly constructed or doesn't have separators // it will return an error. -func (dt *DenomTrace) RemovePrefix() error { +func (dt *DenomTrace) RemovePrefix() { if dt.Trace == "" { - return nil + return } traceSplit := strings.SplitN(dt.Trace, "/", 3) - var err error switch { // NOTE: other cases are checked during msg validation case len(traceSplit) == 2: @@ -74,12 +73,6 @@ func (dt *DenomTrace) RemovePrefix() error { case len(traceSplit) == 3: dt.Trace = traceSplit[2] } - - if err != nil { - return err - } - - return nil } func validateTraceIdentifiers(identifiers []string) error { @@ -107,6 +100,8 @@ func (dt DenomTrace) Validate() error { return nil case strings.TrimSpace(dt.Trace) == "" && strings.TrimSpace(dt.BaseDenom) == "": return fmt.Errorf("cannot have an empty trace and empty base denomination") + case dt.Trace != "" && strings.TrimSpace(dt.BaseDenom) == "": + return sdkerrors.Wrap(ErrInvalidDenomForTransfer, "denomination cannot be blank") } // NOTE: no base denomination validation @@ -138,11 +133,15 @@ func (t Traces) Validate() error { // ValidateIBCDenom checks that the denomination for an IBC fungible token packet denom is valid. func ValidateIBCDenom(denom string) error { denomSplit := strings.Split(denom, "/") - if denomSplit[0] == denom { + if denomSplit[0] == denom && strings.TrimSpace(denom) != "" { // NOTE: no base denomination validation return nil } + if strings.TrimSpace(denomSplit[len(denomSplit)-1]) == "" { + return sdkerrors.Wrap(ErrInvalidDenomForTransfer, "base denomination cannot be blank") + } + identifiers := denomSplit[:len(denomSplit)-1] return validateTraceIdentifiers(identifiers) } diff --git a/x/ibc-transfer/types/trace_test.go b/x/ibc-transfer/types/trace_test.go new file mode 100644 index 000000000000..115ac34dbf43 --- /dev/null +++ b/x/ibc-transfer/types/trace_test.go @@ -0,0 +1,83 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseDenomTrace(t *testing.T) { + testCases := []struct { + name string + denom string + expTrace DenomTrace + }{ + {"empty denom", "", DenomTrace{}}, + {"base denom", "uatom", DenomTrace{BaseDenom: "uatom"}}, + {"trace info", "transfer/channelToA/uatom", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA"}}, + } + + for _, tc := range testCases { + trace := ParseDenomTrace(tc.denom) + require.Equal(t, tc.expTrace, trace, tc.name) + } +} + +func TestDenomTrace_IBCDenom(t *testing.T) { + testCases := []struct { + name string + trace DenomTrace + expDenom string + }{ + {"base denom", DenomTrace{BaseDenom: "uatom"}, "uatom"}, + {"trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA"}, "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2"}, + } + + for _, tc := range testCases { + denom := tc.trace.IBCDenom() + require.Equal(t, tc.expDenom, denom, tc.name) + } +} + +func TestDenomTrace_RemovePrefix(t *testing.T) { + testCases := []struct { + name string + trace DenomTrace + expTrace string + }{ + {"no trace", DenomTrace{BaseDenom: "uatom"}, ""}, + {"single trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA"}, ""}, + {"multiple trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}, "transfer/channelToB"}, + } + + for _, tc := range testCases { + tc.trace.RemovePrefix() + require.Equal(t, tc.expTrace, tc.trace.Trace, tc.name) + } +} + +func TestDenomTrace_Validate(t *testing.T) { + testCases := []struct { + name string + trace DenomTrace + expError bool + }{ + {"base denom only", DenomTrace{BaseDenom: "uatom"}, false}, + {"empty DenomTrace", DenomTrace{}, true}, + {"valid single trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA"}, false}, + {"valid multiple trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}, false}, + {"single trace identifier", DenomTrace{BaseDenom: "uatom", Trace: "transfer"}, true}, + {"invalid port ID", DenomTrace{BaseDenom: "uatom", Trace: "(transfer)/channelToA"}, true}, + {"invalid channel ID", DenomTrace{BaseDenom: "uatom", Trace: "transfer/(channelToA)"}, true}, + {"empty base denom with trace", DenomTrace{BaseDenom: "", Trace: "transfer/channelToA"}, true}, + } + + for _, tc := range testCases { + err := tc.trace.Validate() + if tc.expError { + require.Error(t, err, tc.name) + continue + } + require.NoError(t, err, tc.name) + } +} From c877d39272104103afc1a587135d981f150aadff Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 18:04:01 +0200 Subject: [PATCH 12/41] fix CLI tx args --- x/ibc-transfer/client/cli/tx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc-transfer/client/cli/tx.go b/x/ibc-transfer/client/cli/tx.go index e1fc445d64ff..f3b3a11b420e 100644 --- a/x/ibc-transfer/client/cli/tx.go +++ b/x/ibc-transfer/client/cli/tx.go @@ -31,7 +31,7 @@ as absolute or relative using the "absolute-timeouts" flag. Relative timeouts ar the block height and block timestamp queried from the latest consensus state corresponding to the counterparty channel. Any timeout set to 0 is disabled.`), Example: fmt.Sprintf("%s tx ibc-transfer transfer [src-port] [src-channel] [receiver] [amount]", version.AppName), - Args: cobra.ExactArgs(5), + Args: cobra.ExactArgs(4), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags()) From 76552c8328ab803bb743c73d4ffaed21d4726313 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 18:34:58 +0200 Subject: [PATCH 13/41] genesis import/export tests --- x/ibc-transfer/keeper/genesis_test.go | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 x/ibc-transfer/keeper/genesis_test.go diff --git a/x/ibc-transfer/keeper/genesis_test.go b/x/ibc-transfer/keeper/genesis_test.go new file mode 100644 index 000000000000..4784ac2ccc09 --- /dev/null +++ b/x/ibc-transfer/keeper/genesis_test.go @@ -0,0 +1,31 @@ +package keeper_test + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" +) + +func (suite *KeeperTestSuite) TestGenesis() { + var trace string + for i := 0; i < 5; i++ { + prefix := fmt.Sprintf("transfer/channelToChain%d", i) + if i == 0 { + trace = prefix + } else { + trace = prefix + trace + } + + denomTrace := types.DenomTrace{ + BaseDenom: "uatom", + Trace: trace, + } + suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), denomTrace) + } + + genesis := suite.chainA.App.TransferKeeper.ExportGenesis(suite.chainA.GetContext()) + + suite.Require().NotPanics(func() { + suite.chainA.App.TransferKeeper.InitGenesis(suite.chainA.GetContext(), genesis) + }) +} From f5bf4b1e3c0bf556eb4025b38a2c784b3a8926a4 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 18:37:47 +0200 Subject: [PATCH 14/41] update comments --- proto/ibc/transfer/query.proto | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proto/ibc/transfer/query.proto b/proto/ibc/transfer/query.proto index a52f7594153d..862707b95c45 100644 --- a/proto/ibc/transfer/query.proto +++ b/proto/ibc/transfer/query.proto @@ -9,10 +9,10 @@ option go_package = "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"; // Query provides defines the gRPC querier service service Query { - // DenomTrace queries an IBC connection end. + // DenomTrace queries a denomination trace info. rpc DenomTrace(QueryDenomTraceRequest) returns (QueryDenomTraceResponse) {} - // DenomTraces queries all the IBC connections of a chain. + // DenomTraces queries all denomination traces. rpc DenomTraces(QueryDenomTracesRequest) returns (QueryDenomTracesResponse) {} } @@ -28,12 +28,12 @@ message QueryDenomTraceResponse { DenomTrace denom_trace = 1; } -// QueryConnectionsRequest is the request type for the Query/Connections RPC method +// QueryConnectionsRequest is the request type for the Query/DenomTraces RPC method message QueryDenomTracesRequest { cosmos.query.PageRequest pagination = 1; } -// QueryConnectionsResponse is the response type for the Query/Connections RPC method. +// QueryConnectionsResponse is the response type for the Query/DenomTraces RPC method. message QueryDenomTracesResponse { // list of stored connections of the chain. repeated DenomTrace denom_traces = 1 [ From 1611cc03235f7d6beb9668f352da6c4f7831b4e5 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 18:55:31 +0200 Subject: [PATCH 15/41] update proto files --- proto/ibc/transfer/transfer.proto | 13 +-- x/ibc-transfer/types/query.pb.go | 12 +-- x/ibc-transfer/types/trace.go | 2 +- x/ibc-transfer/types/transfer.pb.go | 151 +++++++++------------------- 4 files changed, 60 insertions(+), 118 deletions(-) diff --git a/proto/ibc/transfer/transfer.proto b/proto/ibc/transfer/transfer.proto index dbf4bd53d15e..2c2442d69bea 100644 --- a/proto/ibc/transfer/transfer.proto +++ b/proto/ibc/transfer/transfer.proto @@ -16,20 +16,16 @@ message MsgTransfer { string source_channel = 2 [(gogoproto.moretags) = "yaml:\"source_channel\""]; // the tokens to be transferred cosmos.Coin token = 3 [(gogoproto.nullable) = false]; - // fungible token denomination trace info for source tracking - DenomTrace trace = 4 [(gogoproto.nullable) = false]; // the sender address - bytes sender = 5 [ - (gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress" - ]; + bytes sender = 4 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; // the recipient address on the destination chain - string receiver = 6; + string receiver = 5; // Timeout height relative to the current block height. // The timeout is disabled when set to 0. - uint64 timeout_height = 7 [(gogoproto.moretags) = "yaml:\"timeout_height\""]; + uint64 timeout_height = 6 [(gogoproto.moretags) = "yaml:\"timeout_height\""]; // Timeout timestamp (in nanoseconds) relative to the current block timestamp. // The timeout is disabled when set to 0. - uint64 timeout_timestamp = 8 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""]; + uint64 timeout_timestamp = 7 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""]; } // FungibleTokenPacketData defines a struct for the packet payload @@ -64,3 +60,4 @@ message DenomTrace { string trace = 1; // base denomination of the relayed fungible token string base_denom = 2; +} \ No newline at end of file diff --git a/x/ibc-transfer/types/query.pb.go b/x/ibc-transfer/types/query.pb.go index fe68c4c91c9a..d37ab20b0fba 100644 --- a/x/ibc-transfer/types/query.pb.go +++ b/x/ibc-transfer/types/query.pb.go @@ -121,7 +121,7 @@ func (m *QueryDenomTraceResponse) GetDenomTrace() *DenomTrace { return nil } -// QueryConnectionsRequest is the request type for the Query/Connections RPC method +// QueryConnectionsRequest is the request type for the Query/DenomTraces RPC method type QueryDenomTracesRequest struct { Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -166,7 +166,7 @@ func (m *QueryDenomTracesRequest) GetPagination() *query.PageRequest { return nil } -// QueryConnectionsResponse is the response type for the Query/Connections RPC method. +// QueryConnectionsResponse is the response type for the Query/DenomTraces RPC method. type QueryDenomTracesResponse struct { // list of stored connections of the chain. DenomTraces Traces `protobuf:"bytes,1,rep,name=denom_traces,json=denomTraces,proto3,castrepeated=Traces" json:"denom_traces"` @@ -270,9 +270,9 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type QueryClient interface { - // DenomTrace queries an IBC connection end. + // DenomTrace queries a denomination trace info. DenomTrace(ctx context.Context, in *QueryDenomTraceRequest, opts ...grpc.CallOption) (*QueryDenomTraceResponse, error) - // DenomTraces queries all the IBC connections of a chain. + // DenomTraces queries all denomination traces. DenomTraces(ctx context.Context, in *QueryDenomTracesRequest, opts ...grpc.CallOption) (*QueryDenomTracesResponse, error) } @@ -304,9 +304,9 @@ func (c *queryClient) DenomTraces(ctx context.Context, in *QueryDenomTracesReque // QueryServer is the server API for Query service. type QueryServer interface { - // DenomTrace queries an IBC connection end. + // DenomTrace queries a denomination trace info. DenomTrace(context.Context, *QueryDenomTraceRequest) (*QueryDenomTraceResponse, error) - // DenomTraces queries all the IBC connections of a chain. + // DenomTraces queries all denomination traces. DenomTraces(context.Context, *QueryDenomTracesRequest) (*QueryDenomTracesResponse, error) } diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index b6406c53de75..90fbd944fce9 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -123,7 +123,7 @@ func (t Traces) Validate() error { } if err := trace.Validate(); err != nil { - sdkerrors.Wrapf(err, "failed denom trace %d validation", i) + return sdkerrors.Wrapf(err, "failed denom trace %d validation", i) } seenTraces[hash] = true } diff --git a/x/ibc-transfer/types/transfer.pb.go b/x/ibc-transfer/types/transfer.pb.go index a914568b4223..cbb682f31aba 100644 --- a/x/ibc-transfer/types/transfer.pb.go +++ b/x/ibc-transfer/types/transfer.pb.go @@ -35,18 +35,16 @@ type MsgTransfer struct { SourceChannel string `protobuf:"bytes,2,opt,name=source_channel,json=sourceChannel,proto3" json:"source_channel,omitempty" yaml:"source_channel"` // the tokens to be transferred Token types.Coin `protobuf:"bytes,3,opt,name=token,proto3" json:"token"` - // fungible token denomination trace info for source tracking - Trace DenomTrace `protobuf:"bytes,4,opt,name=trace,proto3" json:"trace"` // the sender address - Sender github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,5,opt,name=sender,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"sender,omitempty"` + Sender github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,4,opt,name=sender,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"sender,omitempty"` // the recipient address on the destination chain - Receiver string `protobuf:"bytes,6,opt,name=receiver,proto3" json:"receiver,omitempty"` + Receiver string `protobuf:"bytes,5,opt,name=receiver,proto3" json:"receiver,omitempty"` // Timeout height relative to the current block height. // The timeout is disabled when set to 0. - TimeoutHeight uint64 `protobuf:"varint,7,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty" yaml:"timeout_height"` + TimeoutHeight uint64 `protobuf:"varint,6,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty" yaml:"timeout_height"` // Timeout timestamp (in nanoseconds) relative to the current block timestamp. // The timeout is disabled when set to 0. - TimeoutTimestamp uint64 `protobuf:"varint,8,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty" yaml:"timeout_timestamp"` + TimeoutTimestamp uint64 `protobuf:"varint,7,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty" yaml:"timeout_timestamp"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -103,13 +101,6 @@ func (m *MsgTransfer) GetToken() types.Coin { return types.Coin{} } -func (m *MsgTransfer) GetTrace() DenomTrace { - if m != nil { - return m.Trace - } - return DenomTrace{} -} - func (m *MsgTransfer) GetSender() github_com_cosmos_cosmos_sdk_types.AccAddress { if m != nil { return m.Sender @@ -278,13 +269,13 @@ func (m *FungibleTokenPacketAcknowledgement) GetError() string { return "" } -// DenomTrace contains the base denomination for ICS20 fungible tokens and the souce tracing +// DenomTrace contains the base denomination for ICS20 fungible tokens and the source tracing // information type DenomTrace struct { // chain of port/channel identifiers used for tracing the source of the fungible token Trace string `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` // base denomination of the relayed fungible token - BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty" yaml:"base_denom"` + BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty"` } func (m *DenomTrace) Reset() { *m = DenomTrace{} } @@ -344,42 +335,41 @@ func init() { func init() { proto.RegisterFile("ibc/transfer/transfer.proto", fileDescriptor_08134a70fd29e656) } var fileDescriptor_08134a70fd29e656 = []byte{ - // 556 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0x8d, 0x69, 0x92, 0xb6, 0xdb, 0x16, 0xd1, 0xa5, 0x0d, 0x26, 0x20, 0x3b, 0xf2, 0x29, 0x97, - 0xd8, 0x2a, 0x54, 0x42, 0xe2, 0x44, 0xd2, 0x0a, 0x51, 0x21, 0xa4, 0x6a, 0x95, 0x03, 0xe2, 0x12, - 0xd9, 0xeb, 0xc1, 0xb1, 0x12, 0x7b, 0xa3, 0xdd, 0x35, 0xd0, 0xbf, 0xe0, 0x57, 0xf8, 0x8b, 0x1e, - 0x7b, 0xe4, 0x80, 0x2c, 0x94, 0xfc, 0x41, 0x8e, 0x9c, 0xd0, 0x7a, 0x1d, 0x27, 0x91, 0x2a, 0x24, - 0x4e, 0xde, 0x37, 0xef, 0xcd, 0x78, 0xe6, 0xed, 0x2c, 0x7a, 0x16, 0x07, 0xd4, 0x93, 0xdc, 0x4f, - 0xc5, 0x67, 0xe0, 0xd5, 0xc1, 0x9d, 0x71, 0x26, 0x19, 0x3e, 0x8c, 0x03, 0xea, 0xae, 0x62, 0xed, - 0x93, 0x88, 0x45, 0xac, 0x20, 0x3c, 0x75, 0xd2, 0x9a, 0xf6, 0x63, 0xca, 0x44, 0xc2, 0x84, 0xa7, - 0x3f, 0x3a, 0xe8, 0xfc, 0xda, 0x41, 0x07, 0x1f, 0x44, 0x34, 0x2c, 0x53, 0xf1, 0x2b, 0x74, 0x20, - 0x58, 0xc6, 0x29, 0x8c, 0x66, 0x8c, 0x4b, 0xd3, 0xe8, 0x18, 0xdd, 0xfd, 0x41, 0x6b, 0x99, 0xdb, - 0xf8, 0xc6, 0x4f, 0xa6, 0xaf, 0x9d, 0x0d, 0xd2, 0x21, 0x48, 0xa3, 0x6b, 0xc6, 0x25, 0x7e, 0x83, - 0x1e, 0x96, 0x1c, 0x1d, 0xfb, 0x69, 0x0a, 0x53, 0xf3, 0x41, 0x91, 0xfb, 0x74, 0x99, 0xdb, 0xa7, - 0x5b, 0xb9, 0x25, 0xef, 0x90, 0x23, 0x1d, 0xb8, 0xd0, 0x18, 0x77, 0x51, 0x43, 0xb2, 0x09, 0xa4, - 0xe6, 0x4e, 0xc7, 0xe8, 0x1e, 0xbc, 0x38, 0x74, 0xcb, 0x46, 0x2f, 0x58, 0x9c, 0x0e, 0xea, 0xb7, - 0xb9, 0x5d, 0x23, 0x5a, 0x80, 0xcf, 0x51, 0x43, 0x72, 0x9f, 0x82, 0x59, 0x2f, 0x94, 0xa6, 0xbb, - 0x39, 0xbd, 0x7b, 0x09, 0x29, 0x4b, 0x86, 0x8a, 0xaf, 0xb2, 0x14, 0xc0, 0x57, 0xa8, 0x29, 0x20, - 0x0d, 0x81, 0x9b, 0x8d, 0x8e, 0xd1, 0x3d, 0x1c, 0x9c, 0xfd, 0xc9, 0xed, 0x5e, 0x14, 0xcb, 0x71, - 0x16, 0xb8, 0x94, 0x25, 0xde, 0x96, 0x3d, 0x3d, 0x11, 0x4e, 0x3c, 0x79, 0x33, 0x03, 0xe1, 0xf6, - 0x29, 0xed, 0x87, 0x21, 0x07, 0x21, 0x48, 0x59, 0x00, 0xb7, 0xd1, 0x1e, 0x07, 0x0a, 0xf1, 0x17, - 0xe0, 0x66, 0x53, 0x8d, 0x49, 0x2a, 0xac, 0x8c, 0x90, 0x71, 0x02, 0x2c, 0x93, 0xa3, 0x31, 0xc4, - 0xd1, 0x58, 0x9a, 0xbb, 0x1d, 0xa3, 0x5b, 0xdf, 0x34, 0x62, 0x9b, 0x77, 0xc8, 0x51, 0x19, 0x78, - 0x57, 0x60, 0x7c, 0x85, 0x8e, 0x57, 0x0a, 0xf5, 0x15, 0xd2, 0x4f, 0x66, 0xe6, 0x5e, 0x51, 0xe4, - 0xf9, 0x32, 0xb7, 0xcd, 0xed, 0x22, 0x95, 0xc4, 0x21, 0x8f, 0xca, 0xd8, 0xb0, 0x0a, 0xfd, 0x30, - 0xd0, 0x93, 0xb7, 0x59, 0x1a, 0xc5, 0xc1, 0x14, 0x86, 0xca, 0xbb, 0x6b, 0x9f, 0x4e, 0x40, 0x5e, - 0xfa, 0xd2, 0xc7, 0x27, 0xa8, 0x11, 0x2a, 0xab, 0xf4, 0x25, 0x13, 0x0d, 0x70, 0x0b, 0x35, 0xfd, - 0x84, 0x65, 0xa9, 0x2c, 0xee, 0xaf, 0x4e, 0x4a, 0xb4, 0xf6, 0x7c, 0xe7, 0x7f, 0x3c, 0x6f, 0x55, - 0x9e, 0xd7, 0x8b, 0x9f, 0xdc, 0x67, 0x60, 0x63, 0xdb, 0x40, 0x67, 0x88, 0x9c, 0x7b, 0x5a, 0xee, - 0xd3, 0x49, 0xca, 0xbe, 0x4e, 0x21, 0x8c, 0x20, 0x81, 0x54, 0x62, 0x13, 0xed, 0x8a, 0x8c, 0x52, - 0x10, 0xa2, 0xe8, 0x7f, 0x8f, 0xac, 0xa0, 0x9a, 0x0b, 0x38, 0x67, 0x5c, 0x2f, 0x20, 0xd1, 0xc0, - 0xf9, 0x88, 0xd0, 0xba, 0x49, 0xa5, 0xd1, 0xd3, 0x94, 0xb3, 0xeb, 0x6e, 0xcf, 0x11, 0x0a, 0x7c, - 0x01, 0x23, 0x6d, 0x8b, 0xde, 0xdf, 0xd3, 0x65, 0x6e, 0x1f, 0x6b, 0xc7, 0xd7, 0x9c, 0x43, 0xf6, - 0x15, 0x28, 0x0a, 0x0e, 0xde, 0xdf, 0xce, 0x2d, 0xe3, 0x6e, 0x6e, 0x19, 0xbf, 0xe7, 0x96, 0xf1, - 0x7d, 0x61, 0xd5, 0xee, 0x16, 0x56, 0xed, 0xe7, 0xc2, 0xaa, 0x7d, 0x3a, 0xfb, 0xe7, 0x76, 0x7d, - 0xf3, 0xe2, 0x80, 0xf6, 0xd6, 0x2f, 0x5a, 0x2d, 0x5b, 0xd0, 0x2c, 0x9e, 0xe5, 0xcb, 0xbf, 0x01, - 0x00, 0x00, 0xff, 0xff, 0x8a, 0x04, 0xee, 0x57, 0xee, 0x03, 0x00, 0x00, + // 533 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x4d, 0x6f, 0xd3, 0x30, + 0x18, 0x6e, 0x58, 0xdb, 0x6d, 0x6e, 0x87, 0xc0, 0x8c, 0x11, 0x0a, 0xa4, 0x55, 0x4e, 0xbd, 0x34, + 0xd1, 0x00, 0x09, 0x89, 0x13, 0xed, 0x26, 0xc4, 0x84, 0x90, 0x26, 0xab, 0x27, 0x2e, 0x55, 0xe2, + 0xbc, 0xa4, 0x51, 0x1b, 0xbb, 0xb2, 0x1d, 0x60, 0xff, 0x82, 0x5f, 0xc1, 0x9d, 0x7f, 0xb1, 0xe3, + 0x8e, 0x9c, 0x2a, 0xd4, 0xfe, 0x83, 0x1e, 0x39, 0x21, 0xc7, 0x6e, 0xd7, 0x4a, 0x08, 0x71, 0xb2, + 0x9f, 0xe7, 0xfd, 0xd0, 0xfb, 0x3c, 0x7e, 0x8d, 0x9e, 0x64, 0x31, 0x0d, 0x95, 0x88, 0x98, 0xfc, + 0x04, 0x62, 0x73, 0x09, 0x66, 0x82, 0x2b, 0x8e, 0x9b, 0x59, 0x4c, 0x83, 0x35, 0xd7, 0x3a, 0x4e, + 0x79, 0xca, 0xcb, 0x40, 0xa8, 0x6f, 0x26, 0xa7, 0xf5, 0x80, 0x72, 0x99, 0x73, 0x19, 0x9a, 0xc3, + 0x90, 0xfe, 0xf7, 0x3d, 0xd4, 0xf8, 0x20, 0xd3, 0xa1, 0x2d, 0xc5, 0xaf, 0x50, 0x43, 0xf2, 0x42, + 0x50, 0x18, 0xcd, 0xb8, 0x50, 0xae, 0xd3, 0x71, 0xba, 0x87, 0x83, 0x93, 0xd5, 0xbc, 0x8d, 0xaf, + 0xa2, 0x7c, 0xfa, 0xda, 0xdf, 0x0a, 0xfa, 0x04, 0x19, 0x74, 0xc9, 0x85, 0xc2, 0x6f, 0xd0, 0x5d, + 0x1b, 0xa3, 0xe3, 0x88, 0x31, 0x98, 0xba, 0x77, 0xca, 0xda, 0xc7, 0xab, 0x79, 0xfb, 0xe1, 0x4e, + 0xad, 0x8d, 0xfb, 0xe4, 0xc8, 0x10, 0x67, 0x06, 0xe3, 0x2e, 0xaa, 0x29, 0x3e, 0x01, 0xe6, 0xee, + 0x75, 0x9c, 0x6e, 0xe3, 0x79, 0x33, 0xb0, 0x83, 0x9e, 0xf1, 0x8c, 0x0d, 0xaa, 0xd7, 0xf3, 0x76, + 0x85, 0x98, 0x04, 0x7c, 0x81, 0xea, 0x12, 0x58, 0x02, 0xc2, 0xad, 0x76, 0x9c, 0x6e, 0x73, 0x70, + 0xfa, 0x7b, 0xde, 0xee, 0xa5, 0x99, 0x1a, 0x17, 0x71, 0x40, 0x79, 0x1e, 0xee, 0x08, 0xed, 0xc9, + 0x64, 0x12, 0xaa, 0xab, 0x19, 0xc8, 0xa0, 0x4f, 0x69, 0x3f, 0x49, 0x04, 0x48, 0x49, 0x6c, 0x03, + 0xdc, 0x42, 0x07, 0x02, 0x28, 0x64, 0x9f, 0x41, 0xb8, 0x35, 0x3d, 0x30, 0xd9, 0x60, 0x2d, 0x49, + 0x65, 0x39, 0xf0, 0x42, 0x8d, 0xc6, 0x90, 0xa5, 0x63, 0xe5, 0xd6, 0x3b, 0x4e, 0xb7, 0xba, 0x2d, + 0x69, 0x37, 0xee, 0x93, 0x23, 0x4b, 0xbc, 0x2b, 0x31, 0xbe, 0x40, 0xf7, 0xd7, 0x19, 0xfa, 0x94, + 0x2a, 0xca, 0x67, 0xee, 0x7e, 0xd9, 0xe4, 0xe9, 0x6a, 0xde, 0x76, 0x77, 0x9b, 0x6c, 0x52, 0x7c, + 0x72, 0xcf, 0x72, 0xc3, 0x0d, 0xf5, 0xc3, 0x41, 0x8f, 0xde, 0x16, 0x2c, 0xcd, 0xe2, 0x29, 0x0c, + 0xb5, 0x0b, 0x97, 0x11, 0x9d, 0x80, 0x3a, 0x8f, 0x54, 0x84, 0x8f, 0x51, 0x2d, 0x01, 0xc6, 0x73, + 0xf3, 0x5c, 0xc4, 0x00, 0x7c, 0x82, 0xea, 0x51, 0xce, 0x0b, 0xa6, 0xca, 0x97, 0xa8, 0x12, 0x8b, + 0xf0, 0x4b, 0x54, 0x53, 0x22, 0xa2, 0x60, 0x7d, 0x76, 0x83, 0xed, 0xdd, 0x09, 0xce, 0x75, 0xed, + 0x50, 0xc7, 0x37, 0x9e, 0x6b, 0xa0, 0xbb, 0x6d, 0x79, 0x7e, 0xf8, 0x3f, 0x06, 0xfa, 0x43, 0xe4, + 0xff, 0x65, 0xe4, 0x3e, 0x9d, 0x30, 0xfe, 0x65, 0x0a, 0x49, 0x0a, 0x39, 0x30, 0x85, 0x5d, 0xb4, + 0x2f, 0x0b, 0x4a, 0x41, 0xca, 0x72, 0xfe, 0x03, 0xb2, 0x86, 0x5a, 0x17, 0x08, 0xc1, 0x85, 0x59, + 0x25, 0x62, 0x80, 0xdf, 0x47, 0xe8, 0x76, 0x48, 0x9d, 0x63, 0xd4, 0x58, 0xed, 0x66, 0xda, 0x67, + 0x08, 0xc5, 0x91, 0x84, 0x91, 0xb1, 0xc5, 0x94, 0x1f, 0x6a, 0xa6, 0xac, 0x1c, 0xbc, 0xbf, 0x5e, + 0x78, 0xce, 0xcd, 0xc2, 0x73, 0x7e, 0x2d, 0x3c, 0xe7, 0xdb, 0xd2, 0xab, 0xdc, 0x2c, 0xbd, 0xca, + 0xcf, 0xa5, 0x57, 0xf9, 0x78, 0xfa, 0xcf, 0x35, 0xfa, 0x1a, 0x66, 0x31, 0xed, 0xdd, 0x7e, 0x42, + 0xbd, 0x55, 0x71, 0xbd, 0xfc, 0x49, 0x2f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x97, 0xc5, 0x07, + 0x86, 0xa1, 0x03, 0x00, 0x00, } func (m *MsgTransfer) Marshal() (dAtA []byte, err error) { @@ -405,37 +395,27 @@ func (m *MsgTransfer) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.TimeoutTimestamp != 0 { i = encodeVarintTransfer(dAtA, i, uint64(m.TimeoutTimestamp)) i-- - dAtA[i] = 0x40 + dAtA[i] = 0x38 } if m.TimeoutHeight != 0 { i = encodeVarintTransfer(dAtA, i, uint64(m.TimeoutHeight)) i-- - dAtA[i] = 0x38 + dAtA[i] = 0x30 } if len(m.Receiver) > 0 { i -= len(m.Receiver) copy(dAtA[i:], m.Receiver) i = encodeVarintTransfer(dAtA, i, uint64(len(m.Receiver))) i-- - dAtA[i] = 0x32 + dAtA[i] = 0x2a } if len(m.Sender) > 0 { i -= len(m.Sender) copy(dAtA[i:], m.Sender) i = encodeVarintTransfer(dAtA, i, uint64(len(m.Sender))) i-- - dAtA[i] = 0x2a - } - { - size, err := m.Trace.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTransfer(dAtA, i, uint64(size)) + dAtA[i] = 0x22 } - i-- - dAtA[i] = 0x22 { size, err := m.Token.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -626,8 +606,6 @@ func (m *MsgTransfer) Size() (n int) { } l = m.Token.Size() n += 1 + l + sovTransfer(uint64(l)) - l = m.Trace.Size() - n += 1 + l + sovTransfer(uint64(l)) l = len(m.Sender) if l > 0 { n += 1 + l + sovTransfer(uint64(l)) @@ -837,39 +815,6 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTransfer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Trace.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) } @@ -903,7 +848,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { m.Sender = []byte{} } iNdEx = postIndex - case 6: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) } @@ -935,7 +880,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { } m.Receiver = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 7: + case 6: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TimeoutHeight", wireType) } @@ -954,7 +899,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { break } } - case 8: + case 7: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType) } From 441fe73ec961f5ebcb4b9a1e5e95a22951e3ccf3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 19:48:42 +0200 Subject: [PATCH 16/41] GRPC tests --- x/ibc-transfer/keeper/grpc_query.go | 12 +- x/ibc-transfer/keeper/grpc_query_test.go | 136 +++++++++++++++++++++++ x/ibc-transfer/keeper/keeper.go | 5 +- x/ibc-transfer/keeper/keeper_test.go | 7 ++ 4 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 x/ibc-transfer/keeper/grpc_query_test.go diff --git a/x/ibc-transfer/keeper/grpc_query.go b/x/ibc-transfer/keeper/grpc_query.go index 78bac9056267..aeec782de6e9 100644 --- a/x/ibc-transfer/keeper/grpc_query.go +++ b/x/ibc-transfer/keeper/grpc_query.go @@ -2,11 +2,13 @@ package keeper import ( "context" + "encoding/hex" "fmt" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + tmbytes "github.com/tendermint/tendermint/libs/bytes" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -24,12 +26,18 @@ func (q Keeper) DenomTrace(c context.Context, req *types.QueryDenomTraceRequest) return nil, status.Error(codes.InvalidArgument, "empty request") } - if err := tmtypes.ValidateHash([]byte(req.Hash)); err != nil { + hash, err := hex.DecodeString(req.Hash) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + hash = tmbytes.HexBytes(hash) + if err := tmtypes.ValidateHash(hash); err != nil { return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid denom trace hash %s, %s", req.Hash, err)) } ctx := sdk.UnwrapSDKContext(c) - denomTrace, found := q.GetDenomTrace(ctx, []byte(req.Hash)) + denomTrace, found := q.GetDenomTrace(ctx, hash) if !found { return nil, status.Error( codes.NotFound, diff --git a/x/ibc-transfer/keeper/grpc_query_test.go b/x/ibc-transfer/keeper/grpc_query_test.go new file mode 100644 index 000000000000..99d61356e185 --- /dev/null +++ b/x/ibc-transfer/keeper/grpc_query_test.go @@ -0,0 +1,136 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" +) + +func (suite *KeeperTestSuite) TestQueryConnection() { + var ( + req *types.QueryDenomTraceRequest + expTrace types.DenomTrace + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "invalid hex hash", + func() { + req = &types.QueryDenomTraceRequest{ + Hash: "!@#!@#!", + } + }, + false, + }, + { + "not found denom trace", + func() { + expTrace.Trace = "transfer/channelToA/transfer/channelToB" + expTrace.BaseDenom = "uatom" + req = &types.QueryDenomTraceRequest{ + Hash: expTrace.Hash().String(), + } + }, + false, + }, + { + "success", + func() { + expTrace.Trace = "transfer/channelToA/transfer/channelToB" + expTrace.BaseDenom = "uatom" + suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), expTrace) + + req = &types.QueryDenomTraceRequest{ + Hash: expTrace.Hash().String(), + } + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + + res, err := suite.queryClient.DenomTrace(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(&expTrace, res.DenomTrace) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryConnections() { + var ( + req *types.QueryDenomTracesRequest + expTraces = types.Traces(nil) + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty pagination", + func() { + req = &types.QueryDenomTracesRequest{} + }, + true, + }, + { + "success", + func() { + expTraces = append(expTraces, types.DenomTrace{Trace: "", BaseDenom: "uatom"}) + expTraces = append(expTraces, types.DenomTrace{Trace: "transfer/channelToB", BaseDenom: "uatom"}) + expTraces = append(expTraces, types.DenomTrace{Trace: "transfer/channelToA/transfer/channelToB", BaseDenom: "uatom"}) + + for _, trace := range expTraces { + suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), trace) + } + + req = &types.QueryDenomTracesRequest{ + Pagination: &query.PageRequest{ + Limit: 5, + CountTotal: false, + }, + } + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + + res, err := suite.queryClient.DenomTraces(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + // FIXME: response is non-deterministic so we can't use Equal! + suite.Require().ElementsMatch(expTraces, res.DenomTraces) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/x/ibc-transfer/keeper/keeper.go b/x/ibc-transfer/keeper/keeper.go index 5f5b50993c0e..b4683838effc 100644 --- a/x/ibc-transfer/keeper/keeper.go +++ b/x/ibc-transfer/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "fmt" + tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" @@ -111,7 +112,7 @@ func (k Keeper) SetPort(ctx sdk.Context, portID string) { } // GetDenomTrace retreives the full identifiers trace and base denomination from the store. -func (k Keeper) GetDenomTrace(ctx sdk.Context, denomTraceHash []byte) (types.DenomTrace, bool) { +func (k Keeper) GetDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) (types.DenomTrace, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) bz := store.Get(denomTraceHash) if bz == nil { @@ -124,7 +125,7 @@ func (k Keeper) GetDenomTrace(ctx sdk.Context, denomTraceHash []byte) (types.Den } // HasDenomTrace checks if a the key with the given denomination trace hash exists on the store. -func (k Keeper) HasDenomTrace(ctx sdk.Context, denomTraceHash []byte) bool { +func (k Keeper) HasDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) bool { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) return store.Has(denomTraceHash) } diff --git a/x/ibc-transfer/keeper/keeper_test.go b/x/ibc-transfer/keeper/keeper_test.go index b8f90634542c..b589d51c03ca 100644 --- a/x/ibc-transfer/keeper/keeper_test.go +++ b/x/ibc-transfer/keeper/keeper_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" @@ -19,12 +20,18 @@ type KeeperTestSuite struct { // testing chains used for convenience and readability chainA *ibctesting.TestChain chainB *ibctesting.TestChain + + queryClient types.QueryClient } func (suite *KeeperTestSuite) SetupTest() { suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + + queryHelper := baseapp.NewQueryServerTestHelper(suite.chainA.GetContext(), suite.chainA.App.InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, suite.chainA.App.TransferKeeper) + suite.queryClient = types.NewQueryClient(queryHelper) } func (suite *KeeperTestSuite) TestGetTransferAccount() { From 3e7935f992b13df0d8d6225f3401161a7cd46ea7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 20:02:13 +0200 Subject: [PATCH 17/41] remove field from packet --- proto/ibc/transfer/query.proto | 2 +- proto/ibc/transfer/transfer.proto | 8 +- x/ibc-transfer/types/transfer.pb.go | 133 ++++++++-------------------- 3 files changed, 43 insertions(+), 100 deletions(-) diff --git a/proto/ibc/transfer/query.proto b/proto/ibc/transfer/query.proto index 862707b95c45..914c7bd38b5b 100644 --- a/proto/ibc/transfer/query.proto +++ b/proto/ibc/transfer/query.proto @@ -37,7 +37,7 @@ message QueryDenomTracesRequest { message QueryDenomTracesResponse { // list of stored connections of the chain. repeated DenomTrace denom_traces = 1 [ - (gogoproto.castrepeated) = "Traces", + (gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false ]; // pagination response diff --git a/proto/ibc/transfer/transfer.proto b/proto/ibc/transfer/transfer.proto index 2c2442d69bea..b037e3bfd0b2 100644 --- a/proto/ibc/transfer/transfer.proto +++ b/proto/ibc/transfer/transfer.proto @@ -36,12 +36,10 @@ message FungibleTokenPacketData { string denom = 1; // the token amount to be transferred uint64 amount = 2; - // fungible token denomination trace info for source tracking - DenomTrace trace = 3 [(gogoproto.nullable) = false]; // the sender address - string sender = 4; + string sender = 3; // the recipient address on the destination chain - string receiver = 5; + string receiver = 4; } // FungibleTokenPacketAcknowledgement contains a boolean success flag and an @@ -60,4 +58,4 @@ message DenomTrace { string trace = 1; // base denomination of the relayed fungible token string base_denom = 2; -} \ No newline at end of file +} diff --git a/x/ibc-transfer/types/transfer.pb.go b/x/ibc-transfer/types/transfer.pb.go index cbb682f31aba..2420a6767295 100644 --- a/x/ibc-transfer/types/transfer.pb.go +++ b/x/ibc-transfer/types/transfer.pb.go @@ -137,12 +137,10 @@ type FungibleTokenPacketData struct { Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` // the token amount to be transferred Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` - // fungible token denomination trace info for source tracking - Trace DenomTrace `protobuf:"bytes,3,opt,name=trace,proto3" json:"trace"` // the sender address - Sender string `protobuf:"bytes,4,opt,name=sender,proto3" json:"sender,omitempty"` + Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` // the recipient address on the destination chain - Receiver string `protobuf:"bytes,5,opt,name=receiver,proto3" json:"receiver,omitempty"` + Receiver string `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"` } func (m *FungibleTokenPacketData) Reset() { *m = FungibleTokenPacketData{} } @@ -192,13 +190,6 @@ func (m *FungibleTokenPacketData) GetAmount() uint64 { return 0 } -func (m *FungibleTokenPacketData) GetTrace() DenomTrace { - if m != nil { - return m.Trace - } - return DenomTrace{} -} - func (m *FungibleTokenPacketData) GetSender() string { if m != nil { return m.Sender @@ -335,41 +326,40 @@ func init() { func init() { proto.RegisterFile("ibc/transfer/transfer.proto", fileDescriptor_08134a70fd29e656) } var fileDescriptor_08134a70fd29e656 = []byte{ - // 533 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x4d, 0x6f, 0xd3, 0x30, - 0x18, 0x6e, 0x58, 0xdb, 0x6d, 0x6e, 0x87, 0xc0, 0x8c, 0x11, 0x0a, 0xa4, 0x55, 0x4e, 0xbd, 0x34, - 0xd1, 0x00, 0x09, 0x89, 0x13, 0xed, 0x26, 0xc4, 0x84, 0x90, 0x26, 0xab, 0x27, 0x2e, 0x55, 0xe2, - 0xbc, 0xa4, 0x51, 0x1b, 0xbb, 0xb2, 0x1d, 0x60, 0xff, 0x82, 0x5f, 0xc1, 0x9d, 0x7f, 0xb1, 0xe3, - 0x8e, 0x9c, 0x2a, 0xd4, 0xfe, 0x83, 0x1e, 0x39, 0x21, 0xc7, 0x6e, 0xd7, 0x4a, 0x08, 0x71, 0xb2, - 0x9f, 0xe7, 0xfd, 0xd0, 0xfb, 0x3c, 0x7e, 0x8d, 0x9e, 0x64, 0x31, 0x0d, 0x95, 0x88, 0x98, 0xfc, - 0x04, 0x62, 0x73, 0x09, 0x66, 0x82, 0x2b, 0x8e, 0x9b, 0x59, 0x4c, 0x83, 0x35, 0xd7, 0x3a, 0x4e, - 0x79, 0xca, 0xcb, 0x40, 0xa8, 0x6f, 0x26, 0xa7, 0xf5, 0x80, 0x72, 0x99, 0x73, 0x19, 0x9a, 0xc3, - 0x90, 0xfe, 0xf7, 0x3d, 0xd4, 0xf8, 0x20, 0xd3, 0xa1, 0x2d, 0xc5, 0xaf, 0x50, 0x43, 0xf2, 0x42, - 0x50, 0x18, 0xcd, 0xb8, 0x50, 0xae, 0xd3, 0x71, 0xba, 0x87, 0x83, 0x93, 0xd5, 0xbc, 0x8d, 0xaf, - 0xa2, 0x7c, 0xfa, 0xda, 0xdf, 0x0a, 0xfa, 0x04, 0x19, 0x74, 0xc9, 0x85, 0xc2, 0x6f, 0xd0, 0x5d, - 0x1b, 0xa3, 0xe3, 0x88, 0x31, 0x98, 0xba, 0x77, 0xca, 0xda, 0xc7, 0xab, 0x79, 0xfb, 0xe1, 0x4e, - 0xad, 0x8d, 0xfb, 0xe4, 0xc8, 0x10, 0x67, 0x06, 0xe3, 0x2e, 0xaa, 0x29, 0x3e, 0x01, 0xe6, 0xee, - 0x75, 0x9c, 0x6e, 0xe3, 0x79, 0x33, 0xb0, 0x83, 0x9e, 0xf1, 0x8c, 0x0d, 0xaa, 0xd7, 0xf3, 0x76, - 0x85, 0x98, 0x04, 0x7c, 0x81, 0xea, 0x12, 0x58, 0x02, 0xc2, 0xad, 0x76, 0x9c, 0x6e, 0x73, 0x70, - 0xfa, 0x7b, 0xde, 0xee, 0xa5, 0x99, 0x1a, 0x17, 0x71, 0x40, 0x79, 0x1e, 0xee, 0x08, 0xed, 0xc9, - 0x64, 0x12, 0xaa, 0xab, 0x19, 0xc8, 0xa0, 0x4f, 0x69, 0x3f, 0x49, 0x04, 0x48, 0x49, 0x6c, 0x03, - 0xdc, 0x42, 0x07, 0x02, 0x28, 0x64, 0x9f, 0x41, 0xb8, 0x35, 0x3d, 0x30, 0xd9, 0x60, 0x2d, 0x49, - 0x65, 0x39, 0xf0, 0x42, 0x8d, 0xc6, 0x90, 0xa5, 0x63, 0xe5, 0xd6, 0x3b, 0x4e, 0xb7, 0xba, 0x2d, - 0x69, 0x37, 0xee, 0x93, 0x23, 0x4b, 0xbc, 0x2b, 0x31, 0xbe, 0x40, 0xf7, 0xd7, 0x19, 0xfa, 0x94, - 0x2a, 0xca, 0x67, 0xee, 0x7e, 0xd9, 0xe4, 0xe9, 0x6a, 0xde, 0x76, 0x77, 0x9b, 0x6c, 0x52, 0x7c, - 0x72, 0xcf, 0x72, 0xc3, 0x0d, 0xf5, 0xc3, 0x41, 0x8f, 0xde, 0x16, 0x2c, 0xcd, 0xe2, 0x29, 0x0c, - 0xb5, 0x0b, 0x97, 0x11, 0x9d, 0x80, 0x3a, 0x8f, 0x54, 0x84, 0x8f, 0x51, 0x2d, 0x01, 0xc6, 0x73, - 0xf3, 0x5c, 0xc4, 0x00, 0x7c, 0x82, 0xea, 0x51, 0xce, 0x0b, 0xa6, 0xca, 0x97, 0xa8, 0x12, 0x8b, - 0xf0, 0x4b, 0x54, 0x53, 0x22, 0xa2, 0x60, 0x7d, 0x76, 0x83, 0xed, 0xdd, 0x09, 0xce, 0x75, 0xed, - 0x50, 0xc7, 0x37, 0x9e, 0x6b, 0xa0, 0xbb, 0x6d, 0x79, 0x7e, 0xf8, 0x3f, 0x06, 0xfa, 0x43, 0xe4, - 0xff, 0x65, 0xe4, 0x3e, 0x9d, 0x30, 0xfe, 0x65, 0x0a, 0x49, 0x0a, 0x39, 0x30, 0x85, 0x5d, 0xb4, - 0x2f, 0x0b, 0x4a, 0x41, 0xca, 0x72, 0xfe, 0x03, 0xb2, 0x86, 0x5a, 0x17, 0x08, 0xc1, 0x85, 0x59, - 0x25, 0x62, 0x80, 0xdf, 0x47, 0xe8, 0x76, 0x48, 0x9d, 0x63, 0xd4, 0x58, 0xed, 0x66, 0xda, 0x67, - 0x08, 0xc5, 0x91, 0x84, 0x91, 0xb1, 0xc5, 0x94, 0x1f, 0x6a, 0xa6, 0xac, 0x1c, 0xbc, 0xbf, 0x5e, - 0x78, 0xce, 0xcd, 0xc2, 0x73, 0x7e, 0x2d, 0x3c, 0xe7, 0xdb, 0xd2, 0xab, 0xdc, 0x2c, 0xbd, 0xca, - 0xcf, 0xa5, 0x57, 0xf9, 0x78, 0xfa, 0xcf, 0x35, 0xfa, 0x1a, 0x66, 0x31, 0xed, 0xdd, 0x7e, 0x42, - 0xbd, 0x55, 0x71, 0xbd, 0xfc, 0x49, 0x2f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x97, 0xc5, 0x07, - 0x86, 0xa1, 0x03, 0x00, 0x00, + // 518 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0xc1, 0x6e, 0x13, 0x31, + 0x10, 0xcd, 0xd2, 0x24, 0x6d, 0x9d, 0x14, 0x81, 0x29, 0x65, 0x09, 0xb0, 0x89, 0xf6, 0x94, 0x4b, + 0xb2, 0x2a, 0x1c, 0x90, 0x38, 0x91, 0xb4, 0x42, 0x54, 0x08, 0xa9, 0xb2, 0x72, 0xe2, 0x12, 0x79, + 0xbd, 0xc3, 0x66, 0x95, 0xac, 0x1d, 0xd9, 0x5e, 0xa0, 0xe2, 0x27, 0xf8, 0x0a, 0xbe, 0xa5, 0xc7, + 0x1e, 0x39, 0x45, 0x28, 0xf9, 0x83, 0x1c, 0x39, 0x21, 0xdb, 0x9b, 0xd0, 0x48, 0x15, 0x27, 0xcf, + 0x7b, 0xf3, 0x66, 0x3c, 0x33, 0x1e, 0xa3, 0x67, 0x59, 0xcc, 0x22, 0x2d, 0x29, 0x57, 0x9f, 0x41, + 0x6e, 0x8d, 0xfe, 0x5c, 0x0a, 0x2d, 0x70, 0x33, 0x8b, 0x59, 0x7f, 0xc3, 0xb5, 0x8e, 0x53, 0x91, + 0x0a, 0xeb, 0x88, 0x8c, 0xe5, 0x34, 0xad, 0x47, 0x4c, 0xa8, 0x5c, 0xa8, 0xc8, 0x1d, 0x8e, 0x0c, + 0x7f, 0xee, 0xa1, 0xc6, 0x47, 0x95, 0x8e, 0xca, 0x50, 0xfc, 0x1a, 0x35, 0x94, 0x28, 0x24, 0x83, + 0xf1, 0x5c, 0x48, 0xed, 0x7b, 0x1d, 0xaf, 0x7b, 0x38, 0x3c, 0x59, 0x2f, 0xda, 0xf8, 0x8a, 0xe6, + 0xb3, 0x37, 0xe1, 0x2d, 0x67, 0x48, 0x90, 0x43, 0x97, 0x42, 0x6a, 0xfc, 0x16, 0xdd, 0x2f, 0x7d, + 0x6c, 0x42, 0x39, 0x87, 0x99, 0x7f, 0xcf, 0xc6, 0x3e, 0x5d, 0x2f, 0xda, 0x8f, 0x77, 0x62, 0x4b, + 0x7f, 0x48, 0x8e, 0x1c, 0x71, 0xe6, 0x30, 0xee, 0xa2, 0x9a, 0x16, 0x53, 0xe0, 0xfe, 0x5e, 0xc7, + 0xeb, 0x36, 0x5e, 0x36, 0xfb, 0x65, 0xa1, 0x67, 0x22, 0xe3, 0xc3, 0xea, 0xf5, 0xa2, 0x5d, 0x21, + 0x4e, 0x80, 0x2f, 0x50, 0x5d, 0x01, 0x4f, 0x40, 0xfa, 0xd5, 0x8e, 0xd7, 0x6d, 0x0e, 0x4f, 0xff, + 0x2c, 0xda, 0xbd, 0x34, 0xd3, 0x93, 0x22, 0xee, 0x33, 0x91, 0x47, 0x3b, 0x8d, 0xf6, 0x54, 0x32, + 0x8d, 0xf4, 0xd5, 0x1c, 0x54, 0x7f, 0xc0, 0xd8, 0x20, 0x49, 0x24, 0x28, 0x45, 0xca, 0x04, 0xb8, + 0x85, 0x0e, 0x24, 0x30, 0xc8, 0xbe, 0x80, 0xf4, 0x6b, 0xa6, 0x60, 0xb2, 0xc5, 0xa6, 0x25, 0x9d, + 0xe5, 0x20, 0x0a, 0x3d, 0x9e, 0x40, 0x96, 0x4e, 0xb4, 0x5f, 0xef, 0x78, 0xdd, 0xea, 0xed, 0x96, + 0x76, 0xfd, 0x21, 0x39, 0x2a, 0x89, 0xf7, 0x16, 0xe3, 0x0b, 0xf4, 0x70, 0xa3, 0x30, 0xa7, 0xd2, + 0x34, 0x9f, 0xfb, 0xfb, 0x36, 0xc9, 0xf3, 0xf5, 0xa2, 0xed, 0xef, 0x26, 0xd9, 0x4a, 0x42, 0xf2, + 0xa0, 0xe4, 0x46, 0x5b, 0xea, 0x3b, 0x7a, 0xf2, 0xae, 0xe0, 0x69, 0x16, 0xcf, 0x60, 0x64, 0x86, + 0x70, 0x49, 0xd9, 0x14, 0xf4, 0x39, 0xd5, 0x14, 0x1f, 0xa3, 0x5a, 0x02, 0x5c, 0xe4, 0xee, 0xb5, + 0x88, 0x03, 0xf8, 0x04, 0xd5, 0x69, 0x2e, 0x0a, 0xae, 0xed, 0x43, 0x54, 0x49, 0x89, 0x0c, 0x5f, + 0x0e, 0x6f, 0xcf, 0xca, 0xef, 0x9a, 0x44, 0x75, 0x77, 0x12, 0xe1, 0x08, 0x85, 0x77, 0x5c, 0x3e, + 0x60, 0x53, 0x2e, 0xbe, 0xce, 0x20, 0x49, 0x21, 0x07, 0xae, 0xb1, 0x8f, 0xf6, 0x55, 0xc1, 0x18, + 0x28, 0x65, 0x2b, 0x39, 0x20, 0x1b, 0x68, 0x2a, 0x04, 0x29, 0x85, 0x74, 0x3b, 0x41, 0x1c, 0x08, + 0x07, 0x08, 0x9d, 0x9b, 0x52, 0x47, 0x92, 0x32, 0x30, 0x1a, 0x6d, 0x8c, 0x4d, 0x17, 0x16, 0xe0, + 0x17, 0x08, 0xc5, 0x54, 0xc1, 0xd8, 0x35, 0xe8, 0xc2, 0x0f, 0x0d, 0x63, 0x23, 0x87, 0x1f, 0xae, + 0x97, 0x81, 0x77, 0xb3, 0x0c, 0xbc, 0xdf, 0xcb, 0xc0, 0xfb, 0xb1, 0x0a, 0x2a, 0x37, 0xab, 0xa0, + 0xf2, 0x6b, 0x15, 0x54, 0x3e, 0x9d, 0xfe, 0x77, 0x1f, 0xbe, 0x45, 0x59, 0xcc, 0x7a, 0xff, 0x7e, + 0x93, 0x59, 0x8f, 0xb8, 0x6e, 0xbf, 0xc4, 0xab, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8f, 0x78, + 0x9d, 0x6a, 0x6a, 0x03, 0x00, 0x00, } func (m *MsgTransfer) Marshal() (dAtA []byte, err error) { @@ -468,25 +458,15 @@ func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) copy(dAtA[i:], m.Receiver) i = encodeVarintTransfer(dAtA, i, uint64(len(m.Receiver))) i-- - dAtA[i] = 0x2a + dAtA[i] = 0x22 } if len(m.Sender) > 0 { i -= len(m.Sender) copy(dAtA[i:], m.Sender) i = encodeVarintTransfer(dAtA, i, uint64(len(m.Sender))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x1a } - { - size, err := m.Trace.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTransfer(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a if m.Amount != 0 { i = encodeVarintTransfer(dAtA, i, uint64(m.Amount)) i-- @@ -636,8 +616,6 @@ func (m *FungibleTokenPacketData) Size() (n int) { if m.Amount != 0 { n += 1 + sovTransfer(uint64(m.Amount)) } - l = m.Trace.Size() - n += 1 + l + sovTransfer(uint64(l)) l = len(m.Sender) if l > 0 { n += 1 + l + sovTransfer(uint64(l)) @@ -1023,39 +1001,6 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { } } case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTransfer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTransfer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Trace.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) } @@ -1087,7 +1032,7 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { } m.Sender = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) } From 54788a44d21e9874a3c2d7c943eb6c35e452b03d Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 3 Aug 2020 20:32:44 +0200 Subject: [PATCH 18/41] fix coin validation bug --- types/coin.go | 17 +++++++---------- types/coin_test.go | 12 +++++++++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/types/coin.go b/types/coin.go index 20217dbc4de9..f78ba021a76c 100644 --- a/types/coin.go +++ b/types/coin.go @@ -51,10 +51,7 @@ func validate(denom string, amount Int) error { // IsValid returns true if the Coin has a non-negative amount and the denom is vaild. func (coin Coin) IsValid() bool { - if err := validate(coin.Denom, coin.Amount); err != nil { - return false - } - return true + return validate(coin.Denom, coin.Amount) == nil } // IsZero returns if this represents no money @@ -91,7 +88,7 @@ func (coin Coin) IsEqual(other Coin) bool { return coin.Amount.Equal(other.Amount) } -// Adds amounts of two coins with same denom. If the coins differ in denom then +// Add adds amounts of two coins with same denom. If the coins differ in denom then // it panics. func (coin Coin) Add(coinB Coin) Coin { if coin.Denom != coinB.Denom { @@ -101,7 +98,7 @@ func (coin Coin) Add(coinB Coin) Coin { return Coin{coin.Denom, coin.Amount.Add(coinB.Amount)} } -// Subtracts amounts of two coins with same denom. If the coins differ in denom +// Sub subtracts amounts of two coins with same denom. If the coins differ in denom // then it panics. func (coin Coin) Sub(coinB Coin) Coin { if coin.Denom != coinB.Denom { @@ -201,7 +198,7 @@ func (coins Coins) IsValid() bool { lowDenom := coins[0].Denom for _, coin := range coins[1:] { - if strings.ToLower(coin.Denom) != coin.Denom { + if err := ValidateDenom(coin.Denom); err != nil { return false } if coin.Denom <= lowDenom { @@ -463,7 +460,7 @@ func (coins Coins) Empty() bool { return len(coins) == 0 } -// Returns the amount of a denom from coins +// AmountOf returns the amount of a denom from coins func (coins Coins) AmountOf(denom string) Int { mustValidateDenom(denom) @@ -576,8 +573,8 @@ func (coins Coins) Sort() Coins { // Parsing var ( - // Denominations can be 3 ~ 64 characters long. - reDnmString = `[a-z][a-zA-Z0-9/]{2,63}` + // Denominations can be 3 ~ 128 characters long. + reDnmString = `[a-z][a-zA-Z0-9/]{2,127}` reAmt = `[[:digit:]]+` reDecAmt = `[[:digit:]]*\.[[:digit:]]+` reSpc = `[[:space:]]*` diff --git a/types/coin_test.go b/types/coin_test.go index 9d896861ab8a..745cd9db3c8a 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -67,7 +67,8 @@ func TestCoinIsValid(t *testing.T) { {Coin{"Atom", NewInt(1)}, false}, {Coin{"a", NewInt(1)}, false}, {Coin{"a very long coin denom", NewInt(1)}, false}, - {Coin{"atOm", NewInt(1)}, false}, + {Coin{"atOm", NewInt(1)}, true}, + {Coin{"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", NewInt(1)}, true}, {Coin{" ", NewInt(1)}, false}, } @@ -403,6 +404,10 @@ func TestCoins(t *testing.T) { mixedCase3 := Coins{ {"gAs", NewInt(1)}, } + multipleIBCDenoms := Coins{ + {"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", NewInt(1)}, + {"ibc/876563AAAACF739EB061C67CDB5EDF2B7C9FD4AA9D876450CC21210807C2820A", NewInt(2)}, + } empty := NewCoins() badSort1 := Coins{ {"tree", NewInt(1)}, @@ -433,8 +438,9 @@ func TestCoins(t *testing.T) { assert.True(t, good.IsValid(), "Coins are valid") assert.False(t, mixedCase1.IsValid(), "Coins denoms contain upper case characters") - assert.False(t, mixedCase2.IsValid(), "First Coins denoms contain upper case characters") - assert.False(t, mixedCase3.IsValid(), "Single denom in Coins contains upper case characters") + assert.True(t, mixedCase2.IsValid(), "First Coins denoms contain upper case characters") + assert.True(t, mixedCase3.IsValid(), "Single denom in Coins contains upper case characters") + assert.True(t, multipleIBCDenoms.IsValid(), "IBC denominations as per ADR001 should be valid") assert.True(t, good.IsAllPositive(), "Expected coins to be positive: %v", good) assert.False(t, empty.IsAllPositive(), "Expected coins to not be positive: %v", empty) assert.True(t, good.IsAllGTE(empty), "Expected %v to be >= %v", good, empty) From 0d9aea5b94748124de8446f84a9f139b747ad60e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 4 Aug 2020 09:55:19 +0200 Subject: [PATCH 19/41] more validations --- .../adr-001-coin-source-tracing.md | 6 +-- x/ibc-transfer/types/msgs.go | 7 +-- x/ibc-transfer/types/msgs_test.go | 6 ++- x/ibc-transfer/types/packet.go | 2 +- x/ibc-transfer/types/trace.go | 40 +++++++++++++- x/ibc-transfer/types/trace_test.go | 52 +++++++++++++++++++ x/ibc/testing/chain.go | 2 +- 7 files changed, 101 insertions(+), 14 deletions(-) diff --git a/docs/architecture/adr-001-coin-source-tracing.md b/docs/architecture/adr-001-coin-source-tracing.md index a6efad1e4fd4..2075c275b57f 100644 --- a/docs/architecture/adr-001-coin-source-tracing.md +++ b/docs/architecture/adr-001-coin-source-tracing.md @@ -220,7 +220,7 @@ func (msg MsgTransfer) ValidateBasic() error { if err := msg.Trace.Validate(); err != nil { return err } - if err := ValidateIBCDenom(msg.Token.Denom, msg.Trace); err != nil { + if err := ValidatePrefixedDenom(msg.Token.Denom, msg.Trace); err != nil { return err } // ... @@ -228,8 +228,8 @@ func (msg MsgTransfer) ValidateBasic() error { ``` ```golang -// ValidateIBCDenom checks that the denomination for an IBC fungible token is valid. It returns error if the trace `hash` is invalid -func ValidateIBCDenom(denom string, trace DenomTrace) error { +// ValidatePrefixedDenom checks that the denomination for an IBC fungible token is valid. It returns error if the trace `hash` is invalid +func ValidatePrefixedDenom(denom string, trace DenomTrace) error { // Validate that base denominations are equal if the trace info is not provided if trace.Trace == "" { if trace.BaseDenom != denom { diff --git a/x/ibc-transfer/types/msgs.go b/x/ibc-transfer/types/msgs.go index d12714c6d2ee..113990bf82cd 100644 --- a/x/ibc-transfer/types/msgs.go +++ b/x/ibc-transfer/types/msgs.go @@ -59,12 +59,7 @@ func (msg MsgTransfer) ValidateBasic() error { if msg.Receiver == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing recipient address") } - - // sanity check that validate basic on fungible token packet passes - // NOTE: this should always pass since validation checks should be the - // same. Please open an issue if you encounter an error on this line. - packet := NewFungibleTokenPacketData(msg.Token.Denom, msg.Token.Amount.Uint64(), msg.Sender.String(), msg.Receiver) - return packet.ValidateBasic() + return ValidateIBCDenom(msg.Token.Denom) } // GetSignBytes implements sdk.Msg diff --git a/x/ibc-transfer/types/msgs_test.go b/x/ibc-transfer/types/msgs_test.go index 8a089b8305c4..21d361823226 100644 --- a/x/ibc-transfer/types/msgs_test.go +++ b/x/ibc-transfer/types/msgs_test.go @@ -28,6 +28,8 @@ var ( emptyAddr sdk.AccAddress coin = sdk.NewCoin("atom", sdk.NewInt(100)) + ibcCoin = sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)) + invalidIBCCoin = sdk.NewCoin("notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)) invalidDenomCoin = sdk.Coin{Denom: "ato-m", Amount: sdk.NewInt(100)} negativeCoin = sdk.Coin{Denom: "atoms", Amount: sdk.NewInt(-100)} ) @@ -53,7 +55,9 @@ func TestMsgTransferValidation(t *testing.T) { msg *MsgTransfer expPass bool }{ - {"valid msg", NewMsgTransfer(validPort, validChannel, coin, addr1, addr2, 10, 0), true}, + {"valid msg with base denom", NewMsgTransfer(validPort, validChannel, coin, addr1, addr2, 10, 0), true}, + {"valid msg with trace hash", NewMsgTransfer(validPort, validChannel, ibcCoin, addr1, addr2, 10, 0), true}, + {"invalid ibc denom", NewMsgTransfer(validPort, validChannel, invalidIBCCoin, addr1, addr2, 10, 0), false}, {"too short port id", NewMsgTransfer(invalidShortPort, validChannel, coin, addr1, addr2, 10, 0), false}, {"too long port id", NewMsgTransfer(invalidLongPort, validChannel, coin, addr1, addr2, 10, 0), false}, {"port id contains non-alpha", NewMsgTransfer(invalidPort, validChannel, coin, addr1, addr2, 10, 0), false}, diff --git a/x/ibc-transfer/types/packet.go b/x/ibc-transfer/types/packet.go index 649bacd2bc93..63109efe8ff8 100644 --- a/x/ibc-transfer/types/packet.go +++ b/x/ibc-transfer/types/packet.go @@ -45,7 +45,7 @@ func (ftpd FungibleTokenPacketData) ValidateBasic() error { if strings.TrimSpace(ftpd.Receiver) == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "receiver address cannot be blank") } - return ValidateIBCDenom(ftpd.Denom) + return ValidatePrefixedDenom(ftpd.Denom) } // GetBytes is a helper for serialising diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 90fbd944fce9..69f30415add0 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -1,12 +1,14 @@ package types import ( + "encoding/hex" "errors" fmt "fmt" "strings" "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" + tmtypes "github.com/tendermint/tendermint/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" @@ -130,8 +132,13 @@ func (t Traces) Validate() error { return nil } -// ValidateIBCDenom checks that the denomination for an IBC fungible token packet denom is valid. -func ValidateIBCDenom(denom string) error { +// ValidatePrefixedDenom checks that the denomination for an IBC fungible token packet denom is correctly prefixed. +// The function will return no error if the given string follows one of the two formats: +// +// - Prefixed denomination: '{portIDN}/{channelIDN}/.../{portID0}/{channelID0}/baseDenom' +// +// - Unprefixed denomination: 'baseDenom' +func ValidatePrefixedDenom(denom string) error { denomSplit := strings.Split(denom, "/") if denomSplit[0] == denom && strings.TrimSpace(denom) != "" { // NOTE: no base denomination validation @@ -145,3 +152,32 @@ func ValidateIBCDenom(denom string) error { identifiers := denomSplit[:len(denomSplit)-1] return validateTraceIdentifiers(identifiers) } + +// ValidateIBCDenom validates that the given denomination is either: +// +// - A valid base denomination (eg: 'uatom') +// +// - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-001-coin-source-tracing.md +func ValidateIBCDenom(denom string) error { + denomSplit := strings.SplitN(denom, "/", 2) + + switch { + case denomSplit[0] != "ibc" && denomSplit[0] == denom && strings.TrimSpace(denom) != "": + // NOTE: coin base denomination already verified + return nil + case len(denomSplit) != 2, denomSplit[0] != "ibc", strings.TrimSpace(denomSplit[1]) == "": + return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) + } + + hash, err := hex.DecodeString(denomSplit[1]) + if err != nil { + return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid denom trace hash %s: %s", denomSplit[1], err) + } + + hash = tmbytes.HexBytes(hash) + if err := tmtypes.ValidateHash(hash); err != nil { + return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid denom trace hash %s: %s", denomSplit[1], err) + } + + return nil +} diff --git a/x/ibc-transfer/types/trace_test.go b/x/ibc-transfer/types/trace_test.go index 115ac34dbf43..ef56db9ee15b 100644 --- a/x/ibc-transfer/types/trace_test.go +++ b/x/ibc-transfer/types/trace_test.go @@ -81,3 +81,55 @@ func TestDenomTrace_Validate(t *testing.T) { require.NoError(t, err, tc.name) } } + +func TestValidatePrefixedDenom(t *testing.T) { + testCases := []struct { + name string + denom string + expError bool + }{ + {"prefixed denom", "transfer/channelToA/uatom", false}, + {"base denom", "uatom", false}, + {"empty denom", "", true}, + {"empty prefix", "/uatom", true}, + {"empty identifiers", "//uatom", true}, + {"single trace identifier", "transfer/", true}, + {"invalid port ID", "(transfer)/channelToA/uatom", true}, + {"invalid channel ID", "transfer/(channelToA)/uatom", true}, + } + + for _, tc := range testCases { + err := ValidatePrefixedDenom(tc.denom) + if tc.expError { + require.Error(t, err, tc.name) + continue + } + require.NoError(t, err, tc.name) + } +} + +func TestValidateIBCDenom(t *testing.T) { + testCases := []struct { + name string + denom string + expError bool + }{ + {"denom with trace hash", "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", false}, + {"base denom", "uatom", false}, + {"empty denom", "", true}, + {"invalid prefixed denom", "transfer/channelToA/uatom", true}, + {"denom 'ibc'", "ibc", true}, + {"denom 'ibc/'", "ibc/", true}, + {"invald prefix", "notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", true}, + {"invald hash", "ibc/!@#$!@#", true}, + } + + for _, tc := range testCases { + err := ValidateIBCDenom(tc.denom) + if tc.expError { + require.Error(t, err, tc.name) + continue + } + require.NoError(t, err, tc.name) + } +} diff --git a/x/ibc/testing/chain.go b/x/ibc/testing/chain.go index f8b4e78dfe16..8bc3c03a6191 100644 --- a/x/ibc/testing/chain.go +++ b/x/ibc/testing/chain.go @@ -53,7 +53,7 @@ const ( // Default params variables used to create a TM client var ( DefaultTrustLevel tmmath.Fraction = lite.DefaultTrustLevel - TestHash = []byte("TESTING HASH") + TestHash = tmhash.Sum("TESTING HASH") TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) ConnectionVersion = connectiontypes.GetCompatibleEncodedVersions()[0] From 0d6f40810740686a27c213c1a9727fb57898d2b6 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 4 Aug 2020 09:56:39 +0200 Subject: [PATCH 20/41] update comments --- x/ibc-transfer/types/trace.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 69f30415add0..00b69ea0deed 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -135,9 +135,8 @@ func (t Traces) Validate() error { // ValidatePrefixedDenom checks that the denomination for an IBC fungible token packet denom is correctly prefixed. // The function will return no error if the given string follows one of the two formats: // -// - Prefixed denomination: '{portIDN}/{channelIDN}/.../{portID0}/{channelID0}/baseDenom' -// -// - Unprefixed denomination: 'baseDenom' +// - Prefixed denomination: '{portIDN}/{channelIDN}/.../{portID0}/{channelID0}/baseDenom' +// - Unprefixed denomination: 'baseDenom' func ValidatePrefixedDenom(denom string) error { denomSplit := strings.Split(denom, "/") if denomSplit[0] == denom && strings.TrimSpace(denom) != "" { @@ -155,9 +154,8 @@ func ValidatePrefixedDenom(denom string) error { // ValidateIBCDenom validates that the given denomination is either: // -// - A valid base denomination (eg: 'uatom') -// -// - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-001-coin-source-tracing.md +// - A valid base denomination (eg: 'uatom') +// - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-001-coin-source-tracing.md func ValidateIBCDenom(denom string) error { denomSplit := strings.SplitN(denom, "/", 2) From 69b5982cd1b095fa0955fc21cce7228542f566d9 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 4 Aug 2020 10:06:36 +0200 Subject: [PATCH 21/41] minor refactor --- x/ibc-transfer/keeper/grpc_query.go | 13 ++----------- x/ibc-transfer/types/trace.go | 17 +++++++++++++---- x/ibc/testing/chain.go | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/x/ibc-transfer/keeper/grpc_query.go b/x/ibc-transfer/keeper/grpc_query.go index aeec782de6e9..99c11f77112a 100644 --- a/x/ibc-transfer/keeper/grpc_query.go +++ b/x/ibc-transfer/keeper/grpc_query.go @@ -2,15 +2,11 @@ package keeper import ( "context" - "encoding/hex" "fmt" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - tmbytes "github.com/tendermint/tendermint/libs/bytes" - tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -26,13 +22,8 @@ func (q Keeper) DenomTrace(c context.Context, req *types.QueryDenomTraceRequest) return nil, status.Error(codes.InvalidArgument, "empty request") } - hash, err := hex.DecodeString(req.Hash) + hash, err := types.ParseHexHash(req.Hash) if err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - - hash = tmbytes.HexBytes(hash) - if err := tmtypes.ValidateHash(hash); err != nil { return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid denom trace hash %s, %s", req.Hash, err)) } @@ -61,7 +52,7 @@ func (q Keeper) DenomTraces(c context.Context, req *types.QueryDenomTracesReques traces := types.Traces{} store := prefix.NewStore(ctx.KVStore(q.storeKey), types.DenomTraceKey) - pageRes, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { + pageRes, err := query.Paginate(store, req.Pagination, func(_, value []byte) error { var result types.DenomTrace if err := q.cdc.UnmarshalBinaryBare(value, &result); err != nil { return err diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 00b69ea0deed..31e23b3bfdee 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -167,15 +167,24 @@ func ValidateIBCDenom(denom string) error { return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) } - hash, err := hex.DecodeString(denomSplit[1]) - if err != nil { + if _, err := ParseHexHash(denomSplit[1]); err != nil { return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid denom trace hash %s: %s", denomSplit[1], err) } + return nil +} + +// ParseHexHash parses a hex hash in string format to bytes and validates its correctness. +func ParseHexHash(hexHash string) (tmbytes.HexBytes, error) { + hash, err := hex.DecodeString(hexHash) + if err != nil { + return nil, err + } + hash = tmbytes.HexBytes(hash) if err := tmtypes.ValidateHash(hash); err != nil { - return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid denom trace hash %s: %s", denomSplit[1], err) + return nil, err } - return nil + return hash, nil } diff --git a/x/ibc/testing/chain.go b/x/ibc/testing/chain.go index 8bc3c03a6191..86fc14d47b89 100644 --- a/x/ibc/testing/chain.go +++ b/x/ibc/testing/chain.go @@ -53,7 +53,7 @@ const ( // Default params variables used to create a TM client var ( DefaultTrustLevel tmmath.Fraction = lite.DefaultTrustLevel - TestHash = tmhash.Sum("TESTING HASH") + TestHash = tmhash.Sum([]byte("TESTING HASH")) TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) ConnectionVersion = connectiontypes.GetCompatibleEncodedVersions()[0] From 61c54347f202985d8a7ef653b4566f3c8727ed6a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 4 Aug 2020 10:35:07 +0200 Subject: [PATCH 22/41] update relay.go --- x/ibc-transfer/keeper/relay.go | 21 ++++++++++++++++++--- x/ibc-transfer/types/errors.go | 1 + x/ibc-transfer/types/trace.go | 1 - 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index 8943c409c802..9653ec6834d2 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -1,6 +1,8 @@ package keeper import ( + "strings" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" @@ -69,17 +71,30 @@ func (k Keeper) SendTransfer( // begin createOutgoingPacket logic // See spec for this logic: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel)) if !ok { return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } + prefixedDenom := token.Denom + + // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic + if strings.HasPrefix(token.Denom, "ibc/") { + hexHash := token.Denom[4:] + hash, _ := types.ParseHexHash(hexHash) + + denomTrace, found := k.GetDenomTrace(ctx, hash) + if !found { + return sdkerrors.Wrap(types.ErrTraceNotFound, hexHash) + } + prefixedDenom = denomTrace.GetPrefix() + denomTrace.BaseDenom + } + // NOTE: SendTransfer simply sends the denomination as it exists on its own // chain inside the packet data. The receiving chain will perform denom // prefixing as necessary. - if types.SenderChainIsSource(sourcePort, sourceChannel, token.Denom) { + if types.SenderChainIsSource(sourcePort, sourceChannel, prefixedDenom) { // create the escrow address for the tokens escrowAddress := types.GetEscrowAddress(sourcePort, sourceChannel) @@ -109,7 +124,7 @@ func (k Keeper) SendTransfer( } packetData := types.NewFungibleTokenPacketData( - token.Denom, token.Amount.Uint64(), sender.String(), receiver, + prefixedDenom, token.Amount.Uint64(), sender.String(), receiver, ) packet := channeltypes.NewPacket( diff --git a/x/ibc-transfer/types/errors.go b/x/ibc-transfer/types/errors.go index 6c1da2fb4675..f7cc697d1ce3 100644 --- a/x/ibc-transfer/types/errors.go +++ b/x/ibc-transfer/types/errors.go @@ -10,4 +10,5 @@ var ( ErrInvalidDenomForTransfer = sdkerrors.Register(ModuleName, 3, "invalid denomination for cross-chain transfer") ErrInvalidVersion = sdkerrors.Register(ModuleName, 4, "invalid ICS20 version") ErrInvalidAmount = sdkerrors.Register(ModuleName, 5, "invalid token amount") + ErrTraceNotFound = sdkerrors.Register(ModuleName, 6, "denomination trace not found") ) diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 31e23b3bfdee..f9253b74d1e3 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -181,7 +181,6 @@ func ParseHexHash(hexHash string) (tmbytes.HexBytes, error) { return nil, err } - hash = tmbytes.HexBytes(hash) if err := tmtypes.ValidateHash(hash); err != nil { return nil, err } From a86a15c11fd7adebe5885dcbcfb36e28d3d292d3 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 4 Aug 2020 11:32:27 +0200 Subject: [PATCH 23/41] try fix test --- x/ibc-transfer/handler_test.go | 10 +++++++--- x/ibc-transfer/types/coin.go | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/x/ibc-transfer/handler_test.go b/x/ibc-transfer/handler_test.go index 6545a5884f01..472f83af17ce 100644 --- a/x/ibc-transfer/handler_test.go +++ b/x/ibc-transfer/handler_test.go @@ -48,9 +48,9 @@ func (suite *HandlerTestSuite) TestHandleMsgTransfer() { err = suite.coordinator.RelayPacket(suite.chainA, suite.chainB, clientA, clientB, packet, ack.GetBytes()) suite.Require().NoError(err) // relay committed - // check that voucher exists on chain - voucherDenom := types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), sdk.DefaultBondDenom) - balance := suite.chainB.App.BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenom) + // check that voucher exists on chain B + voucherDenomTrace := types.ParseDenomTrace(types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), sdk.DefaultBondDenom)) + balance := suite.chainB.App.BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) coinToSendBackToA := types.GetTransferCoin(channelB.PortID, channelB.ID, sdk.DefaultBondDenom, 100) suite.Require().Equal(coinToSendBackToA, balance) @@ -76,6 +76,10 @@ func (suite *HandlerTestSuite) TestHandleMsgTransfer() { escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) balance = suite.chainA.App.BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom) suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt()), balance) + + // check that balance on chain B is empty + balance = suite.chainB.App.BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) + suite.Require().Equal(0, balance.Amount.Int64()) } func TestHandlerTestSuite(t *testing.T) { diff --git a/x/ibc-transfer/types/coin.go b/x/ibc-transfer/types/coin.go index 65b4e91d1998..e2fe7dc5ade2 100644 --- a/x/ibc-transfer/types/coin.go +++ b/x/ibc-transfer/types/coin.go @@ -48,5 +48,6 @@ func GetPrefixedCoin(portID, channelID string, coin sdk.Coin) sdk.Coin { // GetTransferCoin creates a transfer coin with the port ID and channel ID // prefixed to the base denom. func GetTransferCoin(portID, channelID, baseDenom string, amount int64) sdk.Coin { - return sdk.NewInt64Coin(GetPrefixedDenom(portID, channelID, baseDenom), amount) + denomTrace := ParseDenomTrace(GetPrefixedDenom(portID, channelID, baseDenom)) + return sdk.NewInt64Coin(denomTrace.IBCDenom(), amount) } From 632c00e5dc978e2dbca049f307e04f7b77ef930a Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Mon, 10 Aug 2020 22:14:56 +0200 Subject: [PATCH 24/41] minor updates --- x/ibc-transfer/keeper/grpc_query.go | 2 +- x/ibc-transfer/keeper/relay.go | 5 ++++- x/ibc-transfer/types/trace_test.go | 29 +++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/x/ibc-transfer/keeper/grpc_query.go b/x/ibc-transfer/keeper/grpc_query.go index 99c11f77112a..8d11e7cdc697 100644 --- a/x/ibc-transfer/keeper/grpc_query.go +++ b/x/ibc-transfer/keeper/grpc_query.go @@ -32,7 +32,7 @@ func (q Keeper) DenomTrace(c context.Context, req *types.QueryDenomTraceRequest) if !found { return nil, status.Error( codes.NotFound, - sdkerrors.Wrap(types.ErrInvalidDenomForTransfer, req.Hash).Error(), // TODO: update error + sdkerrors.Wrap(types.ErrTraceNotFound, req.Hash).Error(), ) } diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index 9653ec6834d2..b0d2b1bed0bf 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -81,7 +81,10 @@ func (k Keeper) SendTransfer( // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic if strings.HasPrefix(token.Denom, "ibc/") { hexHash := token.Denom[4:] - hash, _ := types.ParseHexHash(hexHash) + hash, err := types.ParseHexHash(hexHash) + if err != nil { + return err + } denomTrace, found := k.GetDenomTrace(ctx, hash) if !found { diff --git a/x/ibc-transfer/types/trace_test.go b/x/ibc-transfer/types/trace_test.go index ef56db9ee15b..95b7b7614f05 100644 --- a/x/ibc-transfer/types/trace_test.go +++ b/x/ibc-transfer/types/trace_test.go @@ -82,6 +82,35 @@ func TestDenomTrace_Validate(t *testing.T) { } } +func TestTraces_Validate(t *testing.T) { + testCases := []struct { + name string + traces Traces + expError bool + }{ + {"empty Traces", Traces{}, false}, + {"valid multiple trace info", Traces{{BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}}, false}, + { + "valid multiple trace info", + Traces{ + {BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}, + {BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}, + }, + true, + }, + {"empty base denom with trace", Traces{{BaseDenom: "", Trace: "transfer/channelToA"}}, true}, + } + + for _, tc := range testCases { + err := tc.traces.Validate() + if tc.expError { + require.Error(t, err, tc.name) + continue + } + require.NoError(t, err, tc.name) + } +} + func TestValidatePrefixedDenom(t *testing.T) { testCases := []struct { name string From db04cb5b020ea9166e43ea4f6b1ee013d603b578 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 11 Aug 2020 10:44:16 +0200 Subject: [PATCH 25/41] fix tests --- x/ibc-transfer/handler_test.go | 5 ++++- x/ibc-transfer/keeper/relay.go | 3 +++ x/ibc-transfer/types/msgs_test.go | 4 ++-- x/ibc-transfer/types/trace.go | 16 +++++++++++----- x/ibc-transfer/types/trace_test.go | 3 ++- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/x/ibc-transfer/handler_test.go b/x/ibc-transfer/handler_test.go index 472f83af17ce..6a4113f44101 100644 --- a/x/ibc-transfer/handler_test.go +++ b/x/ibc-transfer/handler_test.go @@ -56,6 +56,9 @@ func (suite *HandlerTestSuite) TestHandleMsgTransfer() { suite.Require().Equal(coinToSendBackToA, balance) // send from chainB back to chainA + + // NOTE: token is prefixed with the full trace in order to verify the packet commitment + coinToSendBackToA = sdk.NewCoin(voucherDenomTrace.GetPrefix()+voucherDenomTrace.BaseDenom, coinToSendBackToA.Amount) msg = types.NewMsgTransfer(channelB.PortID, channelB.ID, coinToSendBackToA, suite.chainB.SenderAccount.GetAddress(), suite.chainA.SenderAccount.GetAddress().String(), 110, 0) err = suite.coordinator.SendMsgs(suite.chainB, suite.chainA, clientA, msg) @@ -79,7 +82,7 @@ func (suite *HandlerTestSuite) TestHandleMsgTransfer() { // check that balance on chain B is empty balance = suite.chainB.App.BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) - suite.Require().Equal(0, balance.Amount.Int64()) + suite.Require().Zero(balance.Amount.Int64()) } func TestHandlerTestSuite(t *testing.T) { diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index b0d2b1bed0bf..b2eb4e6edf49 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -91,6 +91,9 @@ func (k Keeper) SendTransfer( return sdkerrors.Wrap(types.ErrTraceNotFound, hexHash) } prefixedDenom = denomTrace.GetPrefix() + denomTrace.BaseDenom + } else if strings.Contains(token.Denom, "/") { + denomTrace := types.ParseDenomTrace(token.Denom) + token.Denom = denomTrace.IBCDenom() } // NOTE: SendTransfer simply sends the denomination as it exists on its own diff --git a/x/ibc-transfer/types/msgs_test.go b/x/ibc-transfer/types/msgs_test.go index 21d361823226..dea823df0bd7 100644 --- a/x/ibc-transfer/types/msgs_test.go +++ b/x/ibc-transfer/types/msgs_test.go @@ -31,7 +31,7 @@ var ( ibcCoin = sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)) invalidIBCCoin = sdk.NewCoin("notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)) invalidDenomCoin = sdk.Coin{Denom: "ato-m", Amount: sdk.NewInt(100)} - negativeCoin = sdk.Coin{Denom: "atoms", Amount: sdk.NewInt(-100)} + negativeCoin = sdk.Coin{Denom: "atoms", Amount: sdk.ZeroInt()} ) // TestMsgTransferRoute tests Route for MsgTransfer @@ -65,7 +65,7 @@ func TestMsgTransferValidation(t *testing.T) { {"too long channel id", NewMsgTransfer(validPort, invalidLongChannel, coin, addr1, addr2, 10, 0), false}, {"channel id contains non-alpha", NewMsgTransfer(validPort, invalidChannel, coin, addr1, addr2, 10, 0), false}, {"invalid amount", NewMsgTransfer(validPort, validChannel, invalidDenomCoin, addr1, addr2, 10, 0), false}, - {"negative coin", NewMsgTransfer(validPort, validChannel, negativeCoin, addr1, addr2, 10, 0), false}, + {"zero value coin", NewMsgTransfer(validPort, validChannel, negativeCoin, addr1, addr2, 10, 0), false}, {"missing sender address", NewMsgTransfer(validPort, validChannel, coin, emptyAddr, addr2, 10, 0), false}, {"missing recipient address", NewMsgTransfer(validPort, validChannel, coin, addr1, "", 10, 0), false}, {"empty coin", NewMsgTransfer(validPort, validChannel, sdk.Coin{}, addr1, addr2, 10, 0), false}, diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index f9253b74d1e3..d916c0878c8a 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -78,7 +78,7 @@ func (dt *DenomTrace) RemovePrefix() { } func validateTraceIdentifiers(identifiers []string) error { - if len(identifiers)%2 != 0 { + if len(identifiers) == 0 || len(identifiers)%2 != 0 { return errors.New("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}'") } @@ -157,14 +157,20 @@ func ValidatePrefixedDenom(denom string) error { // - A valid base denomination (eg: 'uatom') // - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-001-coin-source-tracing.md func ValidateIBCDenom(denom string) error { - denomSplit := strings.SplitN(denom, "/", 2) + denomSplit := strings.Split(denom, "/") switch { - case denomSplit[0] != "ibc" && denomSplit[0] == denom && strings.TrimSpace(denom) != "": + case strings.TrimSpace(denom) == "", + len(denomSplit) == 1 && denomSplit[0] == "ibc", + len(denomSplit) == 2 && (denomSplit[0] != "ibc" || strings.TrimSpace(denomSplit[1]) == ""): + return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) + + case denomSplit[0] == denom && strings.TrimSpace(denom) != "": // NOTE: coin base denomination already verified return nil - case len(denomSplit) != 2, denomSplit[0] != "ibc", strings.TrimSpace(denomSplit[1]) == "": - return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) + + case len(denomSplit) > 2: + return validateTraceIdentifiers(denomSplit[:len(denomSplit)-1]) } if _, err := ParseHexHash(denomSplit[1]); err != nil { diff --git a/x/ibc-transfer/types/trace_test.go b/x/ibc-transfer/types/trace_test.go index 95b7b7614f05..33760506cb22 100644 --- a/x/ibc-transfer/types/trace_test.go +++ b/x/ibc-transfer/types/trace_test.go @@ -146,7 +146,7 @@ func TestValidateIBCDenom(t *testing.T) { {"denom with trace hash", "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", false}, {"base denom", "uatom", false}, {"empty denom", "", true}, - {"invalid prefixed denom", "transfer/channelToA/uatom", true}, + {"invalid prefixed denom", "transfer/channelToA/uatom", false}, {"denom 'ibc'", "ibc", true}, {"denom 'ibc/'", "ibc/", true}, {"invald prefix", "notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", true}, @@ -154,6 +154,7 @@ func TestValidateIBCDenom(t *testing.T) { } for _, tc := range testCases { + t.Log(tc.name) err := ValidateIBCDenom(tc.denom) if tc.expError { require.Error(t, err, tc.name) From 014e08dc5fdefe5148740886524de56204936f8c Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 11 Aug 2020 10:48:23 +0200 Subject: [PATCH 26/41] fix test --- x/ibc-transfer/handler_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x/ibc-transfer/handler_test.go b/x/ibc-transfer/handler_test.go index 6a4113f44101..344080cb1725 100644 --- a/x/ibc-transfer/handler_test.go +++ b/x/ibc-transfer/handler_test.go @@ -56,16 +56,15 @@ func (suite *HandlerTestSuite) TestHandleMsgTransfer() { suite.Require().Equal(coinToSendBackToA, balance) // send from chainB back to chainA - - // NOTE: token is prefixed with the full trace in order to verify the packet commitment - coinToSendBackToA = sdk.NewCoin(voucherDenomTrace.GetPrefix()+voucherDenomTrace.BaseDenom, coinToSendBackToA.Amount) msg = types.NewMsgTransfer(channelB.PortID, channelB.ID, coinToSendBackToA, suite.chainB.SenderAccount.GetAddress(), suite.chainA.SenderAccount.GetAddress().String(), 110, 0) err = suite.coordinator.SendMsgs(suite.chainB, suite.chainA, clientA, msg) suite.Require().NoError(err) // message committed // relay send - fungibleTokenPacket = types.NewFungibleTokenPacketData(coinToSendBackToA.Denom, coinToSendBackToA.Amount.Uint64(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) + // NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment + voucherDenom := voucherDenomTrace.GetPrefix() + voucherDenomTrace.BaseDenom + fungibleTokenPacket = types.NewFungibleTokenPacketData(voucherDenom, coinToSendBackToA.Amount.Uint64(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, channelB.PortID, channelB.ID, channelA.PortID, channelA.ID, 110, 0) err = suite.coordinator.RelayPacket(suite.chainB, suite.chainA, clientB, clientA, packet, ack.GetBytes()) suite.Require().NoError(err) // relay committed From 0eabe48ca92d675e7e69e432a5dc679d58e68f3e Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 11 Aug 2020 11:21:24 +0200 Subject: [PATCH 27/41] ADR updates and comments --- .../adr-001-coin-source-tracing.md | 123 +++++++++++------- docs/architecture/adr-template.md | 2 +- x/ibc-transfer/keeper/relay.go | 8 +- x/ibc-transfer/types/trace.go | 7 +- 4 files changed, 86 insertions(+), 54 deletions(-) diff --git a/docs/architecture/adr-001-coin-source-tracing.md b/docs/architecture/adr-001-coin-source-tracing.md index 2075c275b57f..22b2165da5c6 100644 --- a/docs/architecture/adr-001-coin-source-tracing.md +++ b/docs/architecture/adr-001-coin-source-tracing.md @@ -3,10 +3,11 @@ ## Changelog - 2020-07-09: Initial Draft +- 2020-08-11: Implementation changes ## Status -Proposed +Accepted, Implemented ## Context @@ -133,12 +134,15 @@ message DenomTrace { The `IBCDenom` function constructs the `Coin` denomination used when creating the ICS20 fungible token packet data: ```golang -// Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields. +// Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula: +// +// hash = sha256(trace + "/" + baseDenom) func (dt DenomTrace) Hash() tmbytes.HexBytes { return tmhash.Sum(dt.Trace + "/" + dt.BaseDenom) } -// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + baseDenom)}'. If the trace is empty, it will return the base denomination. +// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + +// baseDenom)}'. If the trace is empty, it will return the base denomination. func (dt DenomTrace) IBCDenom() string { if dt.Trace != "" { return fmt.Sprintf("ibc/%s", dt.Hash()) @@ -152,15 +156,16 @@ In order to trim the denomination trace prefix when sending/receiving fungible t > NOTE: the prefix addition must be done on the client side. ```golang -// RemovePrefix trims the first portID/channelID pair from the trace info. If the trace is already empty it will perform a no-op. If the trace is incorrectly constructed or doesn't have separators it will return an error. -func (dt *DenomTrace) RemovePrefix() error { +// RemovePrefix trims the first portID/channelID pair from the trace info. If the trace is already +// empty it will perform a no-op. If the trace is incorrectly constructed or doesn't have separators +// it will return an error. +func (dt *DenomTrace) RemovePrefix() { if dt.Trace == "" { - return nil + return } traceSplit := strings.SplitN(dt.Trace, "/", 3) - var err error switch { // NOTE: other cases are checked during msg validation case len(traceSplit) == 2: @@ -168,12 +173,6 @@ func (dt *DenomTrace) RemovePrefix() error { case len(traceSplit) == 3: dt.Trace = traceSplit[2] } - - if err != nil { - return err - } - - return nil } ``` @@ -217,44 +216,34 @@ hash, if the trace info is provided, or that the base denominations matches: ```golang func (msg MsgTransfer) ValidateBasic() error { // ... - if err := msg.Trace.Validate(); err != nil { - return err - } - if err := ValidatePrefixedDenom(msg.Token.Denom, msg.Trace); err != nil { - return err - } - // ... + return ValidateIBCDenom(msg.Token.Denom) } ``` ```golang -// ValidatePrefixedDenom checks that the denomination for an IBC fungible token is valid. It returns error if the trace `hash` is invalid -func ValidatePrefixedDenom(denom string, trace DenomTrace) error { - // Validate that base denominations are equal if the trace info is not provided - if trace.Trace == "" { - if trace.BaseDenom != denom { - return Wrapf( - ErrInvalidDenomForTransfer, - "token denom must match the trace base denom (%s ≠ %s)", - denom, trace.BaseDenom, - ) - } - return nil - } - - denomSplit := strings.SplitN(denom, "/", 2) +// ValidateIBCDenom validates that the given denomination is either: +// +// - A valid base denomination (eg: 'uatom') +// - A valid trace prefixed denomination (eg: '{portIDN}/{channelIDN}/.../{portID0}/{channelID0}/baseDenom') +// - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-001-coin-source-tracing.md +func ValidateIBCDenom(denom string) error { + denomSplit := strings.Split(denom, "/") switch { - case denomSplit[0] != "ibc": - return Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) - case len(denomSplit) == 2: - return tmtypes.ValidateHash([]byte(denomSplit[1])) + case strings.TrimSpace(denom) == "", + len(denomSplit) == 1 && denomSplit[0] == "ibc", + len(denomSplit) == 2 && (denomSplit[0] != "ibc" || strings.TrimSpace(denomSplit[1]) == ""): + return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) + + case denomSplit[0] == denom && strings.TrimSpace(denom) != "": + return sdk.ValidateDenom(denom) + + case len(denomSplit) > 2: + return validateTraceIdentifiers(denomSplit[:len(denomSplit)-1]) } - denomTraceHash := denomSplit[1] - traceHash := trace.Hash() - if !bytes.Equal(traceHash.Bytes(), denomTraceHash.Bytes()) { - return Errorf("token denomination trace hash mismatch, expected %s got %s", traceHash, denomTraceHash) + if _, err := ParseHexHash(denomSplit[1]); err != nil { + return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid denom trace hash %s: %s", denomSplit[1], err) } return nil @@ -266,6 +255,38 @@ The denomination trace info only needs to be updated when token is received: - Receiver is **source** chain: The receiver created the token and must have the trace lookup already stored (if necessary _ie_ native token case wouldn't need a lookup). - Receiver is **not source** chain: Store the received info. For example, during step 1, when chain `B` receives `transfer/channelToA/denom`. +```golang +// SendTransfer +// ... + +prefixedDenom := token.Denom + +// deconstruct the token denomination into the denomination trace info +// to determine if the sender is the source chain +if strings.HasPrefix(token.Denom, "ibc/") { + hexHash := token.Denom[4:] + hash, err := types.ParseHexHash(hexHash) + if err != nil { + return err + } + + denomTrace, found := k.GetDenomTrace(ctx, hash) + if !found { + return sdkerrors.Wrap(types.ErrTraceNotFound, hexHash) + } + prefixedDenom = denomTrace.GetPrefix() + denomTrace.BaseDenom +} else if strings.Contains(token.Denom, "/") { + // in the case the user transfers a prefixed denomination, + // update the token denomination with the hashed trace info as that's the + // representation on the user balance + denomTrace := types.ParseDenomTrace(token.Denom) + token.Denom = denomTrace.IBCDenom() +} + +if types.SenderChainIsSource(sourcePort, sourceChannel, prefixedDenom) { +//... +``` + ```golang // OnRecvPacket // ... @@ -292,11 +313,13 @@ if ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data // sender chain is the source, mint vouchers -// construct the denomination trace from the full raw denomination -denomTrace := NewDenomTrace(data.Denom) +// since SendPacket did not prefix the denomination, we must prefix denomination here +sourcePrefix := types.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel()) +// NOTE: sourcePrefix contains the trailing "/" +prefixedDenom := sourcePrefix + data.Denom -// since SendPacket did not prefix the denomination with the voucherPrefix, we must add it here -denomTrace.AddPrefix(packet.GetDestPort(), packet.GetDestChannel()) +// construct the denomination trace from the full raw denomination +denomTrace := types.ParseDenomTrace(prefixedDenom) // set the value to the lookup table if not stored already traceHash := denomTrace.Hash() @@ -304,7 +327,8 @@ if !k.HasDenomTrace(ctx, traceHash) { k.SetDenomTrace(ctx, traceHash, denomTrace) } -voucher := sdk.NewCoin(denomTrace.IBCDenom(), sdk.NewIntFromUint64(data.Amount)) +voucherDenom := denomTrace.IBCDenom() +voucher := sdk.NewCoin(voucherDenom, sdk.NewIntFromUint64(data.Amount)) // mint new tokens if the source of the transfer is the same chain if err := k.bankKeeper.MintCoins( @@ -341,7 +365,8 @@ The coin denomination validation will need to be updated to reflect these change function will now: - Accept slash separators (`"/"`) and uppercase characters (due to the `HexBytes` format) -- Bump the maximum character length to 64 +- Bump the maximum character length to 128, as the hex representation used by Tendermint's + `HexBytes` type contains 64 characters. Additional validation logic, such as verifying the length of the hash, the may be added to the bank module in the future if the [custom base denomination validation](https://github.com/cosmos/cosmos-sdk/pull/6755) is integrated into the SDK. diff --git a/docs/architecture/adr-template.md b/docs/architecture/adr-template.md index e3c6fa8fa004..33cd412df6cb 100644 --- a/docs/architecture/adr-template.md +++ b/docs/architecture/adr-template.md @@ -7,7 +7,7 @@ ## Status > A decision may be "proposed" if the project stakeholders haven't agreed with it yet, or "accepted" once it is agreed. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement. -> {Deprecated|Proposed|Accepted} +> {Deprecated|Proposed|Accepted} {Implemented|Not Implemented} ## Context diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index b2eb4e6edf49..da772c80de71 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -76,9 +76,11 @@ func (k Keeper) SendTransfer( return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } + // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic prefixedDenom := token.Denom - // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic + // deconstruct the token denomination into the denomination trace info + // to determine if the sender is the source chain if strings.HasPrefix(token.Denom, "ibc/") { hexHash := token.Denom[4:] hash, err := types.ParseHexHash(hexHash) @@ -92,6 +94,9 @@ func (k Keeper) SendTransfer( } prefixedDenom = denomTrace.GetPrefix() + denomTrace.BaseDenom } else if strings.Contains(token.Denom, "/") { + // in the case the user transfers a prefixed denomination, + // update the token denomination with the hashed trace info as that's the + // representation on the user balance denomTrace := types.ParseDenomTrace(token.Denom) token.Denom = denomTrace.IBCDenom() } @@ -192,6 +197,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // NOTE: sourcePrefix contains the trailing "/" prefixedDenom := sourcePrefix + data.Denom + // construct the denomination trace from the full raw denomination denomTrace := types.ParseDenomTrace(prefixedDenom) traceHash := denomTrace.Hash() diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index d916c0878c8a..cffe14692ab2 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -10,6 +10,7 @@ import ( tmbytes "github.com/tendermint/tendermint/libs/bytes" tmtypes "github.com/tendermint/tendermint/types" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) @@ -39,7 +40,7 @@ func ParseDenomTrace(rawDenom string) DenomTrace { // Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula: // -// hash = sha256(trace + "/" + baseDenom) +// hash = sha256(trace + "/" + baseDenom) func (dt DenomTrace) Hash() tmbytes.HexBytes { return tmhash.Sum([]byte(dt.GetPrefix() + dt.BaseDenom)) } @@ -155,6 +156,7 @@ func ValidatePrefixedDenom(denom string) error { // ValidateIBCDenom validates that the given denomination is either: // // - A valid base denomination (eg: 'uatom') +// - A valid trace prefixed denomination (eg: '{portIDN}/{channelIDN}/.../{portID0}/{channelID0}/baseDenom') // - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-001-coin-source-tracing.md func ValidateIBCDenom(denom string) error { denomSplit := strings.Split(denom, "/") @@ -166,8 +168,7 @@ func ValidateIBCDenom(denom string) error { return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) case denomSplit[0] == denom && strings.TrimSpace(denom) != "": - // NOTE: coin base denomination already verified - return nil + return sdk.ValidateDenom(denom) case len(denomSplit) > 2: return validateTraceIdentifiers(denomSplit[:len(denomSplit)-1]) From 050fc63cde9e514ec25ecc659cc2855428238099 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 11:22:04 +0200 Subject: [PATCH 28/41] build --- x/ibc-transfer/keeper/genesis.go | 8 ++++---- x/ibc-transfer/keeper/genesis_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x/ibc-transfer/keeper/genesis.go b/x/ibc-transfer/keeper/genesis.go index faa3524ab29f..223d473be28a 100644 --- a/x/ibc-transfer/keeper/genesis.go +++ b/x/ibc-transfer/keeper/genesis.go @@ -9,7 +9,7 @@ import ( // InitGenesis initializes the ibc-transfer state and binds to PortID. func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { - k.SetPort(ctx, state.PortID) + k.SetPort(ctx, state.PortId) for _, trace := range state.DenomTraces { k.SetDenomTrace(ctx, trace) @@ -17,10 +17,10 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { // Only try to bind to port if it is not already bound, since we may already own // port capability from capability InitGenesis - if !k.IsBound(ctx, state.PortID) { + if !k.IsBound(ctx, state.PortId) { // transfer module binds to the transfer port on InitChain // and claims the returned capability - err := k.BindPort(ctx, state.PortID) + err := k.BindPort(ctx, state.PortId) if err != nil { panic(fmt.Sprintf("could not claim port capability: %v", err)) } @@ -36,7 +36,7 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { // ExportGenesis exports ibc-transfer module's portID and denom trace info into its genesis state. func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { return &types.GenesisState{ - PortID: k.GetPort(ctx), + PortId: k.GetPort(ctx), DenomTraces: k.GetAllDenomTraces(ctx), } } diff --git a/x/ibc-transfer/keeper/genesis_test.go b/x/ibc-transfer/keeper/genesis_test.go index 4784ac2ccc09..3711118513cf 100644 --- a/x/ibc-transfer/keeper/genesis_test.go +++ b/x/ibc-transfer/keeper/genesis_test.go @@ -26,6 +26,6 @@ func (suite *KeeperTestSuite) TestGenesis() { genesis := suite.chainA.App.TransferKeeper.ExportGenesis(suite.chainA.GetContext()) suite.Require().NotPanics(func() { - suite.chainA.App.TransferKeeper.InitGenesis(suite.chainA.GetContext(), genesis) + suite.chainA.App.TransferKeeper.InitGenesis(suite.chainA.GetContext(), *genesis) }) } From 40a8f34cef342366ee8db627599cb4ff56f47cf0 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Fri, 14 Aug 2020 11:36:50 +0200 Subject: [PATCH 29/41] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aditya Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- docs/architecture/adr-001-coin-source-tracing.md | 4 ++-- x/ibc-transfer/keeper/relay.go | 4 ++-- x/ibc-transfer/types/trace.go | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/architecture/adr-001-coin-source-tracing.md b/docs/architecture/adr-001-coin-source-tracing.md index 22b2165da5c6..4d05614415e3 100644 --- a/docs/architecture/adr-001-coin-source-tracing.md +++ b/docs/architecture/adr-001-coin-source-tracing.md @@ -141,8 +141,8 @@ func (dt DenomTrace) Hash() tmbytes.HexBytes { return tmhash.Sum(dt.Trace + "/" + dt.BaseDenom) } -// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + -// baseDenom)}'. If the trace is empty, it will return the base denomination. +// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + baseDenom)}'. +// If the trace is empty, it will return the base denomination. func (dt DenomTrace) IBCDenom() string { if dt.Trace != "" { return fmt.Sprintf("ibc/%s", dt.Hash()) diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index da772c80de71..c089307d669e 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -95,8 +95,8 @@ func (k Keeper) SendTransfer( prefixedDenom = denomTrace.GetPrefix() + denomTrace.BaseDenom } else if strings.Contains(token.Denom, "/") { // in the case the user transfers a prefixed denomination, - // update the token denomination with the hashed trace info as that's the - // representation on the user balance + // update the token denomination with the hashed trace info since that is the + // internally represented denomination on the user balance denomTrace := types.ParseDenomTrace(token.Denom) token.Denom = denomTrace.IBCDenom() } diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index cffe14692ab2..19e4b4e196f5 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -113,7 +113,7 @@ func (dt DenomTrace) Validate() error { return validateTraceIdentifiers(identifiers) } -// Traces defines a wrapper type for a slice of IdentifiedDenomTraces. +// Traces defines a wrapper type for a slice of DenomTrace. type Traces []DenomTrace // Validate performs a basic validation of each denomination trace info. @@ -122,7 +122,7 @@ func (t Traces) Validate() error { for i, trace := range t { hash := trace.Hash().String() if seenTraces[hash] { - return fmt.Errorf("duplicated denomination trace with hash %s", trace.Hash()) + return fmt.Errorf("duplicated denomination trace with hash %s", trace.Hash()) } if err := trace.Validate(); err != nil { @@ -175,7 +175,7 @@ func ValidateIBCDenom(denom string) error { } if _, err := ParseHexHash(denomSplit[1]); err != nil { - return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid denom trace hash %s: %s", denomSplit[1], err) + return sdkerrors.Wrapf(err, "invalid denom trace hash %s", denomSplit[1]) } return nil From 6914e053826ae6fef49e3f4660c0540ad8afa6db Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 11:37:17 +0200 Subject: [PATCH 30/41] address a few comments from review --- CHANGELOG.md | 2 +- x/ibc-transfer/keeper/genesis_test.go | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 085535b8b0a8..ddd07a11a3dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -285,7 +285,7 @@ Buffers for state serialization instead of Amino. * (types) [\#7027](https://github.com/cosmos/cosmos-sdk/pull/7027) `Coin(s)` and `DecCoin(s)` updates: * Bump denomination max length to 128 - * Allow unicode letters and numbers in denominations + * Allow uppercase letters and numbers in denominations to support ADR 001 * Added `Validate` function that returns a descriptive error * (baseapp) [\#6186](https://github.com/cosmos/cosmos-sdk/issues/6186) Support emitting events during `AnteHandler` execution. * (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) Add parameter querying support for `x/auth`. diff --git a/x/ibc-transfer/keeper/genesis_test.go b/x/ibc-transfer/keeper/genesis_test.go index 3711118513cf..c63334e1f20b 100644 --- a/x/ibc-transfer/keeper/genesis_test.go +++ b/x/ibc-transfer/keeper/genesis_test.go @@ -7,24 +7,32 @@ import ( ) func (suite *KeeperTestSuite) TestGenesis() { - var trace string + var ( + traceStr string + traces types.Traces + ) + for i := 0; i < 5; i++ { prefix := fmt.Sprintf("transfer/channelToChain%d", i) if i == 0 { - trace = prefix + traceStr = prefix } else { - trace = prefix + trace + traceStr = prefix + "/" + traceStr } denomTrace := types.DenomTrace{ BaseDenom: "uatom", - Trace: trace, + Trace: traceStr, } + traces = append(types.Traces{denomTrace}, traces...) suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), denomTrace) } genesis := suite.chainA.App.TransferKeeper.ExportGenesis(suite.chainA.GetContext()) + suite.Require().Equal(types.PortID, genesis.PortId) + suite.Require().Equal(traces, genesis.DenomTraces) + suite.Require().NotPanics(func() { suite.chainA.App.TransferKeeper.InitGenesis(suite.chainA.GetContext(), *genesis) }) From 372d530dec8c2289e14bfb277d4dee46a0ce80e7 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 20:15:07 +0200 Subject: [PATCH 31/41] gRPC annotations --- proto/ibc/transfer/query.proto | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/proto/ibc/transfer/query.proto b/proto/ibc/transfer/query.proto index 1d3e466a2f74..5476e3b2a311 100644 --- a/proto/ibc/transfer/query.proto +++ b/proto/ibc/transfer/query.proto @@ -4,42 +4,48 @@ package ibc.transfer; import "gogoproto/gogo.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; import "ibc/transfer/transfer.proto"; +import "google/api/annotations.proto"; option go_package = "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"; -// Query provides defines the gRPC querier service +// Query provides defines the gRPC querier service. service Query { - // DenomTrace queries a denomination trace info. - rpc DenomTrace(QueryDenomTraceRequest) returns (QueryDenomTraceResponse) {} + // DenomTrace queries a denomination trace information. + rpc DenomTrace(QueryDenomTraceRequest) returns (QueryDenomTraceResponse) { + option (google.api.http).get = "/ibc_transfer/v1beta1/denom_traces/{hash}"; + } // DenomTraces queries all denomination traces. - rpc DenomTraces(QueryDenomTracesRequest) returns (QueryDenomTracesResponse) {} + rpc DenomTraces(QueryDenomTracesRequest) returns (QueryDenomTracesResponse) { + option (google.api.http).get = "/ibc_transfer/v1beta1/denom_traces"; + } } // QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC method message QueryDenomTraceRequest { - // hex hash of the denomination trace info + // hash (in hex format) of the denomination trace information. string hash = 1; } // QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC method. message QueryDenomTraceResponse { - // denomination trace associated with the request hash + // denom_trace returns the requested denomination trace information. DenomTrace denom_trace = 1; } // QueryConnectionsRequest is the request type for the Query/DenomTraces RPC method message QueryDenomTracesRequest { + // pagination defines an optional pagination for the request. cosmos.base.query.v1beta1.PageRequest pagination = 1; } // QueryConnectionsResponse is the response type for the Query/DenomTraces RPC method. message QueryDenomTracesResponse { - // list of stored connections of the chain. + // denom_traces returns all denominations trace information. repeated DenomTrace denom_traces = 1 [ (gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false ]; - // pagination response + // pagination defines the pagination in the response. cosmos.base.query.v1beta1.PageResponse pagination = 2; } From 9181de3d8fed7d37522f0afcd4ba4d367d18c2c4 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 20:22:58 +0200 Subject: [PATCH 32/41] update proto files --- x/ibc-transfer/types/query.pb.go | 70 ++++---- x/ibc-transfer/types/query.pb.gw.go | 264 ++++++++++++++++++++++++++++ 2 files changed, 302 insertions(+), 32 deletions(-) create mode 100644 x/ibc-transfer/types/query.pb.gw.go diff --git a/x/ibc-transfer/types/query.pb.go b/x/ibc-transfer/types/query.pb.go index 0e883ac92c76..440f3280e1a0 100644 --- a/x/ibc-transfer/types/query.pb.go +++ b/x/ibc-transfer/types/query.pb.go @@ -10,6 +10,7 @@ import ( _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -31,7 +32,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC method type QueryDenomTraceRequest struct { - // hex hash of the denomination trace info + // hash (in hex format) of the denomination trace information. Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` } @@ -77,7 +78,7 @@ func (m *QueryDenomTraceRequest) GetHash() string { // QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC method. type QueryDenomTraceResponse struct { - // denomination trace associated with the request hash + // denom_trace returns the requested denomination trace information. DenomTrace *DenomTrace `protobuf:"bytes,1,opt,name=denom_trace,json=denomTrace,proto3" json:"denom_trace,omitempty"` } @@ -123,6 +124,7 @@ func (m *QueryDenomTraceResponse) GetDenomTrace() *DenomTrace { // QueryConnectionsRequest is the request type for the Query/DenomTraces RPC method type QueryDenomTracesRequest struct { + // pagination defines an optional pagination for the request. Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -168,9 +170,9 @@ func (m *QueryDenomTracesRequest) GetPagination() *query.PageRequest { // QueryConnectionsResponse is the response type for the Query/DenomTraces RPC method. type QueryDenomTracesResponse struct { - // list of stored connections of the chain. + // denom_traces returns all denominations trace information. DenomTraces Traces `protobuf:"bytes,1,rep,name=denom_traces,json=denomTraces,proto3,castrepeated=Traces" json:"denom_traces"` - // pagination response + // pagination defines the pagination in the response. Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -231,32 +233,36 @@ func init() { func init() { proto.RegisterFile("ibc/transfer/query.proto", fileDescriptor_26b3e8b4e9dff1c1) } var fileDescriptor_26b3e8b4e9dff1c1 = []byte{ - // 395 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xcf, 0x4a, 0xfb, 0x40, - 0x10, 0xc7, 0xb3, 0xbf, 0x3f, 0x05, 0x37, 0xc5, 0xc3, 0x22, 0x1a, 0x22, 0xa4, 0x25, 0x68, 0x15, - 0xb1, 0xbb, 0xb4, 0x9e, 0xbc, 0x16, 0xd1, 0x43, 0x2f, 0x5a, 0x7a, 0x52, 0x50, 0x36, 0xe9, 0x9a, - 0x06, 0x69, 0x36, 0xcd, 0x6e, 0xc5, 0xbe, 0x85, 0xcf, 0xe1, 0xc9, 0x87, 0xf0, 0xd0, 0x63, 0x8f, - 0x9e, 0x54, 0xda, 0x17, 0x91, 0x64, 0x13, 0x93, 0x52, 0x69, 0x4f, 0x3b, 0xec, 0xcc, 0x77, 0xe6, - 0xf3, 0xdd, 0x1d, 0x68, 0xf8, 0x8e, 0x4b, 0x64, 0x44, 0x03, 0x71, 0xcf, 0x22, 0x32, 0x1c, 0xb1, - 0x68, 0x8c, 0xc3, 0x88, 0x4b, 0x8e, 0xca, 0xbe, 0xe3, 0xe2, 0x2c, 0x63, 0x6e, 0x79, 0xdc, 0xe3, - 0x49, 0x82, 0xc4, 0x91, 0xaa, 0x31, 0x8f, 0x5c, 0x2e, 0x06, 0x5c, 0x10, 0x87, 0x0a, 0xa6, 0xc4, - 0xe4, 0xb1, 0xe1, 0x30, 0x49, 0x1b, 0x24, 0xa4, 0x9e, 0x1f, 0x50, 0xe9, 0xf3, 0x20, 0xad, 0xdd, - 0x5d, 0x98, 0x94, 0x05, 0x2a, 0x69, 0x1f, 0xc3, 0xed, 0xab, 0x58, 0x7e, 0xc6, 0x02, 0x3e, 0xe8, - 0x46, 0xd4, 0x65, 0x1d, 0x36, 0x1c, 0x31, 0x21, 0x11, 0x82, 0xff, 0xfa, 0x54, 0xf4, 0x0d, 0x50, - 0x05, 0x87, 0x1b, 0x9d, 0x24, 0xb6, 0xbb, 0x70, 0x67, 0xa9, 0x5a, 0x84, 0x3c, 0x10, 0x0c, 0x9d, - 0x42, 0xbd, 0x17, 0xdf, 0xde, 0xc9, 0xf8, 0x3a, 0x51, 0xe9, 0x4d, 0x03, 0x17, 0xbd, 0xe0, 0x82, - 0x0c, 0xf6, 0x7e, 0x62, 0x9b, 0x2e, 0x75, 0x15, 0x19, 0xc4, 0x39, 0x84, 0xb9, 0x9f, 0xb4, 0x69, - 0x0d, 0x2b, 0xf3, 0x38, 0x36, 0x8f, 0xd5, 0xcb, 0xa5, 0xe6, 0xf1, 0x25, 0xf5, 0x32, 0x03, 0x9d, - 0x82, 0xd2, 0x7e, 0x05, 0xd0, 0x58, 0x9e, 0x91, 0xa2, 0xb7, 0x61, 0xb9, 0x80, 0x2e, 0x0c, 0x50, - 0xfd, 0xbb, 0x8a, 0xbd, 0xb5, 0x39, 0xf9, 0xa8, 0x68, 0x2f, 0x9f, 0x95, 0x52, 0xda, 0x47, 0xcf, - 0xbd, 0x08, 0x74, 0xb1, 0x40, 0xfc, 0x27, 0x21, 0x3e, 0x58, 0x4b, 0xac, 0x48, 0x8a, 0xc8, 0xcd, - 0x37, 0x00, 0xff, 0x27, 0xc8, 0xe8, 0x06, 0xc2, 0x7c, 0x3a, 0xda, 0x5b, 0xe4, 0xfa, 0xfd, 0xf7, - 0xcc, 0xfd, 0x35, 0x55, 0x6a, 0xa0, 0xad, 0xa1, 0x5b, 0xa8, 0x17, 0xde, 0x04, 0xad, 0xd6, 0x65, - 0xff, 0x62, 0xd6, 0xd6, 0x95, 0x65, 0xfd, 0x5b, 0xed, 0xc9, 0xcc, 0x02, 0xd3, 0x99, 0x05, 0xbe, - 0x66, 0x16, 0x78, 0x9e, 0x5b, 0xda, 0x74, 0x6e, 0x69, 0xef, 0x73, 0x4b, 0xbb, 0x6e, 0x78, 0xbe, - 0xec, 0x8f, 0x1c, 0xec, 0xf2, 0x01, 0x49, 0xd7, 0x59, 0x1d, 0x75, 0xd1, 0x7b, 0x20, 0x4f, 0xc4, - 0x77, 0xdc, 0x7a, 0xbe, 0xb6, 0xe3, 0x90, 0x09, 0xa7, 0x94, 0x2c, 0xed, 0xc9, 0x77, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x59, 0xc8, 0xc1, 0xaa, 0x3d, 0x03, 0x00, 0x00, + // 452 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0xbf, 0x8f, 0xd3, 0x30, + 0x14, 0xc7, 0xe3, 0x02, 0x27, 0xe1, 0x9c, 0x18, 0x2c, 0x04, 0x51, 0x40, 0xb9, 0x53, 0x74, 0x1c, + 0x50, 0xa8, 0xad, 0x94, 0x89, 0xb5, 0x42, 0x30, 0x74, 0x81, 0xaa, 0x13, 0x4b, 0xe5, 0xa4, 0x26, + 0x8d, 0xa0, 0x71, 0x1a, 0xbb, 0x88, 0x0a, 0xb1, 0x30, 0x31, 0x30, 0x20, 0xf1, 0x17, 0xb0, 0x32, + 0xf1, 0x67, 0x74, 0xac, 0xc4, 0xc2, 0x04, 0xa8, 0xe5, 0x0f, 0x41, 0xb1, 0x9d, 0x26, 0x55, 0x4f, + 0xcd, 0x94, 0xa7, 0xbc, 0x5f, 0x9f, 0xf7, 0xf5, 0x7b, 0xd0, 0x49, 0xc2, 0x88, 0xc8, 0x9c, 0xa6, + 0xe2, 0x15, 0xcb, 0xc9, 0x6c, 0xce, 0xf2, 0x05, 0xce, 0x72, 0x2e, 0x39, 0x3a, 0x4e, 0xc2, 0x08, + 0x97, 0x1e, 0xf7, 0x7a, 0xcc, 0x63, 0xae, 0x1c, 0xa4, 0xb0, 0x74, 0x8c, 0xdb, 0x8e, 0xb8, 0x98, + 0x72, 0x41, 0x42, 0x2a, 0x98, 0x4e, 0x26, 0x6f, 0x83, 0x90, 0x49, 0x1a, 0x90, 0x8c, 0xc6, 0x49, + 0x4a, 0x65, 0xc2, 0x53, 0x13, 0x7b, 0x6b, 0xa7, 0x53, 0x69, 0x18, 0xe7, 0xed, 0x98, 0xf3, 0xf8, + 0x0d, 0x23, 0x34, 0x4b, 0x08, 0x4d, 0x53, 0x2e, 0x55, 0xa6, 0xd0, 0x5e, 0xff, 0x21, 0xbc, 0xf1, + 0xa2, 0x28, 0xfe, 0x84, 0xa5, 0x7c, 0x3a, 0xcc, 0x69, 0xc4, 0x06, 0x6c, 0x36, 0x67, 0x42, 0x22, + 0x04, 0x2f, 0x4f, 0xa8, 0x98, 0x38, 0xe0, 0x14, 0xdc, 0xbb, 0x3a, 0x50, 0xb6, 0x3f, 0x84, 0x37, + 0xf7, 0xa2, 0x45, 0xc6, 0x53, 0xc1, 0xd0, 0x63, 0x68, 0x8f, 0x8b, 0xbf, 0x23, 0x59, 0xfc, 0x56, + 0x59, 0x76, 0xd7, 0xc1, 0xf5, 0x49, 0x71, 0x2d, 0x0d, 0x8e, 0xb7, 0xb6, 0x4f, 0xf7, 0xaa, 0x8a, + 0x12, 0xe2, 0x29, 0x84, 0xd5, 0xb4, 0xa6, 0xe8, 0x39, 0xd6, 0xd2, 0xe0, 0x42, 0x1a, 0xac, 0x75, + 0x35, 0xd2, 0xe0, 0xe7, 0x34, 0x2e, 0x07, 0x18, 0xd4, 0x32, 0xfd, 0x1f, 0x00, 0x3a, 0xfb, 0x3d, + 0x0c, 0x7a, 0x1f, 0x1e, 0xd7, 0xd0, 0x85, 0x03, 0x4e, 0x2f, 0x1d, 0x62, 0xef, 0x5d, 0x5b, 0xfe, + 0x3e, 0xb1, 0xbe, 0xff, 0x39, 0x39, 0x32, 0x75, 0xec, 0x6a, 0x16, 0x81, 0x9e, 0xed, 0x10, 0xb7, + 0x14, 0xf1, 0xdd, 0x46, 0x62, 0x4d, 0x52, 0x47, 0xee, 0x7e, 0x6b, 0xc1, 0x2b, 0x0a, 0x19, 0x7d, + 0x06, 0x10, 0x56, 0xed, 0xd1, 0xd9, 0x2e, 0xd8, 0xc5, 0xcf, 0xe7, 0xde, 0x69, 0x88, 0xd2, 0x1d, + 0xfd, 0xe0, 0xe3, 0xcf, 0x7f, 0x5f, 0x5b, 0x0f, 0xd0, 0x7d, 0x92, 0x84, 0xd1, 0x68, 0xbb, 0x43, + 0xe5, 0xaa, 0xd5, 0x75, 0x21, 0xef, 0x8b, 0x1d, 0xf8, 0x80, 0x3e, 0x01, 0x68, 0xd7, 0x64, 0x44, + 0x87, 0x3b, 0x95, 0x4f, 0xe9, 0x9e, 0x37, 0x85, 0x19, 0xa2, 0xb6, 0x22, 0x3a, 0x43, 0x7e, 0x33, + 0x51, 0xaf, 0xbf, 0x5c, 0x7b, 0x60, 0xb5, 0xf6, 0xc0, 0xdf, 0xb5, 0x07, 0xbe, 0x6c, 0x3c, 0x6b, + 0xb5, 0xf1, 0xac, 0x5f, 0x1b, 0xcf, 0x7a, 0x19, 0xc4, 0x89, 0x9c, 0xcc, 0x43, 0x1c, 0xf1, 0x29, + 0x31, 0x97, 0xa4, 0x3f, 0x1d, 0x31, 0x7e, 0x4d, 0xde, 0x15, 0xb5, 0x3b, 0xd5, 0xc5, 0x2c, 0x32, + 0x26, 0xc2, 0x23, 0x75, 0x11, 0x8f, 0xfe, 0x07, 0x00, 0x00, 0xff, 0xff, 0x5b, 0xa6, 0x29, 0xd0, + 0xb8, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -271,7 +277,7 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type QueryClient interface { - // DenomTrace queries a denomination trace info. + // DenomTrace queries a denomination trace information. DenomTrace(ctx context.Context, in *QueryDenomTraceRequest, opts ...grpc.CallOption) (*QueryDenomTraceResponse, error) // DenomTraces queries all denomination traces. DenomTraces(ctx context.Context, in *QueryDenomTracesRequest, opts ...grpc.CallOption) (*QueryDenomTracesResponse, error) @@ -305,7 +311,7 @@ func (c *queryClient) DenomTraces(ctx context.Context, in *QueryDenomTracesReque // QueryServer is the server API for Query service. type QueryServer interface { - // DenomTrace queries a denomination trace info. + // DenomTrace queries a denomination trace information. DenomTrace(context.Context, *QueryDenomTraceRequest) (*QueryDenomTraceResponse, error) // DenomTraces queries all denomination traces. DenomTraces(context.Context, *QueryDenomTracesRequest) (*QueryDenomTracesResponse, error) diff --git a/x/ibc-transfer/types/query.pb.gw.go b/x/ibc-transfer/types/query.pb.gw.go new file mode 100644 index 000000000000..397bb4791ca8 --- /dev/null +++ b/x/ibc-transfer/types/query.pb.gw.go @@ -0,0 +1,264 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: ibc/transfer/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +func request_Query_DenomTrace_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomTraceRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["hash"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "hash") + } + + protoReq.Hash, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "hash", err) + } + + msg, err := client.DenomTrace(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomTrace_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomTraceRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["hash"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "hash") + } + + protoReq.Hash, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "hash", err) + } + + msg, err := server.DenomTrace(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_DenomTraces_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_DenomTraces_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomTracesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DenomTraces_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.DenomTraces(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomTraces_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomTracesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DenomTraces_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.DenomTraces(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_DenomTrace_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomTrace_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomTrace_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomTraces_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomTraces_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomTraces_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_DenomTrace_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomTrace_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomTrace_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomTraces_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomTraces_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomTraces_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_DenomTrace_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"ibc_transfer", "v1beta1", "denom_traces", "hash"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_DenomTraces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"ibc_transfer", "v1beta1", "denom_traces"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Query_DenomTrace_0 = runtime.ForwardResponseMessage + + forward_Query_DenomTraces_0 = runtime.ForwardResponseMessage +) From c527795ab1fa253a486bd8c427dad5284285e0e1 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Fri, 14 Aug 2020 20:25:55 +0200 Subject: [PATCH 33/41] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- x/ibc-transfer/client/cli/query.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/ibc-transfer/client/cli/query.go b/x/ibc-transfer/client/cli/query.go index cdf5f575b6a1..bdf47b7c67b3 100644 --- a/x/ibc-transfer/client/cli/query.go +++ b/x/ibc-transfer/client/cli/query.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" ) -// GetCmdQueryDenomTraces defines the command to query all the denomination trace infos +// GetCmdQueryDenomTraces defines the command to query all the denomination trace information // that this chain mantains. func GetCmdQueryDenomTraces() *cobra.Command { cmd := &cobra.Command{ @@ -48,12 +48,12 @@ func GetCmdQueryDenomTraces() *cobra.Command { }, } flags.AddQueryFlagsToCmd(cmd) - flags.AddPaginationFlagsToCmd(cmd, "denominations trace") + flags.AddPaginationFlagsToCmd(cmd, "denomination traces") return cmd } -// GetCmdQueryDenomTrace defines the command to query a a denomination trace from a given hash. +// GetCmdQueryDenomTrace defines the command to query a denomination trace from a given hash. func GetCmdQueryDenomTrace() *cobra.Command { cmd := &cobra.Command{ Use: "denom-trace [hash]", From 8e26f54954e7b60e3207ddab5f22c6b5169b7e47 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 22:10:47 +0200 Subject: [PATCH 34/41] address comments --- .../adr-001-coin-source-tracing.md | 27 +----- proto/ibc/transfer/transfer.proto | 9 +- x/ibc-transfer/client/cli/query.go | 64 ++++++------ x/ibc-transfer/keeper/genesis_test.go | 10 +- x/ibc-transfer/keeper/grpc_query_test.go | 10 +- x/ibc-transfer/keeper/relay.go | 41 ++++---- x/ibc-transfer/types/msgs_test.go | 4 +- x/ibc-transfer/types/trace.go | 51 +++------- x/ibc-transfer/types/trace_test.go | 44 +++------ x/ibc-transfer/types/transfer.pb.go | 97 ++++++++++--------- 10 files changed, 152 insertions(+), 205 deletions(-) diff --git a/docs/architecture/adr-001-coin-source-tracing.md b/docs/architecture/adr-001-coin-source-tracing.md index 4d05614415e3..371c933d56f9 100644 --- a/docs/architecture/adr-001-coin-source-tracing.md +++ b/docs/architecture/adr-001-coin-source-tracing.md @@ -125,7 +125,7 @@ The hash function will be a SHA256 hash of the fields of the `DenomTrace`: // information message DenomTrace { // chain of port/channel identifiers used for tracing the source of the fungible token - string trace = 1; + string path = 1; // base denomination of the relayed fungible token string base_denom = 2; } @@ -151,31 +151,6 @@ func (dt DenomTrace) IBCDenom() string { } ``` -In order to trim the denomination trace prefix when sending/receiving fungible tokens, the `RemovePrefix` function is provided. - -> NOTE: the prefix addition must be done on the client side. - -```golang -// RemovePrefix trims the first portID/channelID pair from the trace info. If the trace is already -// empty it will perform a no-op. If the trace is incorrectly constructed or doesn't have separators -// it will return an error. -func (dt *DenomTrace) RemovePrefix() { - if dt.Trace == "" { - return - } - - traceSplit := strings.SplitN(dt.Trace, "/", 3) - - switch { - // NOTE: other cases are checked during msg validation - case len(traceSplit) == 2: - dt.Trace = "" - case len(traceSplit) == 3: - dt.Trace = traceSplit[2] - } -} -``` - ### `x/ibc-transfer` Changes In order to retrieve the trace information from an IBC denomination, a lookup table needs to be diff --git a/proto/ibc/transfer/transfer.proto b/proto/ibc/transfer/transfer.proto index 6364f355caac..b49e8b3dcf20 100644 --- a/proto/ibc/transfer/transfer.proto +++ b/proto/ibc/transfer/transfer.proto @@ -52,10 +52,11 @@ message FungibleTokenPacketAcknowledgement { } // DenomTrace contains the base denomination for ICS20 fungible tokens and the source tracing -// information +// information path. message DenomTrace { - // chain of port/channel identifiers used for tracing the source of the fungible token - string trace = 1; - // base denomination of the relayed fungible token + // path defines the chain of port/channel identifiers used for tracing the source of the fungible + // token. + string path = 1; + // base denomination of the relayed fungible token. string base_denom = 2; } diff --git a/x/ibc-transfer/client/cli/query.go b/x/ibc-transfer/client/cli/query.go index cdf5f575b6a1..c794367901e3 100644 --- a/x/ibc-transfer/client/cli/query.go +++ b/x/ibc-transfer/client/cli/query.go @@ -12,34 +12,27 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" ) -// GetCmdQueryDenomTraces defines the command to query all the denomination trace infos -// that this chain mantains. -func GetCmdQueryDenomTraces() *cobra.Command { +// GetCmdQueryDenomTrace defines the command to query a a denomination trace from a given hash. +func GetCmdQueryDenomTrace() *cobra.Command { cmd := &cobra.Command{ - Use: "denom-traces", - Short: "Query the trace info for all token denominations", - Long: "Query the trace info for all token denominations", - Example: fmt.Sprintf("%s query ibc-transfer denom-traces", version.AppName), - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { + Use: "denom-trace [hash]", + Short: "Query the denom trace info from a given trace hash", + Long: "Query the denom trace info from a given trace hash", + Example: fmt.Sprintf("%s query ibc-transfer denom-trace [hash]", version.AppName), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) clientCtx, err := client.ReadQueryCommandFlags(clientCtx, cmd.Flags()) if err != nil { return err } - queryClient := types.NewQueryClient(clientCtx) - pageReq, err := client.ReadPageRequest(cmd.Flags()) - if err != nil { - return err - } - - req := &types.QueryDenomTracesRequest{ - Pagination: pageReq, + req := &types.QueryDenomTraceRequest{ + Hash: args[0], } - res, err := queryClient.DenomTraces(context.Background(), req) + res, err := queryClient.DenomTrace(context.Background(), req) if err != nil { return err } @@ -47,33 +40,39 @@ func GetCmdQueryDenomTraces() *cobra.Command { return clientCtx.PrintOutput(res) }, } - flags.AddQueryFlagsToCmd(cmd) - flags.AddPaginationFlagsToCmd(cmd, "denominations trace") + flags.AddQueryFlagsToCmd(cmd) return cmd } -// GetCmdQueryDenomTrace defines the command to query a a denomination trace from a given hash. -func GetCmdQueryDenomTrace() *cobra.Command { +// GetCmdQueryDenomTraces defines the command to query all the denomination trace infos +// that this chain mantains. +func GetCmdQueryDenomTraces() *cobra.Command { cmd := &cobra.Command{ - Use: "denom-trace [hash]", - Short: "Query the denom trace info from a given trace hash", - Long: "Query the denom trace info from a given trace hash", - Example: fmt.Sprintf("%s query ibc-transfer denom-trace [hash]", version.AppName), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + Use: "denom-traces", + Short: "Query the trace info for all token denominations", + Long: "Query the trace info for all token denominations", + Example: fmt.Sprintf("%s query ibc-transfer denom-traces", version.AppName), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { clientCtx := client.GetClientContextFromCmd(cmd) clientCtx, err := client.ReadQueryCommandFlags(clientCtx, cmd.Flags()) if err != nil { return err } + queryClient := types.NewQueryClient(clientCtx) - req := &types.QueryDenomTraceRequest{ - Hash: args[0], + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err } - res, err := queryClient.DenomTrace(context.Background(), req) + req := &types.QueryDenomTracesRequest{ + Pagination: pageReq, + } + + res, err := queryClient.DenomTraces(context.Background(), req) if err != nil { return err } @@ -81,7 +80,8 @@ func GetCmdQueryDenomTrace() *cobra.Command { return clientCtx.PrintOutput(res) }, } - flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "denominations trace") + return cmd } diff --git a/x/ibc-transfer/keeper/genesis_test.go b/x/ibc-transfer/keeper/genesis_test.go index c63334e1f20b..19005cdd3bf5 100644 --- a/x/ibc-transfer/keeper/genesis_test.go +++ b/x/ibc-transfer/keeper/genesis_test.go @@ -8,21 +8,21 @@ import ( func (suite *KeeperTestSuite) TestGenesis() { var ( - traceStr string - traces types.Traces + path string + traces types.Traces ) for i := 0; i < 5; i++ { prefix := fmt.Sprintf("transfer/channelToChain%d", i) if i == 0 { - traceStr = prefix + path = prefix } else { - traceStr = prefix + "/" + traceStr + path = prefix + "/" + path } denomTrace := types.DenomTrace{ BaseDenom: "uatom", - Trace: traceStr, + Path: path, } traces = append(types.Traces{denomTrace}, traces...) suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), denomTrace) diff --git a/x/ibc-transfer/keeper/grpc_query_test.go b/x/ibc-transfer/keeper/grpc_query_test.go index 99d61356e185..e01e36529bdf 100644 --- a/x/ibc-transfer/keeper/grpc_query_test.go +++ b/x/ibc-transfer/keeper/grpc_query_test.go @@ -31,7 +31,7 @@ func (suite *KeeperTestSuite) TestQueryConnection() { { "not found denom trace", func() { - expTrace.Trace = "transfer/channelToA/transfer/channelToB" + expTrace.Path = "transfer/channelToA/transfer/channelToB" expTrace.BaseDenom = "uatom" req = &types.QueryDenomTraceRequest{ Hash: expTrace.Hash().String(), @@ -42,7 +42,7 @@ func (suite *KeeperTestSuite) TestQueryConnection() { { "success", func() { - expTrace.Trace = "transfer/channelToA/transfer/channelToB" + expTrace.Path = "transfer/channelToA/transfer/channelToB" expTrace.BaseDenom = "uatom" suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), expTrace) @@ -95,9 +95,9 @@ func (suite *KeeperTestSuite) TestQueryConnections() { { "success", func() { - expTraces = append(expTraces, types.DenomTrace{Trace: "", BaseDenom: "uatom"}) - expTraces = append(expTraces, types.DenomTrace{Trace: "transfer/channelToB", BaseDenom: "uatom"}) - expTraces = append(expTraces, types.DenomTrace{Trace: "transfer/channelToA/transfer/channelToB", BaseDenom: "uatom"}) + expTraces = append(expTraces, types.DenomTrace{Path: "", BaseDenom: "uatom"}) + expTraces = append(expTraces, types.DenomTrace{Path: "transfer/channelToB", BaseDenom: "uatom"}) + expTraces = append(expTraces, types.DenomTrace{Path: "transfer/channelToA/transfer/channelToB", BaseDenom: "uatom"}) for _, trace := range expTraces { suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), trace) diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index c089307d669e..791cb8bf93e2 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -77,35 +77,24 @@ func (k Keeper) SendTransfer( } // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic - prefixedDenom := token.Denom + fullDenomPath := token.Denom + + var err error // deconstruct the token denomination into the denomination trace info // to determine if the sender is the source chain if strings.HasPrefix(token.Denom, "ibc/") { - hexHash := token.Denom[4:] - hash, err := types.ParseHexHash(hexHash) + fullDenomPath, err = k.DenomPathFromHash(ctx, token.Denom) if err != nil { return err } - - denomTrace, found := k.GetDenomTrace(ctx, hash) - if !found { - return sdkerrors.Wrap(types.ErrTraceNotFound, hexHash) - } - prefixedDenom = denomTrace.GetPrefix() + denomTrace.BaseDenom - } else if strings.Contains(token.Denom, "/") { - // in the case the user transfers a prefixed denomination, - // update the token denomination with the hashed trace info since that is the - // internally represented denomination on the user balance - denomTrace := types.ParseDenomTrace(token.Denom) - token.Denom = denomTrace.IBCDenom() } // NOTE: SendTransfer simply sends the denomination as it exists on its own // chain inside the packet data. The receiving chain will perform denom // prefixing as necessary. - if types.SenderChainIsSource(sourcePort, sourceChannel, prefixedDenom) { + if types.SenderChainIsSource(sourcePort, sourceChannel, fullDenomPath) { // create the escrow address for the tokens escrowAddress := types.GetEscrowAddress(sourcePort, sourceChannel) @@ -135,7 +124,7 @@ func (k Keeper) SendTransfer( } packetData := types.NewFungibleTokenPacketData( - prefixedDenom, token.Amount.Uint64(), sender.String(), receiver, + fullDenomPath, token.Amount.Uint64(), sender.String(), receiver, ) packet := channeltypes.NewPacket( @@ -276,3 +265,21 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, sdk.NewCoins(token)) } + +// DenomPathFromHash returns the full denomination path prefix from an ibc denom with a hash +// compoenent. +func (k Keeper) DenomPathFromHash(ctx sdk.Context, denom string) (string, error) { + hexHash := denom[4:] + hash, err := types.ParseHexHash(hexHash) + if err != nil { + return "", sdkerrors.Wrap(types.ErrInvalidDenomForTransfer, err.Error()) + } + + denomTrace, found := k.GetDenomTrace(ctx, hash) + if !found { + return "", sdkerrors.Wrap(types.ErrTraceNotFound, hexHash) + } + + fullDenomPath := denomTrace.GetFullDenomPath() + return fullDenomPath, nil +} diff --git a/x/ibc-transfer/types/msgs_test.go b/x/ibc-transfer/types/msgs_test.go index 9ad9ce9e9192..6895a874602e 100644 --- a/x/ibc-transfer/types/msgs_test.go +++ b/x/ibc-transfer/types/msgs_test.go @@ -31,7 +31,7 @@ var ( ibcCoin = sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)) invalidIBCCoin = sdk.NewCoin("notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)) invalidDenomCoin = sdk.Coin{Denom: "0atom", Amount: sdk.NewInt(100)} - negativeCoin = sdk.Coin{Denom: "atoms", Amount: sdk.NewInt(-100)} + zeroCoin = sdk.Coin{Denom: "atoms", Amount: sdk.NewInt(0)} ) // TestMsgTransferRoute tests Route for MsgTransfer @@ -65,7 +65,7 @@ func TestMsgTransferValidation(t *testing.T) { {"too long channel id", NewMsgTransfer(validPort, invalidLongChannel, coin, addr1, addr2, 10, 0), false}, {"channel id contains non-alpha", NewMsgTransfer(validPort, invalidChannel, coin, addr1, addr2, 10, 0), false}, {"invalid denom", NewMsgTransfer(validPort, validChannel, invalidDenomCoin, addr1, addr2, 10, 0), false}, - {"negative coin", NewMsgTransfer(validPort, validChannel, negativeCoin, addr1, addr2, 10, 0), false}, + {"zero coin", NewMsgTransfer(validPort, validChannel, zeroCoin, addr1, addr2, 10, 0), false}, {"missing sender address", NewMsgTransfer(validPort, validChannel, coin, emptyAddr, addr2, 10, 0), false}, {"missing recipient address", NewMsgTransfer(validPort, validChannel, coin, addr1, "", 10, 0), false}, {"empty coin", NewMsgTransfer(validPort, validChannel, sdk.Coin{}, addr1, addr2, 10, 0), false}, diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 19e4b4e196f5..07b4b6f69c8c 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -20,20 +20,20 @@ import ( // // Examples: // -// - "portidone/channelidone/uatom" => DenomTrace{Trace: "portidone/channelidone", BaseDenom: "uatom"} -// - "uatom" => DenomTrace{Trace: "", BaseDenom: "uatom"} +// - "portidone/channelidone/uatom" => DenomTrace{Path: "portidone/channelidone", BaseDenom: "uatom"} +// - "uatom" => DenomTrace{Path: "", BaseDenom: "uatom"} func ParseDenomTrace(rawDenom string) DenomTrace { denomSplit := strings.Split(rawDenom, "/") if denomSplit[0] == rawDenom { return DenomTrace{ - Trace: "", + Path: "", BaseDenom: rawDenom, } } return DenomTrace{ - Trace: strings.Join(denomSplit[:len(denomSplit)-1], "/"), + Path: strings.Join(denomSplit[:len(denomSplit)-1], "/"), BaseDenom: denomSplit[len(denomSplit)-1], } } @@ -42,40 +42,27 @@ func ParseDenomTrace(rawDenom string) DenomTrace { // // hash = sha256(trace + "/" + baseDenom) func (dt DenomTrace) Hash() tmbytes.HexBytes { - return tmhash.Sum([]byte(dt.GetPrefix() + dt.BaseDenom)) + return tmhash.Sum([]byte(dt.GetFullDenomPath())) } // GetPrefix returns the receiving denomination prefix composed by the trace info and a separator. func (dt DenomTrace) GetPrefix() string { - return dt.Trace + "/" + return dt.Path + "/" } // IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + // baseDenom)}'. If the trace is empty, it will return the base denomination. func (dt DenomTrace) IBCDenom() string { - if dt.Trace != "" { + if dt.Path != "" { return fmt.Sprintf("ibc/%s", dt.Hash()) } return dt.BaseDenom } -// RemovePrefix trims the first portID/channelID pair from the trace info. If the trace is already -// empty it will perform a no-op. If the trace is incorrectly constructed or doesn't have separators -// it will return an error. -func (dt *DenomTrace) RemovePrefix() { - if dt.Trace == "" { - return - } - - traceSplit := strings.SplitN(dt.Trace, "/", 3) - - switch { - // NOTE: other cases are checked during msg validation - case len(traceSplit) == 2: - dt.Trace = "" - case len(traceSplit) == 3: - dt.Trace = traceSplit[2] - } +// GetFullDenomPath returns the full denomination according to the ICS20 specification: trace + "/" +// + baseDenom +func (dt DenomTrace) GetFullDenomPath() string { + return dt.GetPrefix() + dt.BaseDenom } func validateTraceIdentifiers(identifiers []string) error { @@ -99,17 +86,15 @@ func validateTraceIdentifiers(identifiers []string) error { func (dt DenomTrace) Validate() error { // empty trace is accepted when token lives on the original chain switch { - case dt.Trace == "" && dt.BaseDenom != "": + case dt.Path == "" && dt.BaseDenom != "": return nil - case strings.TrimSpace(dt.Trace) == "" && strings.TrimSpace(dt.BaseDenom) == "": - return fmt.Errorf("cannot have an empty trace and empty base denomination") - case dt.Trace != "" && strings.TrimSpace(dt.BaseDenom) == "": - return sdkerrors.Wrap(ErrInvalidDenomForTransfer, "denomination cannot be blank") + case strings.TrimSpace(dt.BaseDenom) == "": + return fmt.Errorf("base denomination cannot be blank") } // NOTE: no base denomination validation - identifiers := strings.Split(dt.Trace, "/") + identifiers := strings.Split(dt.Path, "/") return validateTraceIdentifiers(identifiers) } @@ -156,10 +141,9 @@ func ValidatePrefixedDenom(denom string) error { // ValidateIBCDenom validates that the given denomination is either: // // - A valid base denomination (eg: 'uatom') -// - A valid trace prefixed denomination (eg: '{portIDN}/{channelIDN}/.../{portID0}/{channelID0}/baseDenom') // - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-001-coin-source-tracing.md func ValidateIBCDenom(denom string) error { - denomSplit := strings.Split(denom, "/") + denomSplit := strings.SplitN(denom, "/", 2) switch { case strings.TrimSpace(denom) == "", @@ -169,9 +153,6 @@ func ValidateIBCDenom(denom string) error { case denomSplit[0] == denom && strings.TrimSpace(denom) != "": return sdk.ValidateDenom(denom) - - case len(denomSplit) > 2: - return validateTraceIdentifiers(denomSplit[:len(denomSplit)-1]) } if _, err := ParseHexHash(denomSplit[1]); err != nil { diff --git a/x/ibc-transfer/types/trace_test.go b/x/ibc-transfer/types/trace_test.go index 33760506cb22..837219acd9ee 100644 --- a/x/ibc-transfer/types/trace_test.go +++ b/x/ibc-transfer/types/trace_test.go @@ -14,7 +14,7 @@ func TestParseDenomTrace(t *testing.T) { }{ {"empty denom", "", DenomTrace{}}, {"base denom", "uatom", DenomTrace{BaseDenom: "uatom"}}, - {"trace info", "transfer/channelToA/uatom", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA"}}, + {"trace info", "transfer/channelToA/uatom", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA"}}, } for _, tc := range testCases { @@ -30,7 +30,7 @@ func TestDenomTrace_IBCDenom(t *testing.T) { expDenom string }{ {"base denom", DenomTrace{BaseDenom: "uatom"}, "uatom"}, - {"trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA"}, "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2"}, + {"trace info", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA"}, "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2"}, } for _, tc := range testCases { @@ -39,23 +39,6 @@ func TestDenomTrace_IBCDenom(t *testing.T) { } } -func TestDenomTrace_RemovePrefix(t *testing.T) { - testCases := []struct { - name string - trace DenomTrace - expTrace string - }{ - {"no trace", DenomTrace{BaseDenom: "uatom"}, ""}, - {"single trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA"}, ""}, - {"multiple trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}, "transfer/channelToB"}, - } - - for _, tc := range testCases { - tc.trace.RemovePrefix() - require.Equal(t, tc.expTrace, tc.trace.Trace, tc.name) - } -} - func TestDenomTrace_Validate(t *testing.T) { testCases := []struct { name string @@ -64,12 +47,12 @@ func TestDenomTrace_Validate(t *testing.T) { }{ {"base denom only", DenomTrace{BaseDenom: "uatom"}, false}, {"empty DenomTrace", DenomTrace{}, true}, - {"valid single trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA"}, false}, - {"valid multiple trace info", DenomTrace{BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}, false}, - {"single trace identifier", DenomTrace{BaseDenom: "uatom", Trace: "transfer"}, true}, - {"invalid port ID", DenomTrace{BaseDenom: "uatom", Trace: "(transfer)/channelToA"}, true}, - {"invalid channel ID", DenomTrace{BaseDenom: "uatom", Trace: "transfer/(channelToA)"}, true}, - {"empty base denom with trace", DenomTrace{BaseDenom: "", Trace: "transfer/channelToA"}, true}, + {"valid single trace info", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA"}, false}, + {"valid multiple trace info", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA/transfer/channelToB"}, false}, + {"single trace identifier", DenomTrace{BaseDenom: "uatom", Path: "transfer"}, true}, + {"invalid port ID", DenomTrace{BaseDenom: "uatom", Path: "(transfer)/channelToA"}, true}, + {"invalid channel ID", DenomTrace{BaseDenom: "uatom", Path: "transfer/(channelToA)"}, true}, + {"empty base denom with trace", DenomTrace{BaseDenom: "", Path: "transfer/channelToA"}, true}, } for _, tc := range testCases { @@ -89,16 +72,16 @@ func TestTraces_Validate(t *testing.T) { expError bool }{ {"empty Traces", Traces{}, false}, - {"valid multiple trace info", Traces{{BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}}, false}, + {"valid multiple trace info", Traces{{BaseDenom: "uatom", Path: "transfer/channelToA/transfer/channelToB"}}, false}, { "valid multiple trace info", Traces{ - {BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}, - {BaseDenom: "uatom", Trace: "transfer/channelToA/transfer/channelToB"}, + {BaseDenom: "uatom", Path: "transfer/channelToA/transfer/channelToB"}, + {BaseDenom: "uatom", Path: "transfer/channelToA/transfer/channelToB"}, }, true, }, - {"empty base denom with trace", Traces{{BaseDenom: "", Trace: "transfer/channelToA"}}, true}, + {"empty base denom with trace", Traces{{BaseDenom: "", Path: "transfer/channelToA"}}, true}, } for _, tc := range testCases { @@ -146,7 +129,7 @@ func TestValidateIBCDenom(t *testing.T) { {"denom with trace hash", "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", false}, {"base denom", "uatom", false}, {"empty denom", "", true}, - {"invalid prefixed denom", "transfer/channelToA/uatom", false}, + {"invalid prefixed denom", "transfer/channelToA/uatom", true}, {"denom 'ibc'", "ibc", true}, {"denom 'ibc/'", "ibc/", true}, {"invald prefix", "notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", true}, @@ -154,7 +137,6 @@ func TestValidateIBCDenom(t *testing.T) { } for _, tc := range testCases { - t.Log(tc.name) err := ValidateIBCDenom(tc.denom) if tc.expError { require.Error(t, err, tc.name) diff --git a/x/ibc-transfer/types/transfer.pb.go b/x/ibc-transfer/types/transfer.pb.go index 8ca232877e2d..f8c0f63b147e 100644 --- a/x/ibc-transfer/types/transfer.pb.go +++ b/x/ibc-transfer/types/transfer.pb.go @@ -261,11 +261,12 @@ func (m *FungibleTokenPacketAcknowledgement) GetError() string { } // DenomTrace contains the base denomination for ICS20 fungible tokens and the source tracing -// information +// information path. type DenomTrace struct { - // chain of port/channel identifiers used for tracing the source of the fungible token - Trace string `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"` - // base denomination of the relayed fungible token + // path defines the chain of port/channel identifiers used for tracing the source of the fungible + // token. + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + // base denomination of the relayed fungible token. BaseDenom string `protobuf:"bytes,2,opt,name=base_denom,json=baseDenom,proto3" json:"base_denom,omitempty"` } @@ -302,9 +303,9 @@ func (m *DenomTrace) XXX_DiscardUnknown() { var xxx_messageInfo_DenomTrace proto.InternalMessageInfo -func (m *DenomTrace) GetTrace() string { +func (m *DenomTrace) GetPath() string { if m != nil { - return m.Trace + return m.Path } return "" } @@ -326,41 +327,41 @@ func init() { func init() { proto.RegisterFile("ibc/transfer/transfer.proto", fileDescriptor_08134a70fd29e656) } var fileDescriptor_08134a70fd29e656 = []byte{ - // 537 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0x8e, 0xc9, 0x4f, 0xdb, 0x4d, 0x8b, 0x60, 0x55, 0x8a, 0x1b, 0xc0, 0x89, 0x7c, 0xca, 0x25, - 0xb6, 0x02, 0x42, 0x48, 0x9c, 0x48, 0x5a, 0x21, 0x2a, 0x84, 0x54, 0xad, 0x72, 0xe2, 0x12, 0xad, - 0xd7, 0x83, 0x63, 0x25, 0xde, 0x8d, 0x76, 0xd7, 0x85, 0x8a, 0x97, 0xe0, 0x5d, 0x78, 0x89, 0x1e, - 0x7b, 0xe4, 0x14, 0xa1, 0xe4, 0x0d, 0x72, 0xe4, 0x84, 0xd6, 0xeb, 0x84, 0x46, 0xaa, 0x38, 0x79, - 0xbf, 0x6f, 0xbe, 0x19, 0x7f, 0x33, 0x3b, 0x8b, 0x9e, 0xa5, 0x11, 0x0b, 0xb5, 0xa4, 0x5c, 0x7d, - 0x01, 0xb9, 0x3d, 0x04, 0x73, 0x29, 0xb4, 0xc0, 0x87, 0x69, 0xc4, 0x82, 0x0d, 0xd7, 0x3a, 0x4e, - 0x44, 0x22, 0x8a, 0x40, 0x68, 0x4e, 0x56, 0xd3, 0xf2, 0x98, 0x50, 0x99, 0x50, 0x61, 0x44, 0x15, - 0x84, 0x57, 0xfd, 0x08, 0x34, 0xed, 0x87, 0x4c, 0xa4, 0xdc, 0xc6, 0xfd, 0x9f, 0x55, 0xd4, 0xfc, - 0xa4, 0x92, 0x51, 0x59, 0x05, 0xbf, 0x41, 0x4d, 0x25, 0x72, 0xc9, 0x60, 0x3c, 0x17, 0x52, 0xbb, - 0x4e, 0xc7, 0xe9, 0x1e, 0x0c, 0x4f, 0xd6, 0x8b, 0x36, 0xbe, 0xa6, 0xd9, 0xec, 0xad, 0x7f, 0x27, - 0xe8, 0x13, 0x64, 0xd1, 0xa5, 0x90, 0x1a, 0xbf, 0x43, 0x0f, 0xcb, 0x18, 0x9b, 0x50, 0xce, 0x61, - 0xe6, 0x3e, 0x28, 0x72, 0x4f, 0xd7, 0x8b, 0xf6, 0x93, 0x9d, 0xdc, 0x32, 0xee, 0x93, 0x23, 0x4b, - 0x9c, 0x59, 0x8c, 0x5f, 0xa3, 0xba, 0x16, 0x53, 0xe0, 0x6e, 0xb5, 0xe3, 0x74, 0x9b, 0x2f, 0x4f, - 0x03, 0x6b, 0x3d, 0x30, 0xd6, 0x83, 0xd2, 0x7a, 0x70, 0x26, 0x52, 0x3e, 0xac, 0xdd, 0x2c, 0xda, - 0x15, 0x62, 0xd5, 0xf8, 0x02, 0x35, 0x14, 0xf0, 0x18, 0xa4, 0x5b, 0xeb, 0x38, 0xdd, 0xc3, 0x61, - 0xff, 0xcf, 0xa2, 0xdd, 0x4b, 0x52, 0x3d, 0xc9, 0xa3, 0x80, 0x89, 0x2c, 0x2c, 0x07, 0x60, 0x3f, - 0x3d, 0x15, 0x4f, 0x43, 0x7d, 0x3d, 0x07, 0x15, 0x0c, 0x18, 0x1b, 0xc4, 0xb1, 0x04, 0xa5, 0x48, - 0x59, 0x00, 0xb7, 0xd0, 0xbe, 0x04, 0x06, 0xe9, 0x15, 0x48, 0xb7, 0x6e, 0xdc, 0x93, 0x2d, 0x36, - 0xfd, 0xe9, 0x34, 0x03, 0x91, 0xeb, 0xf1, 0x04, 0xd2, 0x64, 0xa2, 0xdd, 0x46, 0xc7, 0xe9, 0xd6, - 0xee, 0xf6, 0xb7, 0x1b, 0xf7, 0xc9, 0x51, 0x49, 0x7c, 0x28, 0x30, 0xbe, 0x40, 0x8f, 0x37, 0x0a, - 0xf3, 0x55, 0x9a, 0x66, 0x73, 0x77, 0xaf, 0x28, 0xf2, 0x7c, 0xbd, 0x68, 0xbb, 0xbb, 0x45, 0xb6, - 0x12, 0x9f, 0x3c, 0x2a, 0xb9, 0xd1, 0x96, 0xfa, 0x8e, 0x9e, 0xbe, 0xcf, 0x79, 0x92, 0x46, 0x33, - 0x18, 0x99, 0x21, 0x5c, 0x52, 0x36, 0x05, 0x7d, 0x4e, 0x35, 0xc5, 0xc7, 0xa8, 0x1e, 0x03, 0x17, - 0x99, 0xbd, 0x3a, 0x62, 0x01, 0x3e, 0x41, 0x0d, 0x9a, 0x89, 0x9c, 0xeb, 0xe2, 0x56, 0x6a, 0xa4, - 0x44, 0x86, 0x2f, 0x87, 0x57, 0x2d, 0xe4, 0xf7, 0x4d, 0xa2, 0xb6, 0x3b, 0x09, 0x7f, 0x84, 0xfc, - 0x7b, 0x7e, 0x3e, 0x60, 0x53, 0x2e, 0xbe, 0xce, 0x20, 0x4e, 0x20, 0x03, 0xae, 0xb1, 0x8b, 0xf6, - 0x54, 0xce, 0x18, 0x28, 0x55, 0x38, 0xd9, 0x27, 0x1b, 0x68, 0x1c, 0x82, 0x94, 0x42, 0xda, 0x05, - 0x21, 0x16, 0xf8, 0x03, 0x84, 0xce, 0x8d, 0xd5, 0x91, 0xa4, 0x0c, 0x8c, 0x46, 0x9b, 0xc3, 0xa6, - 0x8b, 0x02, 0xe0, 0x17, 0x08, 0x99, 0x65, 0x18, 0xdb, 0x06, 0x6d, 0xfa, 0x81, 0x61, 0x8a, 0xcc, - 0xe1, 0xc7, 0x9b, 0xa5, 0xe7, 0xdc, 0x2e, 0x3d, 0xe7, 0xf7, 0xd2, 0x73, 0x7e, 0xac, 0xbc, 0xca, - 0xed, 0xca, 0xab, 0xfc, 0x5a, 0x79, 0x95, 0xcf, 0xfd, 0xff, 0xee, 0xc3, 0xb7, 0x30, 0x8d, 0x58, - 0xef, 0xdf, 0x2b, 0x33, 0xeb, 0x11, 0x35, 0x8a, 0xf7, 0xf1, 0xea, 0x6f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x9e, 0xc3, 0xf0, 0x85, 0x82, 0x03, 0x00, 0x00, + // 541 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0xc1, 0x6e, 0xd3, 0x4c, + 0x10, 0x8e, 0xff, 0xba, 0x69, 0xbb, 0x69, 0x7f, 0xc1, 0xaa, 0x14, 0x37, 0x80, 0x13, 0xf9, 0x94, + 0x4b, 0x6c, 0x05, 0x84, 0x90, 0xb8, 0x40, 0xd2, 0x0a, 0x51, 0x21, 0xa4, 0xca, 0xca, 0x89, 0x4b, + 0xb4, 0x5e, 0x0f, 0x8e, 0x95, 0x78, 0x37, 0xda, 0x5d, 0x17, 0x2a, 0x5e, 0x82, 0x77, 0xe1, 0x25, + 0x7a, 0xec, 0x91, 0x53, 0x84, 0x92, 0x37, 0xc8, 0x91, 0x13, 0x5a, 0xef, 0x26, 0x34, 0x52, 0xc5, + 0xc9, 0xfb, 0x7d, 0xdf, 0xcc, 0xf8, 0x9b, 0xd9, 0x59, 0xf4, 0x24, 0x4f, 0x68, 0xa4, 0x04, 0x61, + 0xf2, 0x33, 0x88, 0xcd, 0x21, 0x9c, 0x09, 0xae, 0x38, 0x3e, 0xcc, 0x13, 0x1a, 0xae, 0xb9, 0xe6, + 0x71, 0xc6, 0x33, 0x5e, 0x09, 0x91, 0x3e, 0x99, 0x98, 0xa6, 0x4f, 0xb9, 0x2c, 0xb8, 0x8c, 0x12, + 0x22, 0x21, 0xba, 0xea, 0x25, 0xa0, 0x48, 0x2f, 0xa2, 0x3c, 0x67, 0x46, 0x0f, 0x7e, 0xec, 0xa0, + 0xc6, 0x47, 0x99, 0x0d, 0x6d, 0x15, 0xfc, 0x0a, 0x35, 0x24, 0x2f, 0x05, 0x85, 0xd1, 0x8c, 0x0b, + 0xe5, 0x39, 0x6d, 0xa7, 0x73, 0x30, 0x38, 0x59, 0xcd, 0x5b, 0xf8, 0x9a, 0x14, 0xd3, 0xd7, 0xc1, + 0x1d, 0x31, 0x88, 0x91, 0x41, 0x97, 0x5c, 0x28, 0xfc, 0x16, 0xfd, 0x6f, 0x35, 0x3a, 0x26, 0x8c, + 0xc1, 0xd4, 0xfb, 0xaf, 0xca, 0x3d, 0x5d, 0xcd, 0x5b, 0x8f, 0xb6, 0x72, 0xad, 0x1e, 0xc4, 0x47, + 0x86, 0x38, 0x33, 0x18, 0xbf, 0x44, 0xbb, 0x8a, 0x4f, 0x80, 0x79, 0x3b, 0x6d, 0xa7, 0xd3, 0x78, + 0x7e, 0x1a, 0x1a, 0xeb, 0xa1, 0xb6, 0x1e, 0x5a, 0xeb, 0xe1, 0x19, 0xcf, 0xd9, 0xc0, 0xbd, 0x99, + 0xb7, 0x6a, 0xb1, 0x89, 0xc6, 0x17, 0xa8, 0x2e, 0x81, 0xa5, 0x20, 0x3c, 0xb7, 0xed, 0x74, 0x0e, + 0x07, 0xbd, 0xdf, 0xf3, 0x56, 0x37, 0xcb, 0xd5, 0xb8, 0x4c, 0x42, 0xca, 0x8b, 0xc8, 0x0e, 0xc0, + 0x7c, 0xba, 0x32, 0x9d, 0x44, 0xea, 0x7a, 0x06, 0x32, 0xec, 0x53, 0xda, 0x4f, 0x53, 0x01, 0x52, + 0xc6, 0xb6, 0x00, 0x6e, 0xa2, 0x7d, 0x01, 0x14, 0xf2, 0x2b, 0x10, 0xde, 0xae, 0x76, 0x1f, 0x6f, + 0xb0, 0xee, 0x4f, 0xe5, 0x05, 0xf0, 0x52, 0x8d, 0xc6, 0x90, 0x67, 0x63, 0xe5, 0xd5, 0xdb, 0x4e, + 0xc7, 0xbd, 0xdb, 0xdf, 0xb6, 0x1e, 0xc4, 0x47, 0x96, 0x78, 0x5f, 0x61, 0x7c, 0x81, 0x1e, 0xae, + 0x23, 0xf4, 0x57, 0x2a, 0x52, 0xcc, 0xbc, 0xbd, 0xaa, 0xc8, 0xd3, 0xd5, 0xbc, 0xe5, 0x6d, 0x17, + 0xd9, 0x84, 0x04, 0xf1, 0x03, 0xcb, 0x0d, 0x37, 0xd4, 0x37, 0xf4, 0xf8, 0x5d, 0xc9, 0xb2, 0x3c, + 0x99, 0xc2, 0x50, 0x0f, 0xe1, 0x92, 0xd0, 0x09, 0xa8, 0x73, 0xa2, 0x08, 0x3e, 0x46, 0xbb, 0x29, + 0x30, 0x5e, 0x98, 0xab, 0x8b, 0x0d, 0xc0, 0x27, 0xa8, 0x4e, 0x0a, 0x5e, 0x32, 0x55, 0xdd, 0x8a, + 0x1b, 0x5b, 0xa4, 0x79, 0x3b, 0xbc, 0x9d, 0x2a, 0xfc, 0xbe, 0x49, 0xb8, 0xdb, 0x93, 0x08, 0x86, + 0x28, 0xb8, 0xe7, 0xe7, 0x7d, 0x3a, 0x61, 0xfc, 0xcb, 0x14, 0xd2, 0x0c, 0x0a, 0x60, 0x0a, 0x7b, + 0x68, 0x4f, 0x96, 0x94, 0x82, 0x94, 0x95, 0x93, 0xfd, 0x78, 0x0d, 0xb5, 0x43, 0x10, 0x82, 0x0b, + 0xb3, 0x20, 0xb1, 0x01, 0xc1, 0x1b, 0x84, 0xce, 0xb5, 0xd5, 0xa1, 0x20, 0x14, 0x30, 0x46, 0xee, + 0x8c, 0xa8, 0xb1, 0x6d, 0xa2, 0x3a, 0xe3, 0x67, 0x08, 0xe9, 0x55, 0x18, 0x99, 0xf6, 0x4c, 0xf2, + 0x81, 0x66, 0xaa, 0xbc, 0xc1, 0x87, 0x9b, 0x85, 0xef, 0xdc, 0x2e, 0x7c, 0xe7, 0xd7, 0xc2, 0x77, + 0xbe, 0x2f, 0xfd, 0xda, 0xed, 0xd2, 0xaf, 0xfd, 0x5c, 0xfa, 0xb5, 0x4f, 0xbd, 0x7f, 0x6e, 0xc3, + 0xd7, 0x28, 0x4f, 0x68, 0xf7, 0xef, 0x1b, 0xd3, 0xcb, 0x91, 0xd4, 0xab, 0xd7, 0xf1, 0xe2, 0x4f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x8b, 0x58, 0xed, 0x2d, 0x80, 0x03, 0x00, 0x00, } func (m *MsgTransfer) Marshal() (dAtA []byte, err error) { @@ -550,10 +551,10 @@ func (m *DenomTrace) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.Trace) > 0 { - i -= len(m.Trace) - copy(dAtA[i:], m.Trace) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.Trace))) + if len(m.Path) > 0 { + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintTransfer(dAtA, i, uint64(len(m.Path))) i-- dAtA[i] = 0xa } @@ -650,7 +651,7 @@ func (m *DenomTrace) Size() (n int) { } var l int _ = l - l = len(m.Trace) + l = len(m.Path) if l > 0 { n += 1 + l + sovTransfer(uint64(l)) } @@ -1225,7 +1226,7 @@ func (m *DenomTrace) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1253,7 +1254,7 @@ func (m *DenomTrace) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Trace = string(dAtA[iNdEx:postIndex]) + m.Path = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { From 1c00f9d6742354912fb83ade04f7c7b65a9f5889 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 22:24:27 +0200 Subject: [PATCH 35/41] docs and changelog --- CHANGELOG.md | 1 + x/ibc-transfer/spec/04_messages.md | 4 ++-- x/ibc-transfer/spec/05_events.md | 6 +----- x/ibc/spec/01_concepts.md | 6 +++--- x/ibc/spec/README.md | 2 ++ 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddd07a11a3dc..a2c82830f58d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -283,6 +283,7 @@ Buffers for state serialization instead of Amino. ### Improvements +* (x/ibc-transfer) [\#6871](https://github.com/cosmos/cosmos-sdk/pull/6871) Implement [ADR 001 - Coin Source Tracing](./../../../docs/architecture/adr-001-coin-source-tracing.md). * (types) [\#7027](https://github.com/cosmos/cosmos-sdk/pull/7027) `Coin(s)` and `DecCoin(s)` updates: * Bump denomination max length to 128 * Allow uppercase letters and numbers in denominations to support ADR 001 diff --git a/x/ibc-transfer/spec/04_messages.md b/x/ibc-transfer/spec/04_messages.md index 1f81a0001b29..54458cc1324e 100644 --- a/x/ibc-transfer/spec/04_messages.md +++ b/x/ibc-transfer/spec/04_messages.md @@ -4,7 +4,7 @@ order: 4 # Messages -### MsgTransfer +## MsgTransfer A fungible token cross chain transfer is achieved by using the `MsgTransfer`: @@ -29,6 +29,7 @@ This message is expected to fail if: - `Sender` is empty - `Receiver` is empty - `TimeoutHeight` and `TimeoutTimestamp` are both zero +- `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](./../../../docs/architecture/adr-001-coin-source-tracing.md). This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers @@ -37,4 +38,3 @@ by the counterparty Channel End connected to the Channel End with the identifier The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain. - diff --git a/x/ibc-transfer/spec/05_events.md b/x/ibc-transfer/spec/05_events.md index 15a694e5a217..626a98a4f1a8 100644 --- a/x/ibc-transfer/spec/05_events.md +++ b/x/ibc-transfer/spec/05_events.md @@ -21,6 +21,7 @@ order: 5 | fungible_token_packet | receiver | {receiver} | | fungible_token_packet | denom | {denom} | | fungible_token_packet | amount | {amount} | +| denomination_trace | trace_hash | {hex_hash} | ## OnAcknowledgePacket callback @@ -40,8 +41,3 @@ order: 5 | fungible_token_packet | refund_receiver | {receiver} | | fungible_token_packet | denom | {denom} | | fungible_token_packet | amount | {amount} | - - - - - diff --git a/x/ibc/spec/01_concepts.md b/x/ibc/spec/01_concepts.md index 3dffeb2be180..253a5dcb7d3f 100644 --- a/x/ibc/spec/01_concepts.md +++ b/x/ibc/spec/01_concepts.md @@ -7,7 +7,7 @@ order: 1 > NOTE: if you are not familiar with the IBC terminology and concepts, please read this [document](https://github.com/cosmos/ics/blob/master/ibc/1_IBC_TERMINOLOGY.md) as prerequisite reading. -### Connection Version Negotation +## Connection Version Negotation During the handshake procedure for connections a version string is agreed upon between the two parties. This occurs during the first 3 steps of the @@ -33,7 +33,7 @@ A valid connection version is considered to be in the following format: - the version tuple must be enclosed in parentheses - the feature set must be enclosed in brackets -- there should be no space between the comma separting the identifier and the +- there should be no space between the comma separating the identifier and the feature set - the version identifier must no contain any commas - each feature must not contain any commas @@ -46,7 +46,7 @@ with regards to version selection in `ConnOpenTry`. Each version in a set of versions should have a unique version identifier. ::: -### Channel Version Negotation +## Channel Version Negotation During the channel handshake procedure a version must be agreed upon between the two parties. The selection process is largely left to the callers and diff --git a/x/ibc/spec/README.md b/x/ibc/spec/README.md index 7e8350c99f51..9a85d85dbdb2 100644 --- a/x/ibc/spec/README.md +++ b/x/ibc/spec/README.md @@ -55,6 +55,8 @@ which call each ICS submodule's handlers (i.e `x/ibc/{XX-ICS}/handler.go`). The following ADR provide the design and architecture decision of IBC-related components. +* [ADR 001 - Coin Source Tracing](../../../docs/architecture/adr-001-coin-source-tracing.md): standard to hash the ICS20's fungible token +denomination trace path in order to support special characters and limit the maximum denomination length. * [ADR 17 - Historical Header Module](../../../docs/architecture/adr-017-historical-header-module.md): Introduces the ability to introspect past consensus states in order to verify their membership in the counterparty clients. * [ADR 19 - Protobuf State Encoding](../../../docs/architecture/adr-019-protobuf-state-encoding.md): Migration from Amino to Protobuf for state encoding. From 9429f9083fc0f1a44f3fe59f97b6e9ae89c79ab2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 22:32:17 +0200 Subject: [PATCH 36/41] sort traces --- CHANGELOG.md | 4 ++-- x/ibc-transfer/keeper/genesis_test.go | 2 +- x/ibc-transfer/keeper/keeper.go | 2 +- x/ibc-transfer/types/trace.go | 18 ++++++++++++++++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2c82830f58d..f3ff8b6076bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -283,10 +283,10 @@ Buffers for state serialization instead of Amino. ### Improvements -* (x/ibc-transfer) [\#6871](https://github.com/cosmos/cosmos-sdk/pull/6871) Implement [ADR 001 - Coin Source Tracing](./../../../docs/architecture/adr-001-coin-source-tracing.md). +* (x/ibc-transfer) [\#6871](https://github.com/cosmos/cosmos-sdk/pull/6871) Implement [ADR 001 - Coin Source Tracing](./docs/architecture/adr-001-coin-source-tracing.md). * (types) [\#7027](https://github.com/cosmos/cosmos-sdk/pull/7027) `Coin(s)` and `DecCoin(s)` updates: * Bump denomination max length to 128 - * Allow uppercase letters and numbers in denominations to support ADR 001 + * Allow uppercase letters and numbers in denominations to support [ADR 001](./docs/architecture/adr-001-coin-source-tracing.md) * Added `Validate` function that returns a descriptive error * (baseapp) [\#6186](https://github.com/cosmos/cosmos-sdk/issues/6186) Support emitting events during `AnteHandler` execution. * (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) Add parameter querying support for `x/auth`. diff --git a/x/ibc-transfer/keeper/genesis_test.go b/x/ibc-transfer/keeper/genesis_test.go index 19005cdd3bf5..3c1d192035aa 100644 --- a/x/ibc-transfer/keeper/genesis_test.go +++ b/x/ibc-transfer/keeper/genesis_test.go @@ -31,7 +31,7 @@ func (suite *KeeperTestSuite) TestGenesis() { genesis := suite.chainA.App.TransferKeeper.ExportGenesis(suite.chainA.GetContext()) suite.Require().Equal(types.PortID, genesis.PortId) - suite.Require().Equal(traces, genesis.DenomTraces) + suite.Require().Equal(traces.Sort(), genesis.DenomTraces) suite.Require().NotPanics(func() { suite.chainA.App.TransferKeeper.InitGenesis(suite.chainA.GetContext(), *genesis) diff --git a/x/ibc-transfer/keeper/keeper.go b/x/ibc-transfer/keeper/keeper.go index b4683838effc..d39160c19c40 100644 --- a/x/ibc-transfer/keeper/keeper.go +++ b/x/ibc-transfer/keeper/keeper.go @@ -145,7 +145,7 @@ func (k Keeper) GetAllDenomTraces(ctx sdk.Context) types.Traces { return false }) - return traces + return traces.Sort() } // IterateDenomTraces iterates over the denomination traces in the store diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 07b4b6f69c8c..4e5258c6dd09 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "errors" fmt "fmt" + "sort" "strings" "github.com/tendermint/tendermint/crypto/tmhash" @@ -118,6 +119,23 @@ func (t Traces) Validate() error { return nil } +var _ sort.Interface = Traces{} + +// Len implements sort.Interface for Traces +func (t Traces) Len() int { return len(t) } + +// Less implements sort.Interface for Traces +func (t Traces) Less(i, j int) bool { return t[i].GetFullDenomPath() < t[j].GetFullDenomPath() } + +// Swap implements sort.Interface for Traces +func (t Traces) Swap(i, j int) { t[i], t[j] = t[j], t[i] } + +// Sort is a helper function to sort the set of denomination traces in-place +func (t Traces) Sort() Traces { + sort.Sort(t) + return t +} + // ValidatePrefixedDenom checks that the denomination for an IBC fungible token packet denom is correctly prefixed. // The function will return no error if the given string follows one of the two formats: // From 1aedd3a5b33fd30bd7905262da78a9e2c98a94fc Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 22:43:24 +0200 Subject: [PATCH 37/41] final changes to ADR --- .../adr-001-coin-source-tracing.md | 54 ++++++++++--------- x/ibc-transfer/keeper/relay.go | 2 +- x/ibc-transfer/types/trace.go | 4 +- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/docs/architecture/adr-001-coin-source-tracing.md b/docs/architecture/adr-001-coin-source-tracing.md index 371c933d56f9..be3ff2386522 100644 --- a/docs/architecture/adr-001-coin-source-tracing.md +++ b/docs/architecture/adr-001-coin-source-tracing.md @@ -115,7 +115,7 @@ trace the token back to the originating chain, as specified on ICS20. The new proposed format will be the following: ```golang -ibcDenom = "ibc/" + hash(trace + "/" + base denom) +ibcDenom = "ibc/" + hash(trace path + "/" + base denom) ``` The hash function will be a SHA256 hash of the fields of the `DenomTrace`: @@ -136,15 +136,15 @@ The `IBCDenom` function constructs the `Coin` denomination used when creating th ```golang // Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula: // -// hash = sha256(trace + "/" + baseDenom) +// hash = sha256(tracePath + "/" + baseDenom) func (dt DenomTrace) Hash() tmbytes.HexBytes { - return tmhash.Sum(dt.Trace + "/" + dt.BaseDenom) + return tmhash.Sum(dt.Path + "/" + dt.BaseDenom) } -// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + baseDenom)}'. +// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(tracePath + baseDenom)}'. // If the trace is empty, it will return the base denomination. func (dt DenomTrace) IBCDenom() string { - if dt.Trace != "" { + if dt.Path != "" { return fmt.Sprintf("ibc/%s", dt.Hash()) } return dt.BaseDenom @@ -199,10 +199,9 @@ func (msg MsgTransfer) ValidateBasic() error { // ValidateIBCDenom validates that the given denomination is either: // // - A valid base denomination (eg: 'uatom') -// - A valid trace prefixed denomination (eg: '{portIDN}/{channelIDN}/.../{portID0}/{channelID0}/baseDenom') // - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-001-coin-source-tracing.md func ValidateIBCDenom(denom string) error { - denomSplit := strings.Split(denom, "/") + denomSplit := strings.SplitN(denom, "/", 2) switch { case strings.TrimSpace(denom) == "", @@ -212,13 +211,10 @@ func ValidateIBCDenom(denom string) error { case denomSplit[0] == denom && strings.TrimSpace(denom) != "": return sdk.ValidateDenom(denom) - - case len(denomSplit) > 2: - return validateTraceIdentifiers(denomSplit[:len(denomSplit)-1]) } if _, err := ParseHexHash(denomSplit[1]); err != nil { - return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "invalid denom trace hash %s: %s", denomSplit[1], err) + return Wrapf(err, "invalid denom trace hash %s", denomSplit[1]) } return nil @@ -234,34 +230,42 @@ The denomination trace info only needs to be updated when token is received: // SendTransfer // ... -prefixedDenom := token.Denom + fullDenomPath := token.Denom // deconstruct the token denomination into the denomination trace info // to determine if the sender is the source chain if strings.HasPrefix(token.Denom, "ibc/") { - hexHash := token.Denom[4:] - hash, err := types.ParseHexHash(hexHash) + fullDenomPath, err = k.DenomPathFromHash(ctx, token.Denom) if err != nil { return err } +} + +if types.SenderChainIsSource(sourcePort, sourceChannel, fullDenomPath) { +//... +``` + +```golang +// DenomPathFromHash returns the full denomination path prefix from an ibc denom with a hash +// component. +func (k Keeper) DenomPathFromHash(ctx sdk.Context, denom string) (string, error) { + hexHash := denom[4:] + hash, err := ParseHexHash(hexHash) + if err != nil { + return "", Wrap(ErrInvalidDenomForTransfer, err.Error()) + } denomTrace, found := k.GetDenomTrace(ctx, hash) if !found { - return sdkerrors.Wrap(types.ErrTraceNotFound, hexHash) + return "", Wrap(ErrTraceNotFound, hexHash) } - prefixedDenom = denomTrace.GetPrefix() + denomTrace.BaseDenom -} else if strings.Contains(token.Denom, "/") { - // in the case the user transfers a prefixed denomination, - // update the token denomination with the hashed trace info as that's the - // representation on the user balance - denomTrace := types.ParseDenomTrace(token.Denom) - token.Denom = denomTrace.IBCDenom() -} -if types.SenderChainIsSource(sourcePort, sourceChannel, prefixedDenom) { -//... + fullDenomPath := denomTrace.GetFullDenomPath() + return fullDenomPath, nil +} ``` + ```golang // OnRecvPacket // ... diff --git a/x/ibc-transfer/keeper/relay.go b/x/ibc-transfer/keeper/relay.go index 791cb8bf93e2..4a9388e5def2 100644 --- a/x/ibc-transfer/keeper/relay.go +++ b/x/ibc-transfer/keeper/relay.go @@ -267,7 +267,7 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d } // DenomPathFromHash returns the full denomination path prefix from an ibc denom with a hash -// compoenent. +// component. func (k Keeper) DenomPathFromHash(ctx sdk.Context, denom string) (string, error) { hexHash := denom[4:] hash, err := types.ParseHexHash(hexHash) diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 4e5258c6dd09..55ca36b51d67 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -41,7 +41,7 @@ func ParseDenomTrace(rawDenom string) DenomTrace { // Hash returns the hex bytes of the SHA256 hash of the DenomTrace fields using the following formula: // -// hash = sha256(trace + "/" + baseDenom) +// hash = sha256(tracePath + "/" + baseDenom) func (dt DenomTrace) Hash() tmbytes.HexBytes { return tmhash.Sum([]byte(dt.GetFullDenomPath())) } @@ -51,7 +51,7 @@ func (dt DenomTrace) GetPrefix() string { return dt.Path + "/" } -// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(trace + +// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(tracePath + // baseDenom)}'. If the trace is empty, it will return the base denomination. func (dt DenomTrace) IBCDenom() string { if dt.Path != "" { From cd19a79c03195e81d388dea63164e5a19e67787b Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 22:53:34 +0200 Subject: [PATCH 38/41] client support for full path denom prefixes --- types/coin_test.go | 2 ++ x/ibc-transfer/client/cli/tx.go | 5 +++++ x/ibc-transfer/types/trace_test.go | 3 +++ 3 files changed, 10 insertions(+) diff --git a/types/coin_test.go b/types/coin_test.go index 019887813a8b..f16bd682e5ef 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -633,6 +633,8 @@ func TestParse(t *testing.T) { {"1.2btc", false, nil}, // amount must be integer {"5foo:bar", false, nil}, // invalid separator {"10atom10", true, Coins{{"atom10", NewInt(10)}}}, + {"200transfer/channelToA/uatom", true, Coins{{"transfer/channelToA/uatom", NewInt(200)}}}, + {"50ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", true, Coins{{"ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", NewInt(50)}}}, } for tcIndex, tc := range cases { diff --git a/x/ibc-transfer/client/cli/tx.go b/x/ibc-transfer/client/cli/tx.go index 47b031703ff8..01b17527c852 100644 --- a/x/ibc-transfer/client/cli/tx.go +++ b/x/ibc-transfer/client/cli/tx.go @@ -49,6 +49,11 @@ to the counterparty channel. Any timeout set to 0 is disabled.`), return err } + if !strings.HasPrefix(coin.Denom, "ibc/") { + denomTrace := types.ParseDenomTrace(coin.Denom) + coin.Denom = denomTrace.IBCDenom() + } + timeoutHeight, err := cmd.Flags().GetUint64(flagPacketTimeoutHeight) if err != nil { return err diff --git a/x/ibc-transfer/types/trace_test.go b/x/ibc-transfer/types/trace_test.go index 837219acd9ee..f0868d5680e5 100644 --- a/x/ibc-transfer/types/trace_test.go +++ b/x/ibc-transfer/types/trace_test.go @@ -15,6 +15,9 @@ func TestParseDenomTrace(t *testing.T) { {"empty denom", "", DenomTrace{}}, {"base denom", "uatom", DenomTrace{BaseDenom: "uatom"}}, {"trace info", "transfer/channelToA/uatom", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA"}}, + {"incomplete path", "transfer/uatom", DenomTrace{BaseDenom: "uatom", Path: "transfer"}}, + {"invalid path (1)", "transfer//uatom", DenomTrace{BaseDenom: "uatom", Path: "transfer/"}}, + {"invalid path (2)", "transfer/channelToA/uatom/", DenomTrace{BaseDenom: "", Path: "transfer/channelToA/uatom"}}, } for _, tc := range testCases { From ceab72247a17705c005a9941822bfdb8c5801881 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 22:55:26 +0200 Subject: [PATCH 39/41] address @AdityaSripal comments --- x/ibc-transfer/types/trace.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/ibc-transfer/types/trace.go b/x/ibc-transfer/types/trace.go index 55ca36b51d67..dffe00501c87 100644 --- a/x/ibc-transfer/types/trace.go +++ b/x/ibc-transfer/types/trace.go @@ -51,8 +51,8 @@ func (dt DenomTrace) GetPrefix() string { return dt.Path + "/" } -// IBCDenom a coin denomination for an ICS20 fungible token in the format 'ibc/{hash(tracePath + -// baseDenom)}'. If the trace is empty, it will return the base denomination. +// IBCDenom a coin denomination for an ICS20 fungible token in the format +// 'ibc/{hash(tracePath + baseDenom)}'. If the trace is empty, it will return the base denomination. func (dt DenomTrace) IBCDenom() string { if dt.Path != "" { return fmt.Sprintf("ibc/%s", dt.Hash()) @@ -60,8 +60,8 @@ func (dt DenomTrace) IBCDenom() string { return dt.BaseDenom } -// GetFullDenomPath returns the full denomination according to the ICS20 specification: trace + "/" -// + baseDenom +// GetFullDenomPath returns the full denomination according to the ICS20 specification: +// tracePath + "/" + baseDenom func (dt DenomTrace) GetFullDenomPath() string { return dt.GetPrefix() + dt.BaseDenom } From 7723ca285be3f2a8011e35353baa10b512d4dca2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 23:00:33 +0200 Subject: [PATCH 40/41] address TODO --- x/ibc-transfer/keeper/grpc_query_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x/ibc-transfer/keeper/grpc_query_test.go b/x/ibc-transfer/keeper/grpc_query_test.go index e01e36529bdf..c16ecc379704 100644 --- a/x/ibc-transfer/keeper/grpc_query_test.go +++ b/x/ibc-transfer/keeper/grpc_query_test.go @@ -126,8 +126,7 @@ func (suite *KeeperTestSuite) TestQueryConnections() { if tc.expPass { suite.Require().NoError(err) suite.Require().NotNil(res) - // FIXME: response is non-deterministic so we can't use Equal! - suite.Require().ElementsMatch(expTraces, res.DenomTraces) + suite.Require().Equal(expTraces.Sort(), res.DenomTraces) } else { suite.Require().Error(err) } From eb7e98801b005c70c7ab61b70bd46b7f6d05000c Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Fri, 14 Aug 2020 23:37:43 +0200 Subject: [PATCH 41/41] increase test timeouts --- .github/workflows/test.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c2c7eeaf76d9..60ee78e69845 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,7 +44,7 @@ jobs: test-coverage-run-1: runs-on: ubuntu-latest needs: split-test-files - timeout-minutes: 10 + timeout-minutes: 15 steps: - uses: actions/checkout@v2 - uses: technote-space/get-diff-action@v3 @@ -60,7 +60,7 @@ jobs: if: "env.GIT_DIFF != ''" - name: test & coverage report creation run: | - cat xaa.txt | xargs go test -mod=readonly -timeout 8m -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' + cat xaa.txt | xargs go test -mod=readonly -timeout 15m -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' if: "env.GIT_DIFF != ''" - name: filter out DONTCOVER run: | @@ -81,7 +81,7 @@ jobs: test-coverage-run-2: runs-on: ubuntu-latest needs: split-test-files - timeout-minutes: 10 + timeout-minutes: 15 steps: - uses: actions/checkout@v2 - uses: technote-space/get-diff-action@v3 @@ -97,7 +97,7 @@ jobs: if: "env.GIT_DIFF != ''" - name: test & coverage report creation run: | - cat xab.txt | xargs go test -mod=readonly -timeout 6m -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' + cat xab.txt | xargs go test -mod=readonly -timeout 15m -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' if: "env.GIT_DIFF != ''" - name: filter out DONTCOVER run: | @@ -118,7 +118,7 @@ jobs: test-coverage-run-3: runs-on: ubuntu-latest needs: split-test-files - timeout-minutes: 10 + timeout-minutes: 15 steps: - uses: actions/checkout@v2 - uses: technote-space/get-diff-action@v3 @@ -134,7 +134,7 @@ jobs: if: "env.GIT_DIFF != ''" - name: test & coverage report creation run: | - cat xac.txt | xargs go test -mod=readonly -timeout 6m -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' + cat xac.txt | xargs go test -mod=readonly -timeout 15m -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' if: "env.GIT_DIFF != ''" - name: filter out DONTCOVER run: | @@ -155,7 +155,7 @@ jobs: test-coverage-run-4: runs-on: ubuntu-latest needs: split-test-files - timeout-minutes: 10 + timeout-minutes: 15 steps: - uses: actions/checkout@v2 - uses: technote-space/get-diff-action@v3 @@ -171,7 +171,7 @@ jobs: if: "env.GIT_DIFF != ''" - name: test & coverage report creation run: | - cat xad.txt | xargs go test -mod=readonly -timeout 6m -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' + cat xad.txt | xargs go test -mod=readonly -timeout 15m -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' if: "env.GIT_DIFF != ''" - name: filter out DONTCOVER run: |