diff --git a/abi/codec.go b/abi/codec.go index cad347d..6037978 100644 --- a/abi/codec.go +++ b/abi/codec.go @@ -9,12 +9,7 @@ import ( ) type codec struct { - codecForBool *codecForBool codecForSmallInt *codecForSmallInt - codecForBigInt *codecForBigInt - codecForAddress *codecForAddress - codecForString *codecForString - codecForBytes *codecForBytes codecForStruct *codeForStruct codecForEnum *codecForEnum codecForOption *codecForOption @@ -34,14 +29,7 @@ func newCodec(args argsNewCodec) (*codec, error) { } codec := &codec{ - codecForBool: &codecForBool{}, codecForSmallInt: &codecForSmallInt{}, - codecForBigInt: &codecForBigInt{}, - codecForAddress: &codecForAddress{ - pubKeyLength: args.pubKeyLength, - }, - codecForString: &codecForString{}, - codecForBytes: &codecForBytes{}, } codec.codecForStruct = &codeForStruct{ @@ -77,7 +65,7 @@ func (c *codec) EncodeNested(value any) ([]byte, error) { func (c *codec) doEncodeNested(writer io.Writer, value any) error { switch value := value.(type) { case BoolValue: - return c.codecForBool.encodeNested(writer, value) + return value.encodeNested(writer) case U8Value: return c.codecForSmallInt.encodeNested(writer, value.Value, 1) case U16Value: @@ -95,15 +83,15 @@ func (c *codec) doEncodeNested(writer io.Writer, value any) error { case I64Value: return c.codecForSmallInt.encodeNested(writer, value.Value, 8) case BigUIntValue: - return c.codecForBigInt.encodeNestedUnsigned(writer, value.Value) + return value.encodeNested(writer) case BigIntValue: - return c.codecForBigInt.encodeNestedSigned(writer, value.Value) + return value.encodeNested(writer) case AddressValue: - return c.codecForAddress.encodeNested(writer, value) + return value.encodeNested(writer) case StringValue: - return c.codecForString.encodeNested(writer, value) + return value.encodeNested(writer) case BytesValue: - return c.codecForBytes.encodeNested(writer, value) + return value.encodeNested(writer) case StructValue: return c.codecForStruct.encodeNested(writer, value) case EnumValue: @@ -131,7 +119,7 @@ func (c *codec) EncodeTopLevel(value any) ([]byte, error) { func (c *codec) doEncodeTopLevel(writer io.Writer, value any) error { switch value := value.(type) { case BoolValue: - return c.codecForBool.encodeTopLevel(writer, value) + return value.encodeTopLevel(writer) case U8Value: return c.codecForSmallInt.encodeTopLevelUnsigned(writer, uint64(value.Value)) case U16Value: @@ -149,15 +137,15 @@ func (c *codec) doEncodeTopLevel(writer io.Writer, value any) error { case I64Value: return c.codecForSmallInt.encodeTopLevelSigned(writer, value.Value) case BigUIntValue: - return c.codecForBigInt.encodeTopLevelUnsigned(writer, value.Value) + return value.encodeTopLevel(writer) case BigIntValue: - return c.codecForBigInt.encodeTopLevelSigned(writer, value.Value) + return value.encodeTopLevel(writer) case AddressValue: - return c.codecForAddress.encodeTopLevel(writer, value) + return value.encodeTopLevel(writer) case StringValue: - return c.codecForString.encodeTopLevel(writer, value) + return value.encodeTopLevel(writer) case BytesValue: - return c.codecForBytes.encodeTopLevel(writer, value) + return value.encodeTopLevel(writer) case StructValue: return c.codecForStruct.encodeTopLevel(writer, value) case EnumValue: @@ -185,7 +173,7 @@ func (c *codec) DecodeNested(data []byte, value any) error { func (c *codec) doDecodeNested(reader io.Reader, value any) error { switch value := value.(type) { case *BoolValue: - return c.codecForBool.decodeNested(reader, value) + return value.decodeNested(reader) case *U8Value: return c.codecForSmallInt.decodeNested(reader, &value.Value, 1) case *U16Value: @@ -203,27 +191,15 @@ func (c *codec) doDecodeNested(reader io.Reader, value any) error { case *I64Value: return c.codecForSmallInt.decodeNested(reader, &value.Value, 8) case *BigUIntValue: - n, err := c.codecForBigInt.decodeNestedUnsigned(reader) - if err != nil { - return err - } - - value.Value = n - return nil + return value.decodeNested(reader) case *BigIntValue: - n, err := c.codecForBigInt.decodeNestedSigned(reader) - if err != nil { - return err - } - - value.Value = n - return nil + return value.decodeNested(reader) case *AddressValue: - return c.codecForAddress.decodeNested(reader, value) + return value.decodeNested(reader) case *StringValue: - return c.codecForString.decodeNested(reader, value) + return value.decodeNested(reader) case *BytesValue: - return c.codecForBytes.decodeNested(reader, value) + return value.decodeNested(reader) case *StructValue: return c.codecForStruct.decodeNested(reader, value) case *EnumValue: @@ -250,7 +226,7 @@ func (c *codec) DecodeTopLevel(data []byte, value any) error { func (c *codec) doDecodeTopLevel(data []byte, value any) error { switch value := value.(type) { case *BoolValue: - return c.codecForBool.decodeTopLevel(data, value) + return value.decodeTopLevel(data) case *U8Value: n, err := c.codecForSmallInt.decodeTopLevelUnsigned(data, math.MaxUint8) if err != nil { @@ -309,17 +285,15 @@ func (c *codec) doDecodeTopLevel(data []byte, value any) error { value.Value = int64(n) case *BigUIntValue: - n := c.codecForBigInt.decodeTopLevelUnsigned(data) - value.Value = n + value.decodeTopLevel(data) case *BigIntValue: - n := c.codecForBigInt.decodeTopLevelSigned(data) - value.Value = n + value.decodeTopLevel(data) case *AddressValue: - return c.codecForAddress.decodeTopLevel(data, value) + return value.decodeTopLevel(data) case *StringValue: - return c.codecForString.decodeTopLevel(data, value) + return value.decodeTopLevel(data) case *BytesValue: - return c.codecForBytes.decodeTopLevel(data, value) + return value.decodeTopLevel(data) case *StructValue: return c.codecForStruct.decodeTopLevel(data, value) case *EnumValue: diff --git a/abi/codecForAddress.go b/abi/codecForAddress.go index 7d8cd97..65fc9a1 100644 --- a/abi/codecForAddress.go +++ b/abi/codecForAddress.go @@ -5,12 +5,13 @@ import ( "io" ) -type codecForAddress struct { - pubKeyLength int +// AddressValue is a wrapper for an address +type AddressValue struct { + Value []byte } -func (c *codecForAddress) encodeNested(writer io.Writer, value AddressValue) error { - err := c.checkPubKeyLength(value.Value) +func (value *AddressValue) encodeNested(writer io.Writer) error { + err := value.checkPubKeyLength(value.Value) if err != nil { return err } @@ -19,12 +20,12 @@ func (c *codecForAddress) encodeNested(writer io.Writer, value AddressValue) err return err } -func (c *codecForAddress) encodeTopLevel(writer io.Writer, value AddressValue) error { - return c.encodeNested(writer, value) +func (value *AddressValue) encodeTopLevel(writer io.Writer) error { + return value.encodeNested(writer) } -func (c *codecForAddress) decodeNested(reader io.Reader, value *AddressValue) error { - data, err := readBytesExactly(reader, c.pubKeyLength) +func (value *AddressValue) decodeNested(reader io.Reader) error { + data, err := readBytesExactly(reader, pubKeyLength) if err != nil { return err } @@ -33,8 +34,8 @@ func (c *codecForAddress) decodeNested(reader io.Reader, value *AddressValue) er return nil } -func (c *codecForAddress) decodeTopLevel(data []byte, value *AddressValue) error { - err := c.checkPubKeyLength(data) +func (value *AddressValue) decodeTopLevel(data []byte) error { + err := value.checkPubKeyLength(data) if err != nil { return err } @@ -43,8 +44,8 @@ func (c *codecForAddress) decodeTopLevel(data []byte, value *AddressValue) error return nil } -func (c *codecForAddress) checkPubKeyLength(pubkey []byte) error { - if len(pubkey) != c.pubKeyLength { +func (value *AddressValue) checkPubKeyLength(pubkey []byte) error { + if len(pubkey) != pubKeyLength { return fmt.Errorf("public key (address) has invalid length: %d", len(pubkey)) } diff --git a/abi/codecForBigInt.go b/abi/codecForBigInt.go index df7f5aa..2266dae 100644 --- a/abi/codecForBigInt.go +++ b/abi/codecForBigInt.go @@ -7,11 +7,13 @@ import ( twos "github.com/multiversx/mx-components-big-int/twos-complement" ) -type codecForBigInt struct { +// BigUIntValue is a wrapper for a big integer (unsigned) +type BigUIntValue struct { + Value *big.Int } -func (c *codecForBigInt) encodeNestedUnsigned(writer io.Writer, value *big.Int) error { - data := value.Bytes() +func (value *BigUIntValue) encodeNested(writer io.Writer) error { + data := value.Value.Bytes() dataLength := len(data) // Write the length of the payload @@ -29,38 +31,54 @@ func (c *codecForBigInt) encodeNestedUnsigned(writer io.Writer, value *big.Int) return nil } -func (c *codecForBigInt) encodeNestedSigned(writer io.Writer, value *big.Int) error { - data := twos.ToBytes(value) - dataLength := len(data) +func (value *BigUIntValue) encodeTopLevel(writer io.Writer) error { + data := value.Value.Bytes() + _, err := writer.Write(data) + if err != nil { + return err + } - // Write the length of the payload - err := encodeLength(writer, uint32(dataLength)) + return nil +} + +func (value *BigUIntValue) decodeNested(reader io.Reader) error { + // Read the length of the payload + length, err := decodeLength(reader) if err != nil { return err } - // Write the payload - _, err = writer.Write(data) + // Read the payload + data, err := readBytesExactly(reader, int(length)) if err != nil { return err } + value.Value = big.NewInt(0).SetBytes(data) return nil } -func (c *codecForBigInt) encodeTopLevelUnsigned(writer io.Writer, value *big.Int) error { - data := value.Bytes() - _, err := writer.Write(data) +func (value *BigUIntValue) decodeTopLevel(data []byte) { + value.Value = big.NewInt(0).SetBytes(data) +} + +// BigIntValue is a wrapper for a big integer (signed) +type BigIntValue struct { + Value *big.Int +} + +func (value *BigIntValue) encodeNested(writer io.Writer) error { + data := twos.ToBytes(value.Value) + dataLength := len(data) + + // Write the length of the payload + err := encodeLength(writer, uint32(dataLength)) if err != nil { return err } - return nil -} - -func (c *codecForBigInt) encodeTopLevelSigned(writer io.Writer, value *big.Int) error { - data := twos.ToBytes(value) - _, err := writer.Write(data) + // Write the payload + _, err = writer.Write(data) if err != nil { return err } @@ -68,42 +86,33 @@ func (c *codecForBigInt) encodeTopLevelSigned(writer io.Writer, value *big.Int) return nil } -func (c *codecForBigInt) decodeNestedUnsigned(reader io.Reader) (*big.Int, error) { - // Read the length of the payload - length, err := decodeLength(reader) - if err != nil { - return nil, err - } - - // Read the payload - data, err := readBytesExactly(reader, int(length)) +func (value *BigIntValue) encodeTopLevel(writer io.Writer) error { + data := twos.ToBytes(value.Value) + _, err := writer.Write(data) if err != nil { - return nil, err + return err } - return big.NewInt(0).SetBytes(data), nil + return nil } -func (c *codecForBigInt) decodeNestedSigned(reader io.Reader) (*big.Int, error) { +func (value *BigIntValue) decodeNested(reader io.Reader) error { // Read the length of the payload length, err := decodeLength(reader) if err != nil { - return nil, err + return err } // Read the payload data, err := readBytesExactly(reader, int(length)) if err != nil { - return nil, err + return err } - return twos.FromBytes(data), nil -} - -func (c *codecForBigInt) decodeTopLevelUnsigned(data []byte) *big.Int { - return big.NewInt(0).SetBytes(data) + value.Value = twos.FromBytes(data) + return nil } -func (c *codecForBigInt) decodeTopLevelSigned(data []byte) *big.Int { - return twos.FromBytes(data) +func (value *BigIntValue) decodeTopLevel(data []byte) { + value.Value = twos.FromBytes(data) } diff --git a/abi/codecForBool.go b/abi/codecForBool.go index b34d902..e2d0c8d 100644 --- a/abi/codecForBool.go +++ b/abi/codecForBool.go @@ -5,10 +5,12 @@ import ( "io" ) -type codecForBool struct { +// BoolValue is a wrapper for a boolean +type BoolValue struct { + Value bool } -func (c *codecForBool) encodeNested(writer io.Writer, value BoolValue) error { +func (value *BoolValue) encodeNested(writer io.Writer) error { if value.Value { _, err := writer.Write([]byte{trueAsByte}) return err @@ -18,7 +20,7 @@ func (c *codecForBool) encodeNested(writer io.Writer, value BoolValue) error { return err } -func (c *codecForBool) encodeTopLevel(writer io.Writer, value BoolValue) error { +func (value *BoolValue) encodeTopLevel(writer io.Writer) error { if !value.Value { // For "false", write nothing. return nil @@ -28,13 +30,13 @@ func (c *codecForBool) encodeTopLevel(writer io.Writer, value BoolValue) error { return err } -func (c *codecForBool) decodeNested(reader io.Reader, value *BoolValue) error { +func (value *BoolValue) decodeNested(reader io.Reader) error { data, err := readBytesExactly(reader, 1) if err != nil { return err } - value.Value, err = c.byteToBool(data[0]) + value.Value, err = value.byteToBool(data[0]) if err != nil { return err } @@ -42,14 +44,14 @@ func (c *codecForBool) decodeNested(reader io.Reader, value *BoolValue) error { return nil } -func (c *codecForBool) decodeTopLevel(data []byte, value *BoolValue) error { +func (value *BoolValue) decodeTopLevel(data []byte) error { if len(data) == 0 { value.Value = false return nil } if len(data) == 1 { - boolValue, err := c.byteToBool(data[0]) + boolValue, err := value.byteToBool(data[0]) if err != nil { return err } @@ -61,7 +63,7 @@ func (c *codecForBool) decodeTopLevel(data []byte, value *BoolValue) error { return fmt.Errorf("unexpected boolean value: %v", data) } -func (c *codecForBool) byteToBool(data uint8) (bool, error) { +func (value *BoolValue) byteToBool(data uint8) (bool, error) { switch data { case trueAsByte: return true, nil diff --git a/abi/codecForBytes.go b/abi/codecForBytes.go index 745944d..90b4981 100644 --- a/abi/codecForBytes.go +++ b/abi/codecForBytes.go @@ -4,10 +4,12 @@ import ( "io" ) -type codecForBytes struct { +// BytesValue is a wrapper for a byte slice +type BytesValue struct { + Value []byte } -func (c *codecForBytes) encodeNested(writer io.Writer, value BytesValue) error { +func (value *BytesValue) encodeNested(writer io.Writer) error { err := encodeLength(writer, uint32(len(value.Value))) if err != nil { return err @@ -17,12 +19,12 @@ func (c *codecForBytes) encodeNested(writer io.Writer, value BytesValue) error { return err } -func (c *codecForBytes) encodeTopLevel(writer io.Writer, value BytesValue) error { +func (value *BytesValue) encodeTopLevel(writer io.Writer) error { _, err := writer.Write(value.Value) return err } -func (c *codecForBytes) decodeNested(reader io.Reader, value *BytesValue) error { +func (value *BytesValue) decodeNested(reader io.Reader) error { length, err := decodeLength(reader) if err != nil { return err @@ -37,7 +39,7 @@ func (c *codecForBytes) decodeNested(reader io.Reader, value *BytesValue) error return nil } -func (c *codecForBytes) decodeTopLevel(data []byte, value *BytesValue) error { +func (value *BytesValue) decodeTopLevel(data []byte) error { value.Value = data return nil } diff --git a/abi/codecForString.go b/abi/codecForString.go index fa85f52..7168e4a 100644 --- a/abi/codecForString.go +++ b/abi/codecForString.go @@ -4,10 +4,12 @@ import ( "io" ) -type codecForString struct { +// StringValue is a wrapper for a string +type StringValue struct { + Value string } -func (c *codecForString) encodeNested(writer io.Writer, value StringValue) error { +func (value *StringValue) encodeNested(writer io.Writer) error { data := []byte(value.Value) err := encodeLength(writer, uint32(len(data))) if err != nil { @@ -18,12 +20,12 @@ func (c *codecForString) encodeNested(writer io.Writer, value StringValue) error return err } -func (c *codecForString) encodeTopLevel(writer io.Writer, value StringValue) error { +func (value *StringValue) encodeTopLevel(writer io.Writer) error { _, err := writer.Write([]byte(value.Value)) return err } -func (c *codecForString) decodeNested(reader io.Reader, value *StringValue) error { +func (value *StringValue) decodeNested(reader io.Reader) error { length, err := decodeLength(reader) if err != nil { return err @@ -38,7 +40,7 @@ func (c *codecForString) decodeNested(reader io.Reader, value *StringValue) erro return nil } -func (c *codecForString) decodeTopLevel(data []byte, value *StringValue) error { +func (value *StringValue) decodeTopLevel(data []byte) error { value.Value = string(data) return nil } diff --git a/abi/constants.go b/abi/constants.go index f07d4a2..91e1470 100644 --- a/abi/constants.go +++ b/abi/constants.go @@ -4,3 +4,4 @@ const trueAsByte = uint8(1) const falseAsByte = uint8(0) const optionMarkerForAbsentValue = uint8(0) const optionMarkerForPresentValue = uint8(1) +const pubKeyLength = 32 diff --git a/abi/valuesSingle.go b/abi/valuesSingle.go index cfbd070..d8ca19a 100644 --- a/abi/valuesSingle.go +++ b/abi/valuesSingle.go @@ -1,7 +1,5 @@ package abi -import "math/big" - // U8Value is a wrapper for uint8 type U8Value struct { Value uint8 @@ -42,36 +40,6 @@ type I64Value struct { Value int64 } -// BigUIntValue is a wrapper for a big integer (unsigned) -type BigUIntValue struct { - Value *big.Int -} - -// BigIntValue is a wrapper for a big integer (signed) -type BigIntValue struct { - Value *big.Int -} - -// AddressValue is a wrapper for an address -type AddressValue struct { - Value []byte -} - -// BytesValue is a wrapper for a byte slice -type BytesValue struct { - Value []byte -} - -// StringValue is a wrapper for a string -type StringValue struct { - Value string -} - -// BoolValue is a wrapper for a boolean -type BoolValue struct { - Value bool -} - // OptionValue is a wrapper for an option value type OptionValue struct { Value any