Skip to content

Commit

Permalink
Tomb Address Cast
Browse files Browse the repository at this point in the history
- Address Cast Address.text(...)
- Added new Calls Runtime.notify(...), Runtime.nexus(), Address.text(...)
- On emit events force 64 eventkind
  • Loading branch information
TeknoPT committed Dec 26, 2023
1 parent c88c2da commit dde7617
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 36 deletions.
3 changes: 3 additions & 0 deletions Library/src/AST/Statements/EmitStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public override void GenerateCode(CodeGenerator output)

reg = addressExpr.GenerateCode(output);
output.AppendLine(this, $"PUSH {reg}");

/*output.AppendLine(this, $"LOAD {reg} {eventDecl.Name}");
output.AppendLine(this, $"PUSH {reg}");*/

output.AppendLine(this, $"LOAD {reg} {eventDecl.value}");
output.AppendLine(this, $"PUSH {reg}");
Expand Down
107 changes: 73 additions & 34 deletions Library/src/CodeGen/Libraries.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Phantasma.Business.Blockchain.Contracts.Native;
using Phantasma.Core.Cryptography.Structs;
using Phantasma.Core.Domain.Contract;
using Phantasma.Core.Domain.Contract.Enums;
using Phantasma.Core.Domain.Serializer;
Expand Down Expand Up @@ -104,40 +105,6 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin

switch (name)
{
case "ABI":
{
libDecl.AddMethod("getMethod", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Module), new MethodParameter("method", VarKind.String) }).
SetPreCallback((output, scope, expr) =>
{
var reg = Compiler.Instance.AllocRegister(output, expr);
var module = expr.arguments[0].AsLiteral<Module>();
var methodName = expr.arguments[1].AsLiteral<string>();

var method = module.abi.FindMethod(methodName);
if (method == null)
{
throw new CompilerException($"Cannot find method '{methodName}' in module '{module.Name}'");
}
var vmObj = VMObject.FromStruct(method);
var hexString = vmObj.Serialize();
output.AppendLine(expr, $"LOAD {reg} 0x{hexString}");
output.AppendLine(expr, $"UNPACK {reg} {reg}");
return reg;
});

libDecl.AddMethod("hasMethod", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Module), new MethodParameter("method", VarKind.String) }).
SetPreCallback((output, scope, expr) =>
{
var reg = Compiler.Instance.AllocRegister(output, expr);
var module = expr.arguments[0].AsLiteral<Module>();
var methodName = expr.arguments[1].AsLiteral<string>();

var hasMethod = module.abi.HasMethod(methodName);
output.AppendLine(expr, $"LOAD {reg} {hasMethod}");
return reg;
});
break;
}
case "Module":
libDecl.AddMethod("getScript", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Module) }).
SetPreCallback((output, scope, expr) =>
Expand Down Expand Up @@ -308,6 +275,15 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin
libDecl.AddMethod("isUser", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) });
libDecl.AddMethod("isSystem", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) });
libDecl.AddMethod("isInterop", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) });
libDecl.AddMethod("text", MethodImplementationType.Custom, VarKind.String, new[] { new MethodParameter("target", VarKind.Address) })
.SetPreCallback((output, scope, expr) =>
{

var reg = expr.arguments[0].GenerateCode(output);
output.AppendLine(expr, $"CAST {reg} {reg} #{VMType.String}"); // String
return reg;
});


GenerateCasts(libDecl, VarKind.Bytes, new VarKind[] { VarKind.String });

Expand Down Expand Up @@ -379,6 +355,8 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin
{
libDecl.AddMethod("AESDecrypt", MethodImplementationType.ExtCall, VarKind.Bytes, new[] { new MethodParameter("data", VarKind.Bytes), new MethodParameter("key", VarKind.Bytes) }).SetAlias("Runtime.AESDecrypt");
libDecl.AddMethod("AESEncrypt", MethodImplementationType.ExtCall, VarKind.Bytes, new[] { new MethodParameter("data", VarKind.Bytes), new MethodParameter("key", VarKind.Bytes) }).SetAlias("Runtime.AESEncrypt");
// TODO: Implement the validate . libDecl.AddMethod("Validate", MethodImplementationType.ExtCall, VarKind.Bytes, new[] { new MethodParameter("data", VarKind.Bytes), new MethodParameter("key", VarKind.Bytes) }).SetAlias("Runtime.AESEncrypt");

break;
}

Expand Down Expand Up @@ -415,6 +393,9 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin
libDecl.AddMethod("previousContext", MethodImplementationType.ExtCall, VarKind.String, new MethodParameter[] { }).SetAlias("Runtime.PreviousContext");
libDecl.AddMethod("version", MethodImplementationType.ExtCall, VarKind.Number, new MethodParameter[] { }).SetAlias("Runtime.Version");
libDecl.AddMethod("getGovernanceValue", MethodImplementationType.ExtCall, VarKind.Number, new MethodParameter[] { new MethodParameter("tag", VarKind.String) }).SetAlias("Nexus.GetGovernanceValue");
libDecl.AddMethod("notify", MethodImplementationType.ExtCall, VarKind.None, new MethodParameter[] { new MethodParameter("evtkind", VarKind.Number), new MethodParameter("from", VarKind.Address), new MethodParameter("data", VarKind.Any), new MethodParameter("name", VarKind.String) }).SetAlias("Runtime.Notify");
libDecl.AddMethod("nexus", MethodImplementationType.ExtCall, VarKind.String, new MethodParameter[] { }).SetAlias("Runtime.Nexus");
// TODO Validate Signature
break;

