Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,32 @@ Then install python requirements. Python >= 3.5 is required.

```pip install -r requirements.txt```

### Runtime Enhancements

ProtoSolGenerator includes enhanced runtime support for additional protobuf types and Google well-known types:

#### Float and Double Support

The runtime includes native support for protobuf `float` (32-bit) and `double` (64-bit) types:

- `_decode_float(uint256 p, bytes memory bs)` - Decodes protobuf float to bytes4
- `_encode_float(bytes4 x, uint256 p, bytes memory bs)` - Encodes bytes4 to protobuf float
- `_decode_double(uint256 p, bytes memory bs)` - Decodes protobuf double to bytes8
- `_encode_double(bytes8 x, uint256 p, bytes memory bs)` - Encodes bytes8 to protobuf double

These functions enable proper handling of floating-point validation constraints from buf/validate and other protobuf schemas.

#### Google Well-Known Types

Runtime libraries are provided for common Google protobuf types:

- **GoogleProtobufAny.sol** - Support for `google.protobuf.Any` messages
- **GoogleProtobufDuration.sol** - Support for `google.protobuf.Duration` messages
- **GoogleProtobufTimestamp.sol** - Support for `google.protobuf.Timestamp` messages
- **GoogleProtobufFieldDescriptorProto.sol** - Support for `google.protobuf.FieldDescriptorProto` messages

These libraries are automatically included when generating contracts that use the corresponding Google protobuf types.

### Data Definition

Users can use the custom type definition to define their data structure. Below is an example:
Expand Down
232 changes: 232 additions & 0 deletions protobuf-solidity/src/protoc/plugin/runtime/GoogleProtobufDuration.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.10;
import "./ProtoBufRuntime.sol";

library GoogleProtobufDuration {

//struct definition
struct Data {
int64 seconds_field;
int32 nanos;
}

// Decoder section

/**
* @dev The main decoder for memory
* @param bs The bytes array to be decoded
* @return The decoded struct
*/
function decode(bytes memory bs) internal pure returns (Data memory) {
(Data memory x, ) = _decode(32, bs, bs.length);
return x;
}

/**
* @dev The main decoder for storage
* @param self The in-storage struct
* @param bs The bytes array to be decoded
*/
function decode(Data storage self, bytes memory bs) internal {
(Data memory x, ) = _decode(32, bs, bs.length);
store(x, self);
}

// called by the decoder, the result should be stored in self
function store(Data memory input, Data storage self) internal {
self.seconds_field = input.seconds_field;
self.nanos = input.nanos;
}

/**
* @dev The decoder for internal usage
* @param p The offset of bytes array to start decode
* @param bs The bytes array to be decoded
* @param sz The number of bytes expected
* @return The decoded struct
* @return The number of bytes decoded
*/
function _decode(uint256 p, bytes memory bs, uint256 sz)
internal
pure
returns (Data memory, uint)
{
Data memory r;
uint[3] memory counters;
uint256 fieldId;
ProtoBufRuntime.WireType wireType;
uint256 bytesRead;
uint256 offset = p;
uint256 pointer = p;
while (pointer < offset + sz) {
(fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs);
pointer += bytesRead;
if (fieldId == 1) {
pointer += _read_seconds(pointer, bs, r);
} else if (fieldId == 2) {
pointer += _read_nanos(pointer, bs, r);
} else {
pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs);
}
}
return (r, pointer - offset);
}

// field readers

/**
* @dev The decoder for reading a field
* @param p The offset of bytes array to start decode
* @param bs The bytes array to be decoded
* @param r The in-memory struct
* @return The number of bytes decoded
*/
function _read_seconds(
uint256 p,
bytes memory bs,
Data memory r
) internal pure returns (uint) {
(int64 x, uint256 sz) = ProtoBufRuntime._decode_int64(p, bs);
r.seconds_field = x;
return sz;
}

/**
* @dev The decoder for reading a field
* @param p The offset of bytes array to start decode
* @param bs The bytes array to be decoded
* @param r The in-memory struct
* @return The number of bytes decoded
*/
function _read_nanos(
uint256 p,
bytes memory bs,
Data memory r
) internal pure returns (uint) {
(int32 x, uint256 sz) = ProtoBufRuntime._decode_int32(p, bs);
r.nanos = x;
return sz;
}

// Encoder section

/**
* @dev The main encoder for memory
* @param r The struct to be encoded
* @return The encoded byte array
*/
function encode(Data memory r) internal pure returns (bytes memory) {
bytes memory bs = new bytes(_estimate(r));
uint256 sz = _encode(r, 32, bs);
assembly {
mstore(bs, sz)
}
return bs;
}

// inner encoder

/**
* @dev The encoder for internal usage
* @param r The struct to be encoded
* @param p The offset of bytes array to start decode
* @param bs The bytes array to be decoded
* @return The number of bytes encoded
*/
function _encode(Data memory r, uint256 p, bytes memory bs)
internal
pure
returns (uint)
{
uint256 offset = p;
uint256 pointer = p;

if (r.seconds_field != 0) {
pointer += ProtoBufRuntime._encode_key(
1,
ProtoBufRuntime.WireType.Varint,
pointer,
bs
);
pointer += ProtoBufRuntime._encode_int64(r.seconds_field, pointer, bs);
}
if (r.nanos != 0) {
pointer += ProtoBufRuntime._encode_key(
2,
ProtoBufRuntime.WireType.Varint,
pointer,
bs
);
pointer += ProtoBufRuntime._encode_int32(r.nanos, pointer, bs);
}
return pointer - offset;
}

// nested encoder

/**
* @dev The encoder for inner struct
* @param r The struct to be encoded
* @param p The offset of bytes array to start decode
* @param bs The bytes array to be decoded
* @return The number of bytes encoded
*/
function _encode_nested(Data memory r, uint256 p, bytes memory bs)
internal
pure
returns (uint)
{
/**
* First encoded `r` into a temporary array, and encode the actual size used.
* Then copy the temporary array into `bs`.
*/
uint256 offset = p;
uint256 pointer = p;
bytes memory tmp = new bytes(_estimate(r));
uint256 tmpAddr = ProtoBufRuntime.getMemoryAddress(tmp);
uint256 bsAddr = ProtoBufRuntime.getMemoryAddress(bs);
uint256 size = _encode(r, 32, tmp);
pointer += ProtoBufRuntime._encode_varint(size, pointer, bs);
ProtoBufRuntime.copyBytes(tmpAddr + 32, bsAddr + pointer, size);
pointer += size;
delete tmp;
return pointer - offset;
}

// estimator

/**
* @dev The estimator for a struct
* @param r The struct to be encoded
* @return The number of bytes encoded in estimation
*/
function _estimate(
Data memory r
) internal pure returns (uint) {
uint256 e = 0;
if (r.seconds_field != 0) {
e += 1 + ProtoBufRuntime._sz_int64(r.seconds_field);
}
if (r.nanos != 0) {
e += 1 + ProtoBufRuntime._sz_int32(r.nanos);
}
return e;
}

// empty checker

function _empty(
Data memory r
) internal pure returns (bool) {

if (r.seconds_field != 0) {
return false;
}

if (r.nanos != 0) {
return false;
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.10;
import "./ProtoBufRuntime.sol";

library GoogleProtobufFieldDescriptorProto {

enum Type {
TYPE_DOUBLE,
TYPE_FLOAT,
TYPE_INT64,
TYPE_UINT64,
TYPE_INT32,
TYPE_FIXED64,
TYPE_FIXED32,
TYPE_BOOL,
TYPE_STRING,
TYPE_GROUP,
TYPE_MESSAGE,
TYPE_BYTES,
TYPE_UINT32,
TYPE_ENUM,
TYPE_SFIXED32,
TYPE_SFIXED64,
TYPE_SINT32,
TYPE_SINT64
}

function decode_Type(int64 x) internal pure returns (Type) {
return Type(uint256(uint64(x)));
}

function encode_Type(Type x) internal pure returns (int32) {
return int32(uint32(x));
}
}
Loading