Skip to content

Commit e7d9e83

Browse files
committed
Merge branch 'feature/self-updating-contracts-code'
2 parents 017cee4 + 13dd0a6 commit e7d9e83

File tree

6 files changed

+330
-276
lines changed

6 files changed

+330
-276
lines changed

ProjectPlugins/CodexContractsPlugin/CodexContractsPlugin.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
<Nullable>enable</Nullable>
77
</PropertyGroup>
88

9+
<ItemGroup>
10+
<PackageReference Include="Nethereum.Generators" Version="4.21.4" />
11+
<PackageReference Include="Nethereum.Generators.Net" Version="4.21.4" />
12+
</ItemGroup>
13+
914
<ItemGroup>
1015
<ProjectReference Include="..\..\Framework\Core\Core.csproj" />
1116
<ProjectReference Include="..\GethPlugin\GethPlugin.csproj" />

ProjectPlugins/CodexContractsPlugin/CodexContractsStarter.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Core;
1+
using CodexContractsPlugin.Marketplace;
2+
using Core;
23
using GethPlugin;
34
using KubernetesWorkflow;
45
using KubernetesWorkflow.Types;
@@ -64,7 +65,8 @@ private CodexContractsDeployment DeployContract(RunningContainer container, ISta
6465

6566
var extractor = new ContractsContainerInfoExtractor(tools.GetLog(), workflow, container);
6667
var marketplaceAddress = extractor.ExtractMarketplaceAddress();
67-
var abi = extractor.ExtractMarketplaceAbi();
68+
var (abi, bytecode) = extractor.ExtractMarketplaceAbiAndByteCode();
69+
EnsureCompatbility(abi, bytecode);
6870

6971
var interaction = new ContractInteractions(tools.GetLog(), gethNode);
7072
var tokenAddress = interaction.GetTokenAddress(marketplaceAddress);
@@ -78,6 +80,18 @@ private CodexContractsDeployment DeployContract(RunningContainer container, ISta
7880
return new CodexContractsDeployment(marketplaceAddress, abi, tokenAddress);
7981
}
8082

83+
private void EnsureCompatbility(string abi, string bytecode)
84+
{
85+
var expectedByteCode = MarketplaceDeploymentBase.BYTECODE.ToLowerInvariant();
86+
87+
if (bytecode != expectedByteCode)
88+
{
89+
Log("Deployed contract is incompatible with current build of CodexContracts plugin. Running self-updater...");
90+
var selfUpdater = new SelfUpdater();
91+
selfUpdater.Update(abi, bytecode);
92+
}
93+
}
94+
8195
private void Log(string msg)
8296
{
8397
tools.GetLog().Log(msg);

ProjectPlugins/CodexContractsPlugin/ContractsContainerInfoExtractor.cs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ public string ExtractMarketplaceAddress()
3131
return marketplaceAddress;
3232
}
3333

34-
public string ExtractMarketplaceAbi()
34+
public (string, string) ExtractMarketplaceAbiAndByteCode()
3535
{
3636
log.Debug();
37-
var marketplaceAbi = Retry(FetchMarketplaceAbi);
38-
if (string.IsNullOrEmpty(marketplaceAbi)) throw new InvalidOperationException("Unable to fetch marketplace artifacts from codex-contracts node. Test infra failure.");
37+
var (abi, bytecode) = Retry(FetchMarketplaceAbiAndByteCode);
38+
if (string.IsNullOrEmpty(abi)) throw new InvalidOperationException("Unable to fetch marketplace artifacts from codex-contracts node. Test infra failure.");
3939

40-
log.Debug("Got Marketplace ABI: " + marketplaceAbi);
41-
return marketplaceAbi;
40+
log.Debug("Got Marketplace ABI: " + abi);
41+
return (abi, bytecode);
4242
}
4343

4444
private string FetchMarketplaceAddress()
@@ -48,27 +48,20 @@ private string FetchMarketplaceAddress()
4848
return marketplace!.address;
4949
}
5050

51-
private string FetchMarketplaceAbi()
51+
private (string, string) FetchMarketplaceAbiAndByteCode()
5252
{
5353
var json = workflow.ExecuteCommand(container, "cat", CodexContractsContainerRecipe.MarketplaceArtifactFilename);
5454

5555
var artifact = JObject.Parse(json);
5656
var abi = artifact["abi"];
5757
var byteCode = artifact["bytecode"];
5858
var abiResult = abi!.ToString(Formatting.None);
59-
var byteCodeResult = byteCode!.ToString(Formatting.None);
60-
61-
if (byteCodeResult
62-
.ToLowerInvariant()
63-
.Replace("\"", "") != MarketplaceDeploymentBase.BYTECODE.ToLowerInvariant())
64-
{
65-
throw new Exception("BYTECODE in CodexContractsPlugin does not match BYTECODE deployed by container. Update Marketplace.cs generated code?");
66-
}
67-
68-
return abiResult;
59+
var byteCodeResult = byteCode!.ToString(Formatting.None).ToLowerInvariant().Replace("\"", "");
60+
61+
return (abiResult, byteCodeResult);
6962
}
7063

71-
private static string Retry(Func<string> fetch)
64+
private static T Retry<T>(Func<T> fetch)
7265
{
7366
return Time.Retry(fetch, nameof(ContractsContainerInfoExtractor));
7467
}

ProjectPlugins/CodexContractsPlugin/Marketplace/Marketplace.cs

Lines changed: 190 additions & 256 deletions
Large diffs are not rendered by default.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
namespace CodexContractsPlugin
2+
{
3+
public class SelfUpdater
4+
{
5+
public void Update(string abi, string bytecode)
6+
{
7+
var filePath = GetMarketplaceFilePath();
8+
var content = GenerateContent(abi, bytecode);
9+
var contentLines = content.Split("\r\n");
10+
11+
var beginWith = new string[]
12+
{
13+
"using Nethereum.ABI.FunctionEncoding.Attributes;",
14+
"using Nethereum.Contracts;",
15+
"using System.Numerics;",
16+
"",
17+
"// Generated code, do not modify.",
18+
"",
19+
"#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.",
20+
"namespace CodexContractsPlugin.Marketplace",
21+
"{"
22+
};
23+
24+
var endWith = new string[]
25+
{
26+
"}",
27+
"#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable."
28+
};
29+
30+
File.Delete(filePath);
31+
File.WriteAllLines(filePath,
32+
beginWith.Concat(
33+
contentLines.Concat(
34+
endWith))
35+
);
36+
37+
throw new Exception("Oh no! CodexContracts were updated. Current build of CodexContractsPlugin is incompatible. " +
38+
"But fear not! SelfUpdater.cs has automatically updated the plugin. Just rebuild and rerun and it should work. " +
39+
"Just in case, manual update instructions are found here: 'CodexContractsPlugin/Marketplace/README.md'.");
40+
}
41+
42+
private string GetMarketplaceFilePath()
43+
{
44+
var here = Directory.GetCurrentDirectory();
45+
while (true)
46+
{
47+
var path = GetMarketplaceFile(here);
48+
if (path != null) return path;
49+
50+
var parent = Directory.GetParent(here);
51+
var up = parent?.FullName;
52+
if (up == null || up == here) throw new Exception("Unable to locate ProjectPlugins folder. Unable to update contracts.");
53+
here = up;
54+
}
55+
}
56+
57+
private string? GetMarketplaceFile(string root)
58+
{
59+
var path = Path.Combine(root, "ProjectPlugins", "CodexContractsPlugin", "Marketplace", "Marketplace.cs");
60+
if (File.Exists(path)) return path;
61+
return null;
62+
}
63+
64+
private string GenerateContent(string abi, string bytecode)
65+
{
66+
var deserializer = new Nethereum.Generators.Net.GeneratorModelABIDeserialiser();
67+
var abiModel = deserializer.DeserialiseABI(abi);
68+
var abiCtor = abiModel.Constructor;
69+
var c = new Nethereum.Generators.CQS.ContractDeploymentCQSMessageGenerator(abiCtor, "namespace", bytecode, "Marketplace", Nethereum.Generators.Core.CodeGenLanguage.CSharp);
70+
var lines = "";
71+
lines += c.GenerateClass();
72+
lines += "\r\n";
73+
74+
foreach (var eventAbi in abiModel.Events)
75+
{
76+
var d = new Nethereum.Generators.DTOs.EventDTOGenerator(eventAbi, "namespace", Nethereum.Generators.Core.CodeGenLanguage.CSharp);
77+
lines += d.GenerateClass();
78+
lines += "\r\n";
79+
}
80+
81+
foreach (var errorAbi in abiModel.Errors)
82+
{
83+
var e = new Nethereum.Generators.DTOs.ErrorDTOGenerator(errorAbi, "namespace", Nethereum.Generators.Core.CodeGenLanguage.CSharp);
84+
lines += e.GenerateClass();
85+
lines += "\r\n";
86+
}
87+
88+
foreach (var funcAbi in abiModel.Functions)
89+
{
90+
var f = new Nethereum.Generators.DTOs.FunctionOutputDTOGenerator(funcAbi, "namespace", Nethereum.Generators.Core.CodeGenLanguage.CSharp);
91+
var ff = new Nethereum.Generators.CQS.FunctionCQSMessageGenerator(funcAbi, "namespace", "funcoutput", Nethereum.Generators.Core.CodeGenLanguage.CSharp);
92+
lines += f.GenerateClass();
93+
lines += "\r\n";
94+
lines += ff.GenerateClass();
95+
lines += "\r\n";
96+
}
97+
98+
foreach (var structAbi in abiModel.Structs)
99+
{
100+
var g = new Nethereum.Generators.DTOs.StructTypeGenerator(structAbi, "namespace", Nethereum.Generators.Core.CodeGenLanguage.CSharp);
101+
lines += g.GenerateClass();
102+
lines += "\r\n";
103+
}
104+
105+
return lines;
106+
}
107+
}
108+
}

Tools/MarketInsights/MarketInsights.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net7.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<UserSecretsId>ae71e621-bb16-41b2-b6f3-c597d2d21157</UserSecretsId>

0 commit comments

Comments
 (0)