diff --git a/pkg/codec/byte_string_modifier.go b/pkg/codec/byte_string_modifier.go index b6b6f6524..64befec39 100644 --- a/pkg/codec/byte_string_modifier.go +++ b/pkg/codec/byte_string_modifier.go @@ -1,6 +1,7 @@ package codec import ( + "bytes" "fmt" "reflect" @@ -66,6 +67,41 @@ func NewPathTraverseAddressBytesToStringModifier( return m } +func NewConstrainedLengthBytesToStringModifier( + fields []string, + maxLen int, +) Modifier { + return NewPathTraverseAddressBytesToStringModifier(fields, &constrainedLengthBytesToStringModifier{maxLen: maxLen}, false) +} + +func NewPathTraverseConstrainedLengthBytesToStringModifier( + fields []string, + maxLen int, + enablePathTraverse bool, +) Modifier { + return NewPathTraverseAddressBytesToStringModifier(fields, &constrainedLengthBytesToStringModifier{maxLen: maxLen}, enablePathTraverse) +} + +type constrainedLengthBytesToStringModifier struct { + maxLen int +} + +func (m constrainedLengthBytesToStringModifier) EncodeAddress(bts []byte) (string, error) { + return string(bytes.Trim(bts, "\x00")), nil +} + +func (m constrainedLengthBytesToStringModifier) DecodeAddress(str string) ([]byte, error) { + output := make([]byte, m.maxLen) + + copy(output, []byte(str)[:]) + + return output, nil +} + +func (m constrainedLengthBytesToStringModifier) Length() int { + return m.maxLen +} + type bytesToStringModifier struct { // Injected modifier that contains chain-specific logic modifier AddressModifier diff --git a/pkg/codec/config.go b/pkg/codec/config.go index c8248aa0e..8632f4018 100644 --- a/pkg/codec/config.go +++ b/pkg/codec/config.go @@ -59,6 +59,8 @@ func (m *ModifiersConfig) UnmarshalJSON(data []byte) error { (*m)[i] = &PropertyExtractorConfig{} case ModifierAddressToString: (*m)[i] = &AddressBytesToStringModifierConfig{} + case ModifierBytesToString: + (*m)[i] = &ConstrainedBytesToStringModifierConfig{} case ModifierWrapper: (*m)[i] = &WrapperModifierConfig{} case ModifierPreCodec: @@ -103,6 +105,7 @@ const ( ModifierEpochToTime ModifierType = "epoch to time" ModifierExtractProperty ModifierType = "extract property" ModifierAddressToString ModifierType = "address to string" + ModifierBytesToString ModifierType = "constrained bytes to string" ModifierWrapper ModifierType = "wrapper" ) @@ -368,6 +371,23 @@ func (c *AddressBytesToStringModifierConfig) MarshalJSON() ([]byte, error) { }) } +type ConstrainedBytesToStringModifierConfig struct { + Fields []string + MaxLen int + EnablePathTraverse bool +} + +func (c *ConstrainedBytesToStringModifierConfig) ToModifier(_ ...mapstructure.DecodeHookFunc) (Modifier, error) { + return NewPathTraverseConstrainedLengthBytesToStringModifier(c.Fields, c.MaxLen, c.EnablePathTraverse), nil +} + +func (c *ConstrainedBytesToStringModifierConfig) MarshalJSON() ([]byte, error) { + return json.Marshal(&modifierMarshaller[ConstrainedBytesToStringModifierConfig]{ + Type: ModifierBytesToString, + T: c, + }) +} + // WrapperModifierConfig replaces each field based on cfg map keys with a struct containing one field with the value of the original field which has is named based on map values. // Wrapper modifier does not maintain the original pointers. // Wrapper modifier config shouldn't edit fields that affect each other since the results are not deterministic.