Skip to content

Commit

Permalink
v3.7.5 (#3330)
Browse files Browse the repository at this point in the history
* [Neo Core Bug]fix 3300 (#3301)

* fix 3300

* update format

* add state subitems to ref counter, with suggestion from DuSmart

* apply hardfork

* format

* my mistake

* fix hardfork

* remove negative check

* add unit test

* apply anna's suggestion

---------

Co-authored-by: Shargon <shargon@gmail.com>
Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com>

* SmartContract: use executing contract state to check permissions (#3290)

It's not correct to use an updated contract state got from native
Management to check for the allowed method call. We need to use
manifest from the currently executing context for that. It may be
critical for cases when executing contract is being updated firstly,
and after that it calls another contract. So we need an old (executing)
contract manifest for this check.

This change is moved under D hardfork to avoid state diff issues on
nodes update. Although it should be noted that it's hard to meet the
trigger criteria.

A port of nspcc-dev/neo-go#3473. This bug was
discovered during the similar problem described in
nspcc-dev/neo-go#3471 and fixed in
nspcc-dev/neo-go#3472. I've checked all other
similar usages and the rest of them use proper contract state (executing
one, not the Management's one).

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Co-authored-by: Shargon <shargon@gmail.com>
Co-authored-by: Jimmy <jinghui@wayne.edu>
Co-authored-by: Vitor Nazário Coelho <vncoelho@gmail.com>

* v3.7.5

* Neo.CLI: enable hardforks for NeoFS mainnet (#3240)

Otherwise this configuration file is broken. Port changes from
nspcc-dev/neo-go#3446.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>

* fix workflow & FS config

* remove hardfork for fs testnet

---------

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Co-authored-by: Jimmy <jinghui@wayne.edu>
Co-authored-by: Shargon <shargon@gmail.com>
Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com>
Co-authored-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Co-authored-by: Vitor Nazário Coelho <vncoelho@gmail.com>
  • Loading branch information
6 people authored Jun 12, 2024
1 parent 7f227a3 commit 2fdf1bb
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 23 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: .NET Core Test and Publish

on:
push:
branches: [master]
branches: [v3.7.5]
pull_request:

env:
Expand Down Expand Up @@ -52,7 +52,7 @@ jobs:
file: ${{ github.workspace }}/TestResults/coverage/coverage.info

PublishPackage:
if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/')
if: github.ref == 'refs/heads/v3.7.5' && startsWith(github.repository, 'neo-project/')
needs: Test
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -101,7 +101,7 @@ jobs:
--no-service-endpoint;
Release:
if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/')
if: github.ref == 'refs/heads/v3.7.5' && startsWith(github.repository, 'neo-project/')
needs: Test
runs-on: ubuntu-latest
steps:
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>Neo</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>Neo.VM</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<PropertyGroup>
<Copyright>2015-2024 The Neo Project</Copyright>
<VersionPrefix>3.7.4</VersionPrefix>
<VersionPrefix>3.7.5</VersionPrefix>
<LangVersion>12.0</LangVersion>
<Authors>The Neo Project</Authors>
<PackageIcon>neo.png</PackageIcon>
Expand Down
6 changes: 6 additions & 0 deletions src/Neo.CLI/config.fs.mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
"MaxTraceableBlocks": 2102400,
"InitialGasDistribution": 5200000000000000,
"ValidatorsCount": 7,
"Hardforks": {
"HF_Aspidochelone": 3000000,
"HF_Basilisk": 4500000,
"HF_Cockatrice": 5800000,
"HF_Domovoi": 5800000
},
"StandbyCommittee": [
"026fa34ec057d74c2fdf1a18e336d0bd597ea401a0b2ad57340d5c220d09f44086",
"039a9db2a30942b1843db673aeb0d4fd6433f74cec1d879de6343cb9fcf7628fa4",
Expand Down
3 changes: 2 additions & 1 deletion src/Neo.CLI/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"Hardforks": {
"HF_Aspidochelone": 1730000,
"HF_Basilisk": 4120000,
"HF_Cockatrice": 5450000
"HF_Cockatrice": 5450000,
"HF_Domovoi": 5570000
},
"InitialGasDistribution": 5200000000000000,
"ValidatorsCount": 7,
Expand Down
3 changes: 2 additions & 1 deletion src/Neo.CLI/config.mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"Hardforks": {
"HF_Aspidochelone": 1730000,
"HF_Basilisk": 4120000,
"HF_Cockatrice": 5450000
"HF_Cockatrice": 5450000,
"HF_Domovoi": 5570000
},
"InitialGasDistribution": 5200000000000000,
"ValidatorsCount": 7,
Expand Down
3 changes: 2 additions & 1 deletion src/Neo.CLI/config.testnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"Hardforks": {
"HF_Aspidochelone": 210000,
"HF_Basilisk": 2680000,
"HF_Cockatrice": 3967000
"HF_Cockatrice": 3967000,
"HF_Domovoi": 4144000
},
"InitialGasDistribution": 5200000000000000,
"ValidatorsCount": 7,
Expand Down
3 changes: 2 additions & 1 deletion src/Neo/Hardfork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum Hardfork : byte
{
HF_Aspidochelone,
HF_Basilisk,
HF_Cockatrice
HF_Cockatrice,
HF_Domovoi
}
}
11 changes: 8 additions & 3 deletions src/Neo/SmartContract/ApplicationEngine.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -406,14 +406,19 @@ protected internal void SendNotification(UInt160 hash, string eventName, Array s
/// </summary>
/// <param name="hash">The hash of the specified contract. It can be set to <see langword="null"/> to get all notifications.</param>
/// <returns>The notifications sent during the execution.</returns>
protected internal NotifyEventArgs[] GetNotifications(UInt160 hash)
protected internal Array GetNotifications(UInt160 hash)
{
IEnumerable<NotifyEventArgs> notifications = Notifications;
if (hash != null) // must filter by scriptHash
notifications = notifications.Where(p => p.ScriptHash == hash);
NotifyEventArgs[] array = notifications.ToArray();
var array = notifications.ToArray();
if (array.Length > Limits.MaxStackSize) throw new InvalidOperationException();
return array;
Array notifyArray = new(ReferenceCounter);
foreach (var notify in array)
{
notifyArray.Add(notify.ToStackItem(ReferenceCounter, this));
}
return notifyArray;
}

/// <summary>
Expand Down
10 changes: 6 additions & 4 deletions src/Neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,14 +271,18 @@ private ExecutionContext CallContractInternal(ContractState contract, ContractMe
if (NativeContract.Policy.IsBlocked(Snapshot, contract.Hash))
throw new InvalidOperationException($"The contract {contract.Hash} has been blocked.");

ExecutionContext currentContext = CurrentContext;
ExecutionContextState state = currentContext.GetState<ExecutionContextState>();
if (method.Safe)
{
flags &= ~(CallFlags.WriteStates | CallFlags.AllowNotify);
}
else
{
ContractState currentContract = NativeContract.ContractManagement.GetContract(Snapshot, CurrentScriptHash);
if (currentContract?.CanCall(contract, method.Name) == false)
var executingContract = IsHardforkEnabled(Hardfork.HF_Domovoi)
? state.Contract // use executing contract state to avoid possible contract update/destroy side-effects, ref. https://github.com/neo-project/neo/pull/3290.
: NativeContract.ContractManagement.GetContract(Snapshot, CurrentScriptHash);
if (executingContract?.CanCall(contract, method.Name) == false)
throw new InvalidOperationException($"Cannot Call Method {method.Name} Of Contract {contract.Hash} From Contract {CurrentScriptHash}");
}

Expand All @@ -291,8 +295,6 @@ private ExecutionContext CallContractInternal(ContractState contract, ContractMe
invocationCounter[contract.Hash] = 1;
}

ExecutionContext currentContext = CurrentContext;
ExecutionContextState state = currentContext.GetState<ExecutionContextState>();
CallFlags callingFlags = state.CallFlags;

if (args.Count != method.Parameters.Length) throw new InvalidOperationException($"Method {method} Expects {method.Parameters.Length} Arguments But Receives {args.Count} Arguments");
Expand Down
28 changes: 24 additions & 4 deletions src/Neo/SmartContract/NotifyEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,31 @@ public void FromStackItem(StackItem stackItem)
public StackItem ToStackItem(ReferenceCounter referenceCounter)
{
return new Array(referenceCounter)
{
ScriptHash.ToArray(),
EventName,
State
};
}

public StackItem ToStackItem(ReferenceCounter referenceCounter, ApplicationEngine engine)
{
if (engine.IsHardforkEnabled(Hardfork.HF_Domovoi))
{
ScriptHash.ToArray(),
EventName,
State
};
return new Array(referenceCounter)
{
ScriptHash.ToArray(),
EventName,
State.OnStack ? State : State.DeepCopy(true)
};
}

return new Array(referenceCounter)
{
ScriptHash.ToArray(),
EventName,
State
};
}
}
}
101 changes: 101 additions & 0 deletions tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.SmartContract;
using Neo.SmartContract.Manifest;
using Neo.UnitTests.Extensions;
using Neo.VM;
using System;
using System.Collections.Immutable;
using System.Linq;
Expand Down Expand Up @@ -103,5 +106,103 @@ public void TestCheckingHardfork()
(setting[sortedHardforks[i]] > setting[sortedHardforks[i + 1]]).Should().Be(false);
}
}

[TestMethod]
public void TestSystem_Contract_Call_Permissions()
{
UInt160 scriptHash;
var snapshot = TestBlockchain.GetTestSnapshot();

// Setup: put a simple contract to the storage.
using (var script = new ScriptBuilder())
{
// Push True on stack and return.
script.EmitPush(true);
script.Emit(OpCode.RET);

// Mock contract and put it to the Managemant's storage.
scriptHash = script.ToArray().ToScriptHash();

snapshot.DeleteContract(scriptHash);
var contract = TestUtils.GetContract(script.ToArray(), TestUtils.CreateManifest("test", ContractParameterType.Any));
contract.Manifest.Abi.Methods = new[]
{
new ContractMethodDescriptor
{
Name = "disallowed",
Parameters = new ContractParameterDefinition[]{}
},
new ContractMethodDescriptor
{
Name = "test",
Parameters = new ContractParameterDefinition[]{}
}
};
snapshot.AddContract(scriptHash, contract);
}

// Disallowed method call.
using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default))
using (var script = new ScriptBuilder())
{
// Build call script calling disallowed method.
script.EmitDynamicCall(scriptHash, "disallowed");

// Mock executing state to be a contract-based.
engine.LoadScript(script.ToArray());
engine.CurrentContext.GetState<ExecutionContextState>().Contract = new()
{
Manifest = new()
{
Abi = new() { },
Permissions = new ContractPermission[]
{
new ContractPermission
{
Contract = ContractPermissionDescriptor.Create(scriptHash),
Methods = WildcardContainer<string>.Create(new string[]{"test"}) // allowed to call only "test" method of the target contract.
}
}
}
};
var currentScriptHash = engine.EntryScriptHash;

Assert.AreEqual(VMState.FAULT, engine.Execute());
Assert.IsTrue(engine.FaultException.ToString().Contains($"Cannot Call Method disallowed Of Contract {scriptHash.ToString()}"));
}

// Allowed method call.
using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default))
using (var script = new ScriptBuilder())
{
// Build call script.
script.EmitDynamicCall(scriptHash, "test");

// Mock executing state to be a contract-based.
engine.LoadScript(script.ToArray());
engine.CurrentContext.GetState<ExecutionContextState>().Contract = new()
{
Manifest = new()
{
Abi = new() { },
Permissions = new ContractPermission[]
{
new ContractPermission
{
Contract = ContractPermissionDescriptor.Create(scriptHash),
Methods = WildcardContainer<string>.Create(new string[]{"test"}) // allowed to call only "test" method of the target contract.
}
}
}
};
var currentScriptHash = engine.EntryScriptHash;

Assert.AreEqual(VMState.HALT, engine.Execute());
Assert.AreEqual(1, engine.ResultStack.Count);
Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Boolean));
var res = (VM.Types.Boolean)engine.ResultStack.Pop();
Assert.IsTrue(res.GetBoolean());
}
}
}
}
26 changes: 25 additions & 1 deletion tests/Neo.UnitTests/SmartContract/UT_InteropService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ public void Runtime_GetNotifications_Test()
}
}
};
contract.Manifest.Permissions = new ContractPermission[]
{
new ContractPermission
{
Contract = ContractPermissionDescriptor.Create(scriptHash2),
Methods = WildcardContainer<string>.Create(new string[]{"test"})
}
};
snapshot.AddContract(scriptHash2, contract);
}

Expand Down Expand Up @@ -133,6 +141,14 @@ public void Runtime_GetNotifications_Test()
Parameters = System.Array.Empty<ContractParameterDefinition>()
}
}
},
Permissions = new ContractPermission[]
{
new ContractPermission
{
Contract = ContractPermissionDescriptor.Create(scriptHash2),
Methods = WildcardContainer<string>.Create(new string[]{"test"})
}
}
}
};
Expand Down Expand Up @@ -202,6 +218,14 @@ public void Runtime_GetNotifications_Test()
Parameters = System.Array.Empty<ContractParameterDefinition>()
}
}
},
Permissions = new ContractPermission[]
{
new ContractPermission
{
Contract = ContractPermissionDescriptor.Create(scriptHash2),
Methods = WildcardContainer<string>.Create(new string[]{"test"})
}
}
}
};
Expand Down Expand Up @@ -642,7 +666,7 @@ public void TestContract_Call()
var args = new VM.Types.Array { 0, 1 };
var state = TestUtils.GetContract(method, args.Count);

var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot);
var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default);
engine.LoadScript(new byte[] { 0x01 });
engine.Snapshot.AddContract(state.Hash, state);

Expand Down
Loading

0 comments on commit 2fdf1bb

Please sign in to comment.