Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SC] Contract libraries + ECRecover #697

Open
wants to merge 18 commits into
base: release/1.4.0.0
Choose a base branch
from
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ public void SmartContract_ReferenceResolver_HasCorrectAssemblies()
{
List<Assembly> allowedAssemblies = ReferencedAssemblyResolver.AllowedAssemblies.ToList();

Assert.Equal(5, allowedAssemblies.Count);
Assert.Equal(6, allowedAssemblies.Count);
Assert.Contains(allowedAssemblies, a => a.GetName().Name == "System.Runtime");
Assert.Contains(allowedAssemblies, a => a.GetName().Name == "System.Private.CoreLib");
Assert.Contains(allowedAssemblies, a => a.GetName().Name == "Stratis.SmartContracts");
Assert.Contains(allowedAssemblies, a => a.GetName().Name == "System.Linq");
Assert.Contains(allowedAssemblies, a => a.GetName().Name == "Stratis.SmartContracts.Standards");
Assert.Contains(allowedAssemblies, a => a.GetName().Name == "Stratis.SCL");
}

[Fact]
Expand Down
6 changes: 6 additions & 0 deletions src/Stratis.SmartContracts.CLR.Tests/ContractExecutorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,12 @@ public void Execute_MultipleIfElseBlocks_ExecutionSucceeds()
AssertSuccessfulContractMethodExecution(nameof(MultipleIfElseBlocks), nameof(MultipleIfElseBlocks.PersistNormalizeValue), new object[] { "z" });
}

[Fact]
public void Execute_LibraryContract_ExecutionSucceeds()
{
AssertSuccessfulContractMethodExecution(nameof(LibraryTest), nameof(LibraryTest.Exists));
}

private void AssertSuccessfulContractMethodExecution(string contractName, string methodName, object[] methodParameters = null, string expectedReturn = null)
{
var transactionValue = (Money)100;
Expand Down
16 changes: 16 additions & 0 deletions src/Stratis.SmartContracts.CLR.Tests/SmartContracts/LibraryTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Stratis.SmartContracts;
using Base = Stratis.SCL.Base;

[Deploy]
public class LibraryTest : SmartContract
{
public LibraryTest(ISmartContractState state) : base(state)
{
Base.Operations.Noop();
}

public void Exists()
{
State.SetBool("Exists", true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@
<Compile Update="SmartContracts\InvalidParam.cs">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Compile>
<Compile Update="SmartContracts\LibraryTest.cs">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Compile>
<Compile Update="SmartContracts\MemoryLimit.cs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,44 @@ public Test(ISmartContractState state): base(state)
Assert.False(result.IsValid);
Assert.NotEmpty(result.Errors);
Assert.True(result.Errors.All(e => e is ModuleDefinitionValidationResult));
}
}

[Fact]
public void SmartContractValidator_Allows_SCL()
{
var adjustedSource = @"
using Stratis.SmartContracts;
using Base = Stratis.SCL.Base;

[Deploy]
public class LibraryTest : SmartContract
{
public LibraryTest(ISmartContractState state) : base(state)
{
Base.Operations.Noop();
}

public void Exists()
{
State.SetBool(""Exists"", true);
}
}";
ContractCompilationResult compilationResult = ContractCompiler.Compile(adjustedSource);
Assert.True(compilationResult.Success);

byte[] assemblyBytes = compilationResult.Compilation;
IContractModuleDefinition decompilation = ContractDecompiler.GetModuleDefinition(assemblyBytes).Value;

// Add a module reference
decompilation.ModuleDefinition.ModuleReferences.Add(new ModuleReference("Test.dll"));

var moduleDefinition = decompilation.ModuleDefinition;

SmartContractValidationResult result = new SmartContractValidator().Validate(moduleDefinition);

Assert.False(result.IsValid);
Assert.NotEmpty(result.Errors);
Assert.True(result.Errors.All(e => e is ModuleDefinitionValidationResult));
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<Version>2.0.1.0</Version>
<Version>3.0.0.0-dev</Version>
<Authors>Stratis Group Ltd.</Authors>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public static class ReferencedAssemblyResolver
Core,
typeof(SmartContract).Assembly,
typeof(Enumerable).Assembly,
typeof(IStandardToken).Assembly
typeof(IStandardToken).Assembly,
typeof(SCL.Base.Operations).Assembly
};
}
}
56 changes: 56 additions & 0 deletions src/Stratis.SmartContracts.CLR/SCL/ECRecover.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using NBitcoin;
using Stratis.SmartContracts;

namespace Stratis.SCL.Crypto
{
public static class ECRecover
{
/// <summary>
/// Retrieves the address of the signer of an ECDSA signature.
/// </summary>
/// <param name="message">The message the signature relates to.</param>
/// <param name="signature">The ECDSA signature prepended with header information specifying the correct value of recId.</param>
/// <param name="address">The Address for the signer of a signature.</param>
/// <returns>A bool representing whether or not the signer was retrieved successfully.</returns>
public static bool TryGetSigner(byte[] message, byte[] signature, out Address address)
{
address = Address.Zero;

if (message == null || signature == null)
return false;

// NBitcoin is very throwy
try
{
uint256 hashedUint256 = GetUint256FromMessage(message);

PubKey pubKey = PubKey.RecoverCompact(hashedUint256, signature);

address = CreateAddress(pubKey.Hash.ToBytes());

return true;
}
catch
{
return false;
}
}

private static uint256 GetUint256FromMessage(byte[] message)
{
return new uint256(SHA3.Keccak256(message));
}

private static Address CreateAddress(byte[] bytes)
{
uint pn0 = BitConverter.ToUInt32(bytes, 0);
uint pn1 = BitConverter.ToUInt32(bytes, 4);
uint pn2 = BitConverter.ToUInt32(bytes, 8);
uint pn3 = BitConverter.ToUInt32(bytes, 12);
uint pn4 = BitConverter.ToUInt32(bytes, 16);

return new Address(pn0, pn1, pn2, pn3, pn4);
}
}
}
12 changes: 12 additions & 0 deletions src/Stratis.SmartContracts.CLR/SCL/Operations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace Stratis.SCL.Base
{
public static class Operations
{
/// <summary>
/// A no-operation, i.e. it does nothing.
/// </summary>
public static void Noop() { }
}
}
17 changes: 17 additions & 0 deletions src/Stratis.SmartContracts.CLR/SCL/SHA3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using HashLib;

