diff --git a/common/tools/protolator/api.go b/common/tools/protolator/api.go new file mode 100644 index 00000000000..2b2c382f421 --- /dev/null +++ b/common/tools/protolator/api.go @@ -0,0 +1,63 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protolator + +import ( + "github.com/golang/protobuf/proto" +) + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// This set of interfaces and methods is designed to allow protos to have Go methods attached +// to them, so that they may be automatically marshaled to human readable JSON (where the +// opaque byte fields are represented as their expanded proto contents) and back once again +// to standard proto messages. +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// StaticallyOpaqueFieldProto should be implemented by protos which have bytes fields which +// are the marshaled value of a fixed type +type StaticallyOpaqueFieldProto interface { + // StaticallyOpaqueFields returns the field names which contain opaque data + StaticallyOpaqueFields() []string + + // StaticallyOpaqueFieldProto returns a newly allocated proto message of the correct + // type for the field name. + StaticallyOpaqueFieldProto(name string) (proto.Message, error) +} + +// StaticallyOpaqueMapFieldProto should be implemented by protos which have maps to bytes fields +// which are the marshaled value of a fixed type +type StaticallyOpaqueMapFieldProto interface { + // StaticallyOpaqueFields returns the field names which contain opaque data + StaticallyOpaqueMapFields() []string + + // StaticallyOpaqueFieldProto returns a newly allocated proto message of the correct + // type for the field name. + StaticallyOpaqueMapFieldProto(name string, key string) (proto.Message, error) +} + +// StaticallyOpaqueSliceFieldProto should be implemented by protos which have maps to bytes fields +// which are the marshaled value of a fixed type +type StaticallyOpaqueSliceFieldProto interface { + // StaticallyOpaqueFields returns the field names which contain opaque data + StaticallyOpaqueSliceFields() []string + + // StaticallyOpaqueFieldProto returns a newly allocated proto message of the correct + // type for the field name. + StaticallyOpaqueSliceFieldProto(name string, index int) (proto.Message, error) +} diff --git a/common/tools/protolator/json.go b/common/tools/protolator/json.go index 8d05b6e546b..78cd3a4383c 100644 --- a/common/tools/protolator/json.go +++ b/common/tools/protolator/json.go @@ -57,6 +57,7 @@ type protoField interface { var ( protoMsgType = reflect.TypeOf((*proto.Message)(nil)).Elem() mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{}) + bytesType = reflect.TypeOf([]byte{}) ) type baseField struct { @@ -201,6 +202,15 @@ func (sf *sliceField) PopulateTo() (interface{}, error) { return result, nil } +func stringInSlice(target string, slice []string) bool { + for _, name := range slice { + if name == target { + return true + } + } + return false +} + // protoToJSON is a simple shortcut wrapper around the proto JSON marshaler func protoToJSON(msg proto.Message) ([]byte, error) { var b bytes.Buffer @@ -241,6 +251,9 @@ func jsonToMap(marshaled []byte) (map[string]interface{}, error) { // Factories listed lower, may depend on factories listed higher being // evaluated first. var fieldFactories = []protoFieldFactory{ + staticallyOpaqueSliceFieldFactory{}, + staticallyOpaqueMapFieldFactory{}, + staticallyOpaqueFieldFactory{}, nestedSliceFieldFactory{}, nestedMapFieldFactory{}, nestedFieldFactory{}, diff --git a/common/tools/protolator/statically_opaque.go b/common/tools/protolator/statically_opaque.go new file mode 100644 index 00000000000..480926b81b8 --- /dev/null +++ b/common/tools/protolator/statically_opaque.go @@ -0,0 +1,152 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protolator + +import ( + "reflect" + + "github.com/golang/protobuf/proto" +) + +func opaqueFrom(opaqueType func() (proto.Message, error), value interface{}, destType reflect.Type) (reflect.Value, error) { + tree := value.(map[string]interface{}) // Safe, already checked + nMsg, err := opaqueType() + if err != nil { + return reflect.Value{}, err + } + if err := recursivelyPopulateMessageFromTree(tree, nMsg); err != nil { + return reflect.Value{}, err + } + mMsg, err := proto.Marshal(nMsg) + if err != nil { + return reflect.Value{}, err + } + return reflect.ValueOf(mMsg), nil +} + +func opaqueTo(opaqueType func() (proto.Message, error), value reflect.Value) (interface{}, error) { + nMsg, err := opaqueType() + if err != nil { + return nil, err + } + mMsg := value.Interface().([]byte) // Safe, already checked + if err = proto.Unmarshal(mMsg, nMsg); err != nil { + return nil, err + } + return recursivelyCreateTreeFromMessage(nMsg) +} + +type staticallyOpaqueFieldFactory struct{} + +func (soff staticallyOpaqueFieldFactory) Handles(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) bool { + opaqueProto, ok := msg.(StaticallyOpaqueFieldProto) + if !ok { + return false + } + + return stringInSlice(fieldName, opaqueProto.StaticallyOpaqueFields()) +} + +func (soff staticallyOpaqueFieldFactory) NewProtoField(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) (protoField, error) { + opaqueProto := msg.(StaticallyOpaqueFieldProto) // Type checked in Handles + + return &plainField{ + baseField: baseField{ + msg: msg, + name: fieldName, + fType: mapStringInterfaceType, + vType: bytesType, + value: fieldValue, + }, + populateFrom: func(v interface{}, dT reflect.Type) (reflect.Value, error) { + return opaqueFrom(func() (proto.Message, error) { return opaqueProto.StaticallyOpaqueFieldProto(fieldName) }, v, dT) + }, + populateTo: func(v reflect.Value) (interface{}, error) { + return opaqueTo(func() (proto.Message, error) { return opaqueProto.StaticallyOpaqueFieldProto(fieldName) }, v) + }, + }, nil +} + +type staticallyOpaqueMapFieldFactory struct{} + +func (soff staticallyOpaqueMapFieldFactory) Handles(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) bool { + opaqueProto, ok := msg.(StaticallyOpaqueMapFieldProto) + if !ok { + return false + } + + return stringInSlice(fieldName, opaqueProto.StaticallyOpaqueMapFields()) +} + +func (soff staticallyOpaqueMapFieldFactory) NewProtoField(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) (protoField, error) { + opaqueProto := msg.(StaticallyOpaqueMapFieldProto) // Type checked in Handles + + return &mapField{ + baseField: baseField{ + msg: msg, + name: fieldName, + fType: mapStringInterfaceType, + vType: fieldType, + value: fieldValue, + }, + populateFrom: func(key string, v interface{}, dT reflect.Type) (reflect.Value, error) { + return opaqueFrom(func() (proto.Message, error) { + return opaqueProto.StaticallyOpaqueMapFieldProto(fieldName, key) + }, v, dT) + }, + populateTo: func(key string, v reflect.Value) (interface{}, error) { + return opaqueTo(func() (proto.Message, error) { + return opaqueProto.StaticallyOpaqueMapFieldProto(fieldName, key) + }, v) + }, + }, nil +} + +type staticallyOpaqueSliceFieldFactory struct{} + +func (soff staticallyOpaqueSliceFieldFactory) Handles(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) bool { + opaqueProto, ok := msg.(StaticallyOpaqueSliceFieldProto) + if !ok { + return false + } + + return stringInSlice(fieldName, opaqueProto.StaticallyOpaqueSliceFields()) +} + +func (soff staticallyOpaqueSliceFieldFactory) NewProtoField(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) (protoField, error) { + opaqueProto := msg.(StaticallyOpaqueSliceFieldProto) // Type checked in Handles + + return &sliceField{ + baseField: baseField{ + msg: msg, + name: fieldName, + fType: mapStringInterfaceType, + vType: fieldType, + value: fieldValue, + }, + populateFrom: func(index int, v interface{}, dT reflect.Type) (reflect.Value, error) { + return opaqueFrom(func() (proto.Message, error) { + return opaqueProto.StaticallyOpaqueSliceFieldProto(fieldName, index) + }, v, dT) + }, + populateTo: func(index int, v reflect.Value) (interface{}, error) { + return opaqueTo(func() (proto.Message, error) { + return opaqueProto.StaticallyOpaqueSliceFieldProto(fieldName, index) + }, v) + }, + }, nil +} diff --git a/common/tools/protolator/statically_opaque_test.go b/common/tools/protolator/statically_opaque_test.go new file mode 100644 index 00000000000..5ab33d247ee --- /dev/null +++ b/common/tools/protolator/statically_opaque_test.go @@ -0,0 +1,135 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protolator + +import ( + "bytes" + "testing" + + "github.com/hyperledger/fabric/common/tools/protolator/testprotos" + "github.com/hyperledger/fabric/protos/utils" + + "github.com/golang/protobuf/proto" + "github.com/stretchr/testify/assert" +) + +func extractSimpleMsgPlainField(source []byte) string { + result := &testprotos.SimpleMsg{} + err := proto.Unmarshal(source, result) + if err != nil { + panic(err) + } + return result.PlainField +} + +func TestPlainStaticallyOpaqueMsg(t *testing.T) { + fromPrefix := "from" + toPrefix := "to" + tppff := &testProtoPlainFieldFactory{ + fromPrefix: fromPrefix, + toPrefix: toPrefix, + } + + fieldFactories = []protoFieldFactory{tppff} + + pfValue := "foo" + startMsg := &testprotos.StaticallyOpaqueMsg{ + PlainOpaqueField: utils.MarshalOrPanic(&testprotos.SimpleMsg{ + PlainField: pfValue, + }), + } + + var buffer bytes.Buffer + assert.NoError(t, DeepMarshalJSON(&buffer, startMsg)) + newMsg := &testprotos.StaticallyOpaqueMsg{} + assert.NoError(t, DeepUnmarshalJSON(bytes.NewReader(buffer.Bytes()), newMsg)) + assert.NotEqual(t, fromPrefix+toPrefix+extractSimpleMsgPlainField(startMsg.PlainOpaqueField), extractSimpleMsgPlainField(newMsg.PlainOpaqueField)) + + fieldFactories = []protoFieldFactory{tppff, staticallyOpaqueFieldFactory{}} + + buffer.Reset() + assert.NoError(t, DeepMarshalJSON(&buffer, startMsg)) + assert.NoError(t, DeepUnmarshalJSON(bytes.NewReader(buffer.Bytes()), newMsg)) + assert.Equal(t, fromPrefix+toPrefix+extractSimpleMsgPlainField(startMsg.PlainOpaqueField), extractSimpleMsgPlainField(newMsg.PlainOpaqueField)) +} + +func TestMapStaticallyOpaqueMsg(t *testing.T) { + fromPrefix := "from" + toPrefix := "to" + tppff := &testProtoPlainFieldFactory{ + fromPrefix: fromPrefix, + toPrefix: toPrefix, + } + + fieldFactories = []protoFieldFactory{tppff} + + pfValue := "foo" + mapKey := "bar" + startMsg := &testprotos.StaticallyOpaqueMsg{ + MapOpaqueField: map[string][]byte{ + mapKey: utils.MarshalOrPanic(&testprotos.SimpleMsg{ + PlainField: pfValue, + }), + }, + } + + var buffer bytes.Buffer + assert.NoError(t, DeepMarshalJSON(&buffer, startMsg)) + newMsg := &testprotos.StaticallyOpaqueMsg{} + assert.NoError(t, DeepUnmarshalJSON(bytes.NewReader(buffer.Bytes()), newMsg)) + assert.NotEqual(t, fromPrefix+toPrefix+extractSimpleMsgPlainField(startMsg.MapOpaqueField[mapKey]), extractSimpleMsgPlainField(newMsg.MapOpaqueField[mapKey])) + + fieldFactories = []protoFieldFactory{tppff, staticallyOpaqueMapFieldFactory{}} + + buffer.Reset() + assert.NoError(t, DeepMarshalJSON(&buffer, startMsg)) + assert.NoError(t, DeepUnmarshalJSON(bytes.NewReader(buffer.Bytes()), newMsg)) + assert.Equal(t, fromPrefix+toPrefix+extractSimpleMsgPlainField(startMsg.MapOpaqueField[mapKey]), extractSimpleMsgPlainField(newMsg.MapOpaqueField[mapKey])) +} + +func TestSliceStaticallyOpaqueMsg(t *testing.T) { + fromPrefix := "from" + toPrefix := "to" + tppff := &testProtoPlainFieldFactory{ + fromPrefix: fromPrefix, + toPrefix: toPrefix, + } + + fieldFactories = []protoFieldFactory{tppff} + + pfValue := "foo" + startMsg := &testprotos.StaticallyOpaqueMsg{ + SliceOpaqueField: [][]byte{ + utils.MarshalOrPanic(&testprotos.SimpleMsg{ + PlainField: pfValue, + }), + }, + } + + var buffer bytes.Buffer + assert.NoError(t, DeepMarshalJSON(&buffer, startMsg)) + newMsg := &testprotos.StaticallyOpaqueMsg{} + assert.NoError(t, DeepUnmarshalJSON(bytes.NewReader(buffer.Bytes()), newMsg)) + assert.NotEqual(t, fromPrefix+toPrefix+extractSimpleMsgPlainField(startMsg.SliceOpaqueField[0]), extractSimpleMsgPlainField(newMsg.SliceOpaqueField[0])) + + fieldFactories = []protoFieldFactory{tppff, staticallyOpaqueSliceFieldFactory{}} + + buffer.Reset() + assert.NoError(t, DeepMarshalJSON(&buffer, startMsg)) + assert.NoError(t, DeepUnmarshalJSON(bytes.NewReader(buffer.Bytes()), newMsg)) + assert.Equal(t, fromPrefix+toPrefix+extractSimpleMsgPlainField(startMsg.SliceOpaqueField[0]), extractSimpleMsgPlainField(newMsg.SliceOpaqueField[0])) +} diff --git a/common/tools/protolator/testprotos/sample.go b/common/tools/protolator/testprotos/sample.go new file mode 100644 index 00000000000..771139e3da1 --- /dev/null +++ b/common/tools/protolator/testprotos/sample.go @@ -0,0 +1,59 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testprotos + +import ( + "fmt" + + "github.com/golang/protobuf/proto" +) + +func (som *StaticallyOpaqueMsg) StaticallyOpaqueFields() []string { + return []string{"plain_opaque_field"} +} + +func (som *StaticallyOpaqueMsg) StaticallyOpaqueFieldProto(name string) (proto.Message, error) { + if name != som.StaticallyOpaqueFields()[0] { + return nil, fmt.Errorf("not a statically opaque field: %s", name) + } + + return &SimpleMsg{}, nil +} + +func (som *StaticallyOpaqueMsg) StaticallyOpaqueMapFields() []string { + return []string{"map_opaque_field"} +} + +func (som *StaticallyOpaqueMsg) StaticallyOpaqueMapFieldProto(name string, key string) (proto.Message, error) { + if name != som.StaticallyOpaqueMapFields()[0] { + return nil, fmt.Errorf("not a statically opaque field: %s", name) + } + + return &SimpleMsg{}, nil +} + +func (som *StaticallyOpaqueMsg) StaticallyOpaqueSliceFields() []string { + return []string{"slice_opaque_field"} +} + +func (som *StaticallyOpaqueMsg) StaticallyOpaqueSliceFieldProto(name string, index int) (proto.Message, error) { + if name != som.StaticallyOpaqueSliceFields()[0] { + return nil, fmt.Errorf("not a statically opaque field: %s", name) + } + + return &SimpleMsg{}, nil +} diff --git a/common/tools/protolator/testprotos/sample.pb.go b/common/tools/protolator/testprotos/sample.pb.go index b4eb9da3993..51259a52276 100644 --- a/common/tools/protolator/testprotos/sample.pb.go +++ b/common/tools/protolator/testprotos/sample.pb.go @@ -11,6 +11,7 @@ It is generated from these files: It has these top-level messages: SimpleMsg NestedMsg + StaticallyOpaqueMsg */ package testprotos @@ -82,34 +83,59 @@ func (m *NestedMsg) GetSliceNestedField() []*SimpleMsg { return nil } +// StaticallyOpaqueMsg is designed to test the statically opaque message component +type StaticallyOpaqueMsg struct { + PlainOpaqueField []byte `protobuf:"bytes,1,opt,name=plain_opaque_field,json=plainOpaqueField,proto3" json:"plain_opaque_field,omitempty"` + MapOpaqueField map[string][]byte `protobuf:"bytes,2,rep,name=map_opaque_field,json=mapOpaqueField" json:"map_opaque_field,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value,proto3"` + SliceOpaqueField [][]byte `protobuf:"bytes,3,rep,name=slice_opaque_field,json=sliceOpaqueField,proto3" json:"slice_opaque_field,omitempty"` +} + +func (m *StaticallyOpaqueMsg) Reset() { *m = StaticallyOpaqueMsg{} } +func (m *StaticallyOpaqueMsg) String() string { return proto.CompactTextString(m) } +func (*StaticallyOpaqueMsg) ProtoMessage() {} +func (*StaticallyOpaqueMsg) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *StaticallyOpaqueMsg) GetMapOpaqueField() map[string][]byte { + if m != nil { + return m.MapOpaqueField + } + return nil +} + func init() { proto.RegisterType((*SimpleMsg)(nil), "testprotos.SimpleMsg") proto.RegisterType((*NestedMsg)(nil), "testprotos.NestedMsg") + proto.RegisterType((*StaticallyOpaqueMsg)(nil), "testprotos.StaticallyOpaqueMsg") } func init() { proto.RegisterFile("sample.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 327 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x90, 0x41, 0x4b, 0xfb, 0x30, - 0x18, 0xc6, 0x69, 0xcb, 0xff, 0x8f, 0x7d, 0xa7, 0x32, 0xaa, 0xc2, 0xd8, 0xc5, 0x31, 0x2f, 0x13, - 0xa1, 0x81, 0x79, 0x11, 0xbd, 0x8c, 0x89, 0xde, 0xe6, 0x61, 0xbb, 0x88, 0x17, 0xc9, 0xba, 0x6c, - 0x0b, 0x26, 0x4d, 0x48, 0x32, 0x61, 0xdf, 0xcf, 0xa3, 0x1f, 0x4a, 0xf2, 0xa6, 0x6c, 0x2d, 0x6c, - 0xa7, 0x26, 0x4f, 0xfa, 0xfe, 0x9e, 0xe7, 0x79, 0xe1, 0xd4, 0x52, 0xa9, 0x05, 0xcb, 0xb5, 0x51, - 0x4e, 0x65, 0xe0, 0x98, 0x75, 0x78, 0xb4, 0xfd, 0xdf, 0x08, 0xd2, 0x19, 0xf7, 0x8f, 0x13, 0xbb, - 0xca, 0xae, 0xa1, 0xa5, 0x05, 0xe5, 0xe5, 0xe7, 0x92, 0x33, 0xb1, 0xe8, 0x44, 0xbd, 0x68, 0x90, - 0x4e, 0x01, 0xa5, 0x57, 0xaf, 0x64, 0x23, 0x48, 0x25, 0xd5, 0xd5, 0x73, 0xdc, 0x4b, 0x06, 0xad, - 0xe1, 0x4d, 0xbe, 0xc7, 0xe5, 0x3b, 0x54, 0x3e, 0xa1, 0x1a, 0x47, 0x5e, 0x4a, 0x67, 0xb6, 0xd3, - 0x13, 0x59, 0x5d, 0xbd, 0x85, 0x15, 0xbc, 0x60, 0x15, 0x23, 0xe9, 0x25, 0xde, 0x02, 0x25, 0xfc, - 0xa1, 0xfb, 0x04, 0x67, 0x8d, 0xd9, 0xac, 0x0d, 0xc9, 0x17, 0xdb, 0x56, 0x61, 0xfc, 0x31, 0xbb, - 0x84, 0x7f, 0xdf, 0x54, 0x6c, 0x58, 0x27, 0x46, 0x2d, 0x5c, 0x1e, 0xe3, 0x87, 0xa8, 0xff, 0x13, - 0x43, 0xfa, 0xc6, 0xac, 0x63, 0x0b, 0x5f, 0xe7, 0x19, 0xb2, 0x50, 0xa7, 0x44, 0xa9, 0xd6, 0xaa, - 0x35, 0xbc, 0x3a, 0x18, 0x7b, 0xda, 0xc6, 0x81, 0x80, 0x08, 0x81, 0x67, 0xd0, 0xf6, 0x95, 0x1b, - 0x88, 0xd0, 0xfc, 0xb6, 0x8e, 0xd8, 0xb9, 0xfa, 0xe6, 0xb5, 0xf9, 0xd0, 0xff, 0x5c, 0x36, 0x44, - 0x9f, 0x2c, 0x6c, 0xa1, 0x81, 0x4d, 0x10, 0x7b, 0x2c, 0x19, 0x0e, 0xd4, 0x20, 0xdd, 0x77, 0xb8, - 0x38, 0xe0, 0x75, 0x60, 0x5f, 0x77, 0xf5, 0x7d, 0x1d, 0x35, 0xd8, 0xaf, 0x71, 0x3c, 0xfe, 0x18, - 0xad, 0xb8, 0x5b, 0x6f, 0xe6, 0x79, 0xa1, 0x24, 0x59, 0x6f, 0x35, 0x33, 0x82, 0x2d, 0x56, 0xcc, - 0x90, 0x25, 0x9d, 0x1b, 0x5e, 0x90, 0x42, 0x49, 0xa9, 0x4a, 0xe2, 0x94, 0x12, 0x96, 0x20, 0x49, - 0x50, 0xa7, 0x0c, 0xd9, 0x83, 0xe7, 0xff, 0xf1, 0x7b, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x3a, - 0x1e, 0xfa, 0x9e, 0x7c, 0x02, 0x00, 0x00, + // 404 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x92, 0xc1, 0x4a, 0xc3, 0x40, + 0x10, 0x86, 0x49, 0x82, 0x62, 0xa6, 0x51, 0x4a, 0xaa, 0x50, 0x7a, 0xb1, 0xd4, 0x4b, 0xc5, 0x92, + 0x40, 0x7b, 0x11, 0xbd, 0xd4, 0x8a, 0xde, 0xaa, 0xd0, 0x5e, 0x44, 0x10, 0xd9, 0xa6, 0xdb, 0x36, + 0xb8, 0xc9, 0xc6, 0x64, 0x2b, 0xe4, 0x39, 0x7c, 0x25, 0x8f, 0x3e, 0x94, 0xec, 0x6c, 0xda, 0x6e, + 0xb4, 0xc5, 0x53, 0xb2, 0xb3, 0x33, 0xff, 0x3f, 0xff, 0xc7, 0x82, 0x93, 0x91, 0x28, 0x61, 0xd4, + 0x4b, 0x52, 0x2e, 0xb8, 0x0b, 0x82, 0x66, 0x02, 0x7f, 0xb3, 0xd6, 0xb7, 0x01, 0xf6, 0x38, 0x94, + 0x97, 0xc3, 0x6c, 0xee, 0x9e, 0x42, 0x25, 0x61, 0x24, 0x8c, 0x5f, 0x67, 0x21, 0x65, 0xd3, 0xba, + 0xd1, 0x34, 0xda, 0xf6, 0x08, 0xb0, 0x74, 0x2f, 0x2b, 0x6e, 0x1f, 0xec, 0x88, 0x24, 0xc5, 0xb5, + 0xd9, 0xb4, 0xda, 0x95, 0xee, 0x99, 0xb7, 0x91, 0xf3, 0xd6, 0x52, 0xde, 0x90, 0x24, 0x38, 0x72, + 0x17, 0x8b, 0x34, 0x1f, 0x1d, 0x44, 0xc5, 0x51, 0x5a, 0x64, 0x2c, 0x0c, 0x68, 0xa1, 0x61, 0x35, + 0x2d, 0x69, 0x81, 0x25, 0x6c, 0x68, 0x5c, 0xc3, 0x61, 0x69, 0xd6, 0xad, 0x82, 0xf5, 0x46, 0xf3, + 0x62, 0x19, 0xf9, 0xeb, 0x1e, 0xc3, 0xde, 0x07, 0x61, 0x4b, 0x5a, 0x37, 0xb1, 0xa6, 0x0e, 0x57, + 0xe6, 0xa5, 0xd1, 0xfa, 0x32, 0xc1, 0x7e, 0xa0, 0x99, 0xa0, 0x53, 0x19, 0xe7, 0x16, 0x5c, 0x15, + 0x27, 0xc6, 0x92, 0x96, 0xaa, 0xd2, 0x3d, 0xd9, 0xba, 0xf6, 0xa8, 0x8a, 0x03, 0x4a, 0x42, 0x2d, + 0x3c, 0x86, 0xaa, 0x8c, 0x5c, 0x92, 0x50, 0xc9, 0xcf, 0x75, 0x89, 0xb5, 0xab, 0x4c, 0xae, 0xcd, + 0xab, 0xfc, 0x47, 0x51, 0xa9, 0x28, 0x37, 0x53, 0x14, 0x4a, 0xb2, 0x16, 0xca, 0xee, 0xda, 0x0c, + 0x07, 0x34, 0x91, 0xc6, 0x13, 0xd4, 0xb6, 0x78, 0x6d, 0xe1, 0x75, 0xa1, 0xf3, 0xda, 0x69, 0xa0, + 0x61, 0xfc, 0x34, 0xa1, 0x36, 0x16, 0x44, 0x84, 0x01, 0x61, 0x2c, 0x7f, 0x4c, 0xc8, 0xfb, 0x12, + 0xdf, 0x47, 0x67, 0x05, 0x94, 0x63, 0x49, 0x03, 0xea, 0x14, 0xe4, 0x54, 0xaf, 0x0a, 0xf9, 0xa2, + 0xc8, 0x95, 0x7a, 0x15, 0xb9, 0x5e, 0x69, 0x83, 0xbf, 0x46, 0x92, 0xa1, 0xa6, 0xb4, 0x61, 0xa8, + 0xcb, 0x77, 0x56, 0x0c, 0x4b, 0x06, 0x92, 0xa1, 0x53, 0xc0, 0xd2, 0xba, 0x1b, 0x37, 0x08, 0xeb, + 0xb7, 0xe8, 0x7f, 0x8f, 0xcb, 0xd1, 0xa8, 0x0c, 0x06, 0xcf, 0xfd, 0x79, 0x28, 0x16, 0xcb, 0x89, + 0x17, 0xf0, 0xc8, 0x5f, 0xe4, 0x09, 0x4d, 0x19, 0x9d, 0xce, 0x69, 0xea, 0xcf, 0xc8, 0x24, 0x0d, + 0x03, 0x3f, 0xe0, 0x51, 0xc4, 0x63, 0x5f, 0x70, 0xce, 0x32, 0x1f, 0xd3, 0x31, 0x22, 0x78, 0xea, + 0x6f, 0xc2, 0x4e, 0xf6, 0xf1, 0xdb, 0xfb, 0x09, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x8e, 0x27, 0xdf, + 0x92, 0x03, 0x00, 0x00, } diff --git a/common/tools/protolator/testprotos/sample.proto b/common/tools/protolator/testprotos/sample.proto index 86adef30587..f711cda9456 100644 --- a/common/tools/protolator/testprotos/sample.proto +++ b/common/tools/protolator/testprotos/sample.proto @@ -34,3 +34,10 @@ message NestedMsg { map map_nested_field = 2; repeated SimpleMsg slice_nested_field = 3; } + +// StaticallyOpaqueMsg is designed to test the statically opaque message component +message StaticallyOpaqueMsg { + bytes plain_opaque_field = 1; + map map_opaque_field = 2; + repeated bytes slice_opaque_field = 3; +}