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
7 changes: 7 additions & 0 deletions ContractPluginCSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{53831842-F
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContractGenerator.Tests", "test\ContractGenerator.Tests\ContractGenerator.Tests.csproj", "{74CCB8DE-3532-4C1C-9CB2-B2F1FEC615AB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContractPlugin.Tests", "test\ContractPlugin.Tests\ContractPlugin.Tests.csproj", "{6CD92AE2-949D-41DE-AC30-D9C9A0B58A51}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -34,10 +36,15 @@ Global
{74CCB8DE-3532-4C1C-9CB2-B2F1FEC615AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74CCB8DE-3532-4C1C-9CB2-B2F1FEC615AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74CCB8DE-3532-4C1C-9CB2-B2F1FEC615AB}.Release|Any CPU.Build.0 = Release|Any CPU
{6CD92AE2-949D-41DE-AC30-D9C9A0B58A51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CD92AE2-949D-41DE-AC30-D9C9A0B58A51}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CD92AE2-949D-41DE-AC30-D9C9A0B58A51}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CD92AE2-949D-41DE-AC30-D9C9A0B58A51}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{AEC22CE5-F118-414C-A962-D1BAA026FA98} = {C3C53F50-7867-4E1D-884A-3B3CBDD3FC80}
{655FE90D-C606-404F-B7B3-F3DD2C3C9452} = {C3C53F50-7867-4E1D-884A-3B3CBDD3FC80}
{74CCB8DE-3532-4C1C-9CB2-B2F1FEC615AB} = {53831842-FD7C-4F64-9E7D-72B54861E1BA}
{6CD92AE2-949D-41DE-AC30-D9C9A0B58A51} = {53831842-FD7C-4F64-9E7D-72B54861E1BA}
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion src/ContractGenerator/AbstractGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected void InBlockWithComma(Action a)
Indent();
a();
Outdent();
PrintLine("};");
PrintLine("},");
}

public abstract string? Generate();
Expand Down
18 changes: 11 additions & 7 deletions src/ContractGenerator/ContractGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@ public class ContractGenerator
var fileName = file.GetOutputCSharpFilename();
if (fileName == "") return output;

output.Add(
new CodeGeneratorResponse.Types.File
{
Name = fileName,
Content = generatedCsCodeBody
}
);
// Only generate specific proto files, don't generate "import proto".
if (file == fileDescriptors.Last())
{
output.Add(
new CodeGeneratorResponse.Types.File
{
Name = fileName,
Content = generatedCsCodeBody
}
);
}
}

return output;
Expand Down
4 changes: 4 additions & 0 deletions src/ContractGenerator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ private static string GetCSharpMethodType(MethodDescriptor method)

private static bool IsViewOnlyMethod(MethodDescriptor method)
{
if (method.GetOptions() == null)
{
return false;
}
return method.GetOptions().GetExtension(OptionsExtensions.IsView);
}

Expand Down
35 changes: 27 additions & 8 deletions src/ContractGenerator/Generator_Base.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,20 @@ protected internal void GenerateContractBaseClass()
{
var methods = GetFullMethod();
foreach (var method in methods)
{
#if VIRTUAL_METHOD
PrintLine(
$"public virtual {GetMethodReturnTypeServer(method)} {method.Name}({GetMethodRequestParamServer(method)}{GetMethodResponseStreamMaybe(method)})");
PrintLine("{");
Indent();
PrintLine("throw new global::System.NotImplementedException();");
Outdent();
PrintLine("}");
#else
PrintLine(
$"public abstract {GetMethodReturnTypeServer(method)} {method.Name}({GetMethodRequestParamServer(method)}{GetMethodResponseStreamMaybe(method)});");
$"public abstract {GetMethodReturnTypeServer(method)} {method.Name}({GetMethodRequestParamServer(method)}{GetMethodResponseStreamMaybe(method)});");
#endif
}
});
}

Expand All @@ -36,16 +48,18 @@ private void GenerateBindServiceMethod()
Indent();
PrintLine(".AddDescriptors(Descriptors)");
var methods = GetFullMethod();
foreach (var method in methods.SkipLast(1))
if (methods.Count > 0)
{
foreach (var method in methods.SkipLast(1))
{
PrintLine(
$".AddMethod({GetMethodFieldName(method)}, serviceImpl.{method.Name})");
}

var lastMethod = methods.Last();
PrintLine(
$".AddMethod({GetMethodFieldName(method)}, serviceImpl.{method.Name})");
$".AddMethod({GetMethodFieldName(lastMethod)}, serviceImpl.{lastMethod.Name}).Build();");
}

var lastMethod = methods.Last();
PrintLine(
$".AddMethod({GetMethodFieldName(lastMethod)}, serviceImpl.{lastMethod.Name}).Build();");

Outdent();
Outdent();
});
Expand All @@ -56,6 +70,11 @@ private void GenerateBindServiceMethod()

private string GetStateTypeName()
{
// If there has no option (aelf.csharp_state) = "XXX" in proto files, state name will return empty string. Such as base proto.
if (_serviceDescriptor.GetOptions() == null)
{
return "";
}
return _serviceDescriptor.GetOptions().GetExtension(OptionsExtensions.CsharpState);
}

Expand Down
1 change: 1 addition & 0 deletions src/ContractGenerator/Primitives/MessagePrimitives.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class MessagePrimitives
/// </summary>
public static bool IsEventMessageType(this MessageDescriptor message)
{
if (message.GetOptions() == null) return false;
return message.GetOptions().GetExtension(OptionsExtensions.IsEvent);
}
}
5 changes: 5 additions & 0 deletions src/ContractGenerator/ProtoUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ private static string ToCSharpName(string name, FileDescriptor fileDescriptor)
//TODO Implementation https://github.com/protocolbuffers/protobuf/blob/e57166b65a6d1d55fc7b18beaae000565f617f22/src/google/protobuf/compiler/csharp/names.cc#L66
public static string GetFileNamespace(FileDescriptor fileDescriptor)
{
// If there has no option csharp_namespace = "XXX" in proto files, state name will return empty string. Such as message proto.
if (fileDescriptor.GetOptions() == null)
{
return "";
}
return fileDescriptor.GetOptions().HasCsharpNamespace
? fileDescriptor.GetOptions().CsharpNamespace
: fileDescriptor.Package.UnderscoresToCamelCase(true, true);
Expand Down
9 changes: 8 additions & 1 deletion src/ContractGenerator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ source proto files.

## Test

You'll need to recompile the protos into a bin file before you can run any Xunit tests. Hence you'll need to run this python-script:
For contract generation unit testing, we need to compile proto files and generate a bin file before you can run any Xunit tests.
This file will be used as a dependency for running unit tests.

Follow the steps below. Firstly, we compile the protos into a bin file using the following python command.

```shell
python3 test/ContractGenerator.Tests/scripts/generate_descriptor.py
```

Then you will see the descriptor.bin file under the folder of proto.

Next, run the unit tests directly, and we can see the testing results.
3 changes: 3 additions & 0 deletions src/ContractPlugin/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("ContractPlugin.Tests")]
74 changes: 37 additions & 37 deletions src/ContractPlugin/ContractPlugin.csproj
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>ContractPlugin</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<PublishTrimmed>true</PublishTrimmed>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>osx-arm64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.24.3"/>
<!-- TODO This needs to be a nuget pkg eventually -->
<ProjectReference Include="..\ContractGenerator\ContractGenerator.csproj"/>
</ItemGroup>
<ItemGroup>
<Compile Remove="obj\**"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="obj\**"/>
</ItemGroup>
<ItemGroup>
<None Remove="obj\**"/>
</ItemGroup>
<!-- Define a default build target -->
<!-- <Target Name="Build" Condition="'$(BuildingInsideVisualStudio)' != 'true'">-->
<!-- <MSBuild Projects="$(MSBuildProjectFile)" Targets="Restore;Build" Properties="Configuration=$(Configuration)"/>-->
<!-- </Target>-->
</Project>
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>ContractPlugin</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<PublishTrimmed>true</PublishTrimmed>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>osx-arm64</RuntimeIdentifier>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.24.3"/>
<!-- TODO This needs to be a nuget pkg eventually -->
<ProjectReference Include="..\ContractGenerator\ContractGenerator.csproj"/>
</ItemGroup>

<ItemGroup>
<Compile Remove="obj\**"/>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Remove="obj\**"/>
</ItemGroup>

<ItemGroup>
<None Remove="obj\**"/>
</ItemGroup>

<!-- Define a default build target -->
<!-- <Target Name="Build" Condition="'$(BuildingInsideVisualStudio)' != 'true'">-->
<!-- <MSBuild Projects="$(MSBuildProjectFile)" Targets="Restore;Build" Properties="Configuration=$(Configuration)"/>-->
<!-- </Target>-->

</Project>
54 changes: 40 additions & 14 deletions src/ContractPlugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,57 @@ This is the actual protoc-plugin executable that is to be built & distributed to

## Build

``
Run build command to compile.
```
dotnet build
``
```

Though to build a single platform-specific binary executable you would need to use this command:
``
```
dotnet publish -c Release -r osx.13-arm64 --self-contained true
``
```

## Using with protoc

You'll need to locate the complete self-contained single binary.
``
cd <ProjectRoot>/src/ContractPlugin/bin/Release/net7.0/osx-arm64/publish
``
```
cd <ProjectRoot>/src/ContractPlugin/bin/Release/net7.0/osx.13-arm64/publish
```

Then copy it to your /usr.. bin folder (i.e your PATH) so that the plugin is accessible via `protoc`
``
mv ContractPlugin /usr/local/bin/protoc-gen-contract_csharp_plugin
``
```
cp ContractPlugin /usr/local/bin/protoc-gen-contract_csharp_plugin
```

Now you can find a project with the required proto contract files and try it out.
``
```
protoc -I ./protos_test/aelf/ -I ./protos_test/ --plugin=contract_csharp_plugin --contract_csharp_plugin_out=. protos_test/hello_world_contract.proto
``
```

you can also try with a protoc-param e.g "stub" to get a different C# output.
``
```
protoc -I ./protos_test/aelf/ -I ./protos_test/ --plugin=contract_csharp_plugin --contract_csharp_plugin_out=. --contract_csharp_plugin_opt="stub" protos_test/hello_world_contract.proto
``
```

## Testing in AElf project

1. Complete `Build` step and run the following command to copy plugin to AElf project.
```
cp <UserRoot>/contract_plugin-csharp/src/ContractPlugin/bin/Release/net7.0/osx.13-arm64/publish/ContractPlugin <UserRoot>/AElf/scripts/contract_csharp_plugin
```

2. Go to system contract module of AElf project, and run build command.

## Remarks

1. Since we change method type from `virtual` to `abstract`, and some methods were not implemented in some system contracts. It will probably build failed. Therefore I add a new flag so that we can generate abstract or virtual methods base on flag.
The usage is as followed.

when run dotnet build command to compile it, use this parameter to decide generated method types.
```
// for compile with virtual type
dotnet publish /p:DefineConstants=VIRTUAL_METHOD

// for compile with abstract type (default)
dotnet publish
```
13 changes: 6 additions & 7 deletions test/ContractGenerator.Tests/ContractGenerator.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="testcases\_common\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
<PackageReference Include="xunit" Version="2.4.2"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
Expand All @@ -29,11 +32,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ContractGenerator\ContractGenerator.csproj"/>
<ProjectReference Include="..\..\src\ContractGenerator\ContractGenerator.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="testcases\_common\"/>
</ItemGroup>


</Project>
Loading