namespace Stratis.SCL.Crypto
{
public static class SHA3
{
/// <summary>
/// Returns a 32-byte Keccak256 hash of the given bytes.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static byte[] Keccak256(byte[] input)
{
return HashFactory.Crypto.SHA3.CreateKeccak256().ComputeBytes(input).GetBytes();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<AssemblyVersion>2.0.2.0</AssemblyVersion>
<FileVersion>2.0.2.0</FileVersion>
<Version>2.0.2.0</Version>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.0.0</FileVersion>
<Version>3.0.0.0</Version>
<Authors>Stratis Group Ltd.</Authors>
<Product>Stratis.SmartContracts.CLR</Product>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public static class DeterminismPolicy
public static WhitelistPolicy WhitelistPolicy = new WhitelistPolicy()
.Namespace(nameof(System), AccessPolicy.Denied, SystemPolicy)
.Namespace(typeof(RuntimeHelpers).Namespace, AccessPolicy.Denied, CompilerServicesPolicy)
.Namespace(typeof(SmartContract).Namespace, AccessPolicy.Allowed, SmartContractsPolicy);
.Namespace(typeof(SmartContract).Namespace, AccessPolicy.Allowed, SmartContractsPolicy)
.Namespace(typeof(SCL.Base.Operations).Namespace, AccessPolicy.Allowed)
.Namespace(typeof(SCL.Crypto.ECRecover).Namespace, AccessPolicy.Allowed);

public static ValidationPolicy Default = new ValidationPolicy()
.WhitelistValidator(WhitelistPolicy)
Expand All @@ -37,7 +39,7 @@ private static void SystemPolicy(NamespacePolicy policy)
.Member(nameof(Array.SetValue), AccessPolicy.Allowed)
.Member(nameof(Array.Resize), AccessPolicy.Allowed))
.Type(typeof(void).Name, AccessPolicy.Allowed)
.Type(typeof(object).Name, AccessPolicy.Denied,
.Type(typeof(object).Name, AccessPolicy.Denied,
m => m.Member(nameof(ToString), AccessPolicy.Allowed)
.Constructor(AccessPolicy.Allowed));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Stratis.SmartContracts;
using Stratis.SmartContracts.CLR.Validation;
using Stratis.SmartContracts.CLR.Validation.Validators.Method;
using Stratis.SmartContracts.CLR.Validation.Validators.Module;
using Stratis.SmartContracts.CLR.Validation.Validators.Type;
Expand All @@ -23,7 +25,8 @@ public static class FormatPolicy
Core,
typeof(SmartContract).Assembly,
typeof(Enumerable).Assembly,
typeof(IStandardToken).Assembly
typeof(IStandardToken).Assembly,
typeof(SCL.Base.Operations).Assembly
};

public static ValidationPolicy Default = new ValidationPolicy()
Expand All @@ -46,5 +49,5 @@ public static class FormatPolicy
.MethodDefValidator(new PInvokeValidator())
.InstructionValidator(new MultiDimensionalArrayValidator())
.InstructionValidator(new NewObjValidator());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using Stratis.SmartContracts;

namespace Stratis.SmartContracts.CLR.Validation
{
public static class Primitives
{
public static IEnumerable<Type> Types { get; } = new []
public static IEnumerable<Type> Types { get; } = new[]
{
typeof(bool),
typeof(byte),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Mono.Cecil;
using Stratis.SmartContracts.CLR.Validation;

namespace Stratis.SmartContracts.CLR.Validation
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Stratis.SmartContracts.CLR.Validation;

namespace Stratis.SmartContracts.CLR.Validation
{
Expand All @@ -15,7 +16,7 @@ public SmartContractValidationResult Validate(ModuleDefinition moduleDefinition)

var validator = new ModulePolicyValidator(policy);

List<ValidationResult> results = validator.Validate(moduleDefinition).ToList();
var results = validator.Validate(moduleDefinition).ToList();

return new SmartContractValidationResult(results);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using Mono.Cecil;
using Stratis.SmartContracts.CLR.Validation;

namespace Stratis.SmartContracts.CLR.Validation
{
public sealed class SmartContractValidator : ISmartContractValidator
{
public SmartContractValidationResult Validate(ModuleDefinition moduleDefinition)
{
ValidationPolicy policy = ValidationPolicy.FromExisting(new[] { FormatPolicy.Default, DeterminismPolicy.Default });
var policy = ValidationPolicy.FromExisting(new[] { FormatPolicy.Default, DeterminismPolicy.Default });
var validator = new ModulePolicyValidator(policy);

List<ValidationResult> results = validator.Validate(moduleDefinition).ToList();
var results = validator.Validate(moduleDefinition).ToList();
return new SmartContractValidationResult(results);
}
}
Expand Down
Loading