case "Task":
Expand Down Expand Up @@ -802,6 +783,64 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin
libDecl.AddMethod("getUserDomain", MethodImplementationType.ContractCall, VarKind.String, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(MailContract.GetUserDomain));
break;
}

case "ABI":
{
libDecl.AddMethod("getMethod", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Module), new MethodParameter("method", VarKind.String) }).
SetPreCallback((output, scope, expr) =>
{
var reg = Compiler.Instance.AllocRegister(output, expr);
var module = expr.arguments[0].AsLiteral<Module>();
//var nameReg = expr.arguments[1].GenerateCode(output);
string methodName = expr.arguments[1].AsLiteral<string>().Replace("\"", "");
var method = module.abi.FindMethod(methodName);
if (method == null)
{
throw new CompilerException($"Cannot find method '{methodName}' in module '{module.Name}'");
}
var vmObj = VMObject.FromStruct(method);
var hexString = Base16.Encode(vmObj.Serialize());
output.AppendLine(expr, $"LOAD {reg} 0x{hexString}");
output.AppendLine(expr, $"UNPACK {reg} {reg}");
return reg;
});

libDecl.AddMethod("hasMethod", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Module), new MethodParameter("method", VarKind.String) }).
SetPreCallback((output, scope, expr) =>
{
var reg = Compiler.Instance.AllocRegister(output, expr);
var module = expr.arguments[0].AsLiteral<Module>();
var methodName = expr.arguments[1].AsLiteral<string>();

var hasMethod = module.abi.HasMethod(methodName);
output.AppendLine(expr, $"LOAD {reg} {hasMethod}");
return reg;
});
/*libDecl.AddMethod("createPropertyScript", MethodImplementationType.Custom, VarKind.Generic, new[] { new MethodParameter("script", VarKind.Bytes), new MethodParameter("method", VarKind.String) }).
SetPreCallback((output, scope, expr) =>
{
var reg = Compiler.Instance.AllocRegister(output, expr);
var methodName = expr.arguments[0].AsLiteral<byte[]>();
var methodName = expr.arguments[1].AsLiteral<string>();
var hasMethod = module.abi.HasMethod(methodName);
output.AppendLine(expr, $"LOAD {reg} {hasMethod}");
return reg;
});
libDecl.AddMethod("replaceMethod", MethodImplementationType.Custom, VarKind.Generic, new[] { new MethodParameter("script", VarKind.Bytes), new MethodParameter("method", VarKind.String) }).
SetPreCallback((output, scope, expr) =>
{
var reg = Compiler.Instance.AllocRegister(output, expr);
var methodName = expr.arguments[0].AsLiteral<byte[]>();
var methodName = expr.arguments[1].AsLiteral<string>();
var hasMethod = module.abi.HasMethod(methodName);
output.AppendLine(expr, $"LOAD {reg} {hasMethod}");
return reg;
});*/
break;
}

default:
return FindExternalLibrary(name, scope, moduleKind);
Expand Down
3 changes: 2 additions & 1 deletion Library/src/Compilers/TombLangCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,8 @@ private void ParseModule(Module module)

ExpectToken(";");

var value = (byte)((byte)EventKind.Custom + contract.Events.Count);
//var value = (byte)((byte)EventKind.Custom + contract.Events.Count);
var value = (byte)EventKind.Custom;

var eventDecl = new EventDeclaration(module.Scope, eventName, value, eventType, description);

Expand Down
60 changes: 60 additions & 0 deletions Library/tests/Contracts/ABITests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Nethereum.Util;
using Phantasma.Core.Cryptography;
using Phantasma.Core.Domain.Contract;
using Phantasma.Core.Domain.Execution.Enums;
using Phantasma.Core.Domain.VM;
using Phantasma.Tomb.Compilers;

namespace TOMBLib.Tests.Contracts;

public class ABITests
{
[Test]
public void ABITest()
{
var sourceCode = @"
token MTEST {
public getName(): string {
return ""Unit test"";
}
}
contract mytests {
import Array;
import ABI;
import Module;
public test():number {
local myABI = Module.getABI(MTEST);
local myMethod = ABI.getMethod(MTEST, ""getName"");
return 0;
}
}
";

var parser = new TombLangCompiler();
var contract = parser.Process(sourceCode).First();

var storage = new Dictionary<byte[], byte[]>(new ByteArrayComparer());

TestVM vm;

var testMethod = contract.abi.FindMethod("test");
Assert.IsNotNull(testMethod);

var keys = PhantasmaKeys.Generate();

vm = new TestVM(contract, storage, testMethod);
var result = vm.Execute();
Assert.IsTrue(result == ExecutionState.Halt);

Assert.IsTrue(storage.Count == 1);

Assert.IsTrue(vm.Stack.Count == 1);

var obj = vm.Stack.Pop();
var newVal = obj.AsString();
var expectedVal = "P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM";

Assert.IsTrue(newVal == expectedVal);
}
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,12 @@ The following libraries can be imported into a contract.
### Address

| Method | Return type | Description |
| --------------------------------- | ----------- | ---------------------------------------------------------------------- |
|-----------------------------------|-------------|------------------------------------------------------------------------|
| Address.isNull(target:Address) | Bool | Returns true if the address is null, false otherwise. |
| Address.isUser(target:Address) | Bool | Returns true if the address is a user, false otherwise. |
| Address.isSystem(target:Address) | Bool | Returns true if the address is a System address, false otherwise. |
| Address.isInterop(target:Address) | Bool | Returns true if the address is an Internal Operation, false otherwise. |
| Address.text(target:Address) | String | Returns the address converted to string. |

### Module

Expand Down

0 comments on commit dde7617

Please sign in to comment.