diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 638b5c27f1..159b4982c3 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -40,9 +40,9 @@ jobs:
parts: 3
n: 2
codecoverage: true
- # - template: templates/build-template-macos.yml
- # parameters:
- # parts: 3
- # n: 3
- # codecoverage: true
+ - template: templates/build-template-macos.yml
+ parameters:
+ parts: 3
+ n: 3
+ codecoverage: true
\ No newline at end of file
diff --git a/contract/AElf.Contracts.TokenHolder/TokenHolderContract.cs b/contract/AElf.Contracts.TokenHolder/TokenHolderContract.cs
index e2a60ab703..199bf1810b 100644
--- a/contract/AElf.Contracts.TokenHolder/TokenHolderContract.cs
+++ b/contract/AElf.Contracts.TokenHolder/TokenHolderContract.cs
@@ -13,6 +13,8 @@ public partial class TokenHolderContract : TokenHolderContractImplContainer.Toke
{
public override Empty CreateScheme(CreateTokenHolderProfitSchemeInput input)
{
+ Assert(State.TokenHolderProfitSchemes[Context.Sender] == null, "Token holder profit scheme already exists.");
+
if (State.ProfitContract.Value == null)
State.ProfitContract.Value =
Context.GetContractAddressByName(SmartContractConstants.ProfitContractSystemName);
@@ -52,7 +54,7 @@ public override Empty AddBeneficiary(AddTokenHolderBeneficiaryInput input)
SchemeId = scheme.SchemeId,
Beneficiary = input.Beneficiary
});
- shares.Add(detail.Details.Single().Shares);
+ shares = shares.Add(detail.Details.Single().Shares);
}
State.ProfitContract.AddBeneficiary.Send(new AddBeneficiaryInput
@@ -295,6 +297,6 @@ private void UpdateTokenHolderProfitScheme(ref TokenHolderProfitScheme scheme, A
var originScheme = State.ProfitContract.GetScheme.Call(originSchemeId);
scheme.SchemeId = originScheme.SchemeId;
scheme.Period = originScheme.CurrentPeriod;
- State.TokenHolderProfitSchemes[Context.Sender] = scheme;
+ State.TokenHolderProfitSchemes[manager] = scheme;
}
}
\ No newline at end of file
diff --git a/nuget.config b/nuget.config
index e75cd52656..c87e46df58 100644
--- a/nuget.config
+++ b/nuget.config
@@ -4,6 +4,5 @@
-
\ No newline at end of file
diff --git a/templates/build-template-linux.yml b/templates/build-template-linux.yml
index 829eae430a..d93cf28f9b 100644
--- a/templates/build-template-linux.yml
+++ b/templates/build-template-linux.yml
@@ -18,6 +18,14 @@ jobs:
variables:
CI_TEST: true
steps:
+ - script: |
+ echo "=== Disk space before cleanup ==="
+ df -h /
+ # Remove pre-installed android sdk to free disk space
+ sudo rm -rf /usr/local/lib/android || true
+ echo "=== Disk space after cleanup ==="
+ df -h /
+ displayName: 'Free disk space'
- task: UseDotNet@2
displayName: 'Install .NET Core SDK'
inputs:
diff --git a/test/AElf.Contracts.TestContract.Tests/AElf.Contracts.TestContract.Tests.csproj b/test/AElf.Contracts.TestContract.Tests/AElf.Contracts.TestContract.Tests.csproj
index b38736f190..bc7f0073e6 100644
--- a/test/AElf.Contracts.TestContract.Tests/AElf.Contracts.TestContract.Tests.csproj
+++ b/test/AElf.Contracts.TestContract.Tests/AElf.Contracts.TestContract.Tests.csproj
@@ -97,6 +97,7 @@
Contract
PreserveNewest
+
diff --git a/test/AElf.Contracts.TestContract.Tests/PatchedContractSecurityTests.cs b/test/AElf.Contracts.TestContract.Tests/PatchedContractSecurityTests.cs
index b2c8df1424..03dcae550d 100644
--- a/test/AElf.Contracts.TestContract.Tests/PatchedContractSecurityTests.cs
+++ b/test/AElf.Contracts.TestContract.Tests/PatchedContractSecurityTests.cs
@@ -1,10 +1,16 @@
using System.Text;
using System.Threading.Tasks;
using AElf.Contracts.TestContract.BasicSecurity;
+using AElf.Kernel;
+using AElf.Kernel.Blockchain.Application;
+using AElf.Kernel.SmartContract;
+using AElf.Kernel.SmartContract.Application;
using AElf.Sdk.CSharp;
+using AElf.TestBase;
using AElf.Types;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
+using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
using SmartContractConstants = AElf.Kernel.SmartContract.SmartContractConstants;
@@ -385,7 +391,7 @@ await TestBasicSecurityContractStub.TestMapped2State.SendAsync(new ProtobufInput
}
}
- [Fact]
+ [IgnoreOnCIFact]
public async Task TestBranchCount()
{
{
@@ -434,7 +440,7 @@ await TestBasicSecurityContractStub.TestForeachInfiniteLoop.SendWithExceptionAsy
}
}
- [Fact]
+ [IgnoreOnCIFact]
public async Task TestMethodCallCount()
{
{
@@ -453,4 +459,130 @@ await TestBasicSecurityContractStub.TestInfiniteRecursiveCallInSeparateClass.Sen
txResult.TransactionResult.Error.ShouldContain(nameof(RuntimeCallThresholdExceededException));
}
}
+
+ [Fact]
+ public async Task TestBranchCountWithReducedThreshold()
+ {
+ // Get required services
+ var blockchainService = Application.ServiceProvider.GetRequiredService();
+ var executionObserverThresholdProvider =
+ Application.ServiceProvider.GetRequiredService();
+
+ // Get current best chain block
+ var bestChainBlock = await blockchainService.GetBestChainLastBlockHeaderAsync();
+ var blockIndex = new BlockIndex
+ {
+ BlockHash = bestChainBlock.GetHash(),
+ BlockHeight = bestChainBlock.Height
+ };
+
+ // Set reduced threshold to 5000
+ const int reducedThreshold = 5000;
+ var newThreshold = new ExecutionObserverThreshold
+ {
+ ExecutionBranchThreshold = reducedThreshold,
+ ExecutionCallThreshold = reducedThreshold
+ };
+ await executionObserverThresholdProvider.SetExecutionObserverThresholdAsync(blockIndex, newThreshold);
+
+ // Verify threshold was set correctly
+ var currentThreshold = executionObserverThresholdProvider.GetExecutionObserverThreshold(blockIndex);
+ currentThreshold.ExecutionBranchThreshold.ShouldBe(reducedThreshold);
+ currentThreshold.ExecutionCallThreshold.ShouldBe(reducedThreshold);
+
+ {
+ await TestBasicSecurityContractStub.TestWhileInfiniteLoop.SendAsync(new Int32Input
+ { Int32Value = reducedThreshold -1 });
+ var txResult = await TestBasicSecurityContractStub.TestWhileInfiniteLoop.SendWithExceptionAsync(
+ new Int32Input
+ { Int32Value = reducedThreshold });
+ txResult.TransactionResult.Error.ShouldContain(nameof(RuntimeBranchThresholdExceededException));
+ }
+
+ {
+ await TestBasicSecurityContractStub.TestForInfiniteLoop.SendAsync(new Int32Input { Int32Value = reducedThreshold - 1 });
+ var txResult = await TestBasicSecurityContractStub.TestForInfiniteLoop.SendWithExceptionAsync(
+ new Int32Input
+ { Int32Value = reducedThreshold });
+ txResult.TransactionResult.Error.ShouldContain(nameof(RuntimeBranchThresholdExceededException));
+ }
+
+ {
+ await TestBasicSecurityContractStub.TestForInfiniteLoopInSeparateClass.SendAsync(new Int32Input
+ { Int32Value = reducedThreshold - 1 });
+ var txResult = await TestBasicSecurityContractStub.TestForInfiniteLoop.SendWithExceptionAsync(
+ new Int32Input
+ { Int32Value = reducedThreshold });
+ txResult.TransactionResult.Error.ShouldContain(nameof(RuntimeBranchThresholdExceededException));
+ }
+
+ {
+ await TestBasicSecurityContractStub.TestWhileInfiniteLoopWithState.SendAsync(new Int32Input
+ { Int32Value = reducedThreshold - 1 });
+ var txResult =
+ await TestBasicSecurityContractStub.TestWhileInfiniteLoopWithState.SendWithExceptionAsync(
+ new Int32Input
+ { Int32Value = reducedThreshold });
+ txResult.TransactionResult.Error.ShouldContain(nameof(RuntimeBranchThresholdExceededException));
+ }
+
+ {
+ await TestBasicSecurityContractStub.TestForeachInfiniteLoop.SendAsync(new ListInput
+ { List = { new int[reducedThreshold - 1] } });
+ var txResult =
+ await TestBasicSecurityContractStub.TestForeachInfiniteLoop.SendWithExceptionAsync(
+ new ListInput { List = { new int[reducedThreshold] } });
+ txResult.TransactionResult.Error.ShouldContain(nameof(RuntimeBranchThresholdExceededException));
+ }
+ }
+
+ [Fact]
+ public async Task TestMethodCallCountWithReducedThreshold()
+ {
+ // Get required services
+ var blockchainService = Application.ServiceProvider.GetRequiredService();
+ var executionObserverThresholdProvider =
+ Application.ServiceProvider.GetRequiredService();
+
+ // Get current best chain block
+ var bestChainBlock = await blockchainService.GetBestChainLastBlockHeaderAsync();
+ var blockIndex = new BlockIndex
+ {
+ BlockHash = bestChainBlock.GetHash(),
+ BlockHeight = bestChainBlock.Height
+ };
+
+ // Set reduced threshold to 5000
+ const int reducedThreshold = 5000;
+ var newThreshold = new ExecutionObserverThreshold
+ {
+ ExecutionBranchThreshold = reducedThreshold,
+ ExecutionCallThreshold = reducedThreshold
+ };
+ await executionObserverThresholdProvider.SetExecutionObserverThresholdAsync(blockIndex, newThreshold);
+
+ // Verify threshold was set correctly
+ var currentThreshold = executionObserverThresholdProvider.GetExecutionObserverThreshold(blockIndex);
+ currentThreshold.ExecutionBranchThreshold.ShouldBe(reducedThreshold);
+ currentThreshold.ExecutionCallThreshold.ShouldBe(reducedThreshold);
+
+ // Test recursive call with reduced threshold
+ {
+ await TestBasicSecurityContractStub.TestInfiniteRecursiveCall.SendAsync(new Int32Input
+ { Int32Value = reducedThreshold - 100 });
+ var txResult = await TestBasicSecurityContractStub.TestInfiniteRecursiveCall.SendWithExceptionAsync(
+ new Int32Input { Int32Value = reducedThreshold });
+ txResult.TransactionResult.Error.ShouldContain(nameof(RuntimeCallThresholdExceededException));
+ }
+
+ // Test recursive call in separate class with reduced threshold
+ {
+ await TestBasicSecurityContractStub.TestInfiniteRecursiveCallInSeparateClass.SendAsync(new Int32Input
+ { Int32Value = reducedThreshold - 100 });
+ var txResult =
+ await TestBasicSecurityContractStub.TestInfiniteRecursiveCallInSeparateClass.SendWithExceptionAsync(
+ new Int32Input { Int32Value = reducedThreshold });
+ txResult.TransactionResult.Error.ShouldContain(nameof(RuntimeCallThresholdExceededException));
+ }
+ }
}
\ No newline at end of file
diff --git a/test/AElf.Contracts.TokenHolder.Tests/TokenHolderContractTestBase.cs b/test/AElf.Contracts.TokenHolder.Tests/TokenHolderContractTestBase.cs
index e127c3a78b..075588845d 100644
--- a/test/AElf.Contracts.TokenHolder.Tests/TokenHolderContractTestBase.cs
+++ b/test/AElf.Contracts.TokenHolder.Tests/TokenHolderContractTestBase.cs
@@ -35,6 +35,9 @@ public class TokenHolderContractTestBase : ContractTestBase Accounts[1].Address;
protected List UserKeyPairs => Accounts.Skip(2).Take(3).Select(a => a.KeyPair).ToList();
+
+ protected ECKeyPair OtherKeyPair => Accounts[2].KeyPair;
+ protected Address Other => Accounts[2].Address;
protected List UserAddresses =>
UserKeyPairs.Select(k => Address.FromPublicKey(k.PublicKey)).ToList();
@@ -58,6 +61,8 @@ public class TokenHolderContractTestBase : ContractTestBase GetContractZeroTester(StarterKeyPair)
diff --git a/test/AElf.Contracts.TokenHolder.Tests/TokenHolderTests.cs b/test/AElf.Contracts.TokenHolder.Tests/TokenHolderTests.cs
index 68698e8177..2673adde1a 100644
--- a/test/AElf.Contracts.TokenHolder.Tests/TokenHolderTests.cs
+++ b/test/AElf.Contracts.TokenHolder.Tests/TokenHolderTests.cs
@@ -54,10 +54,71 @@ await TokenHolderContractStub.ContributeProfits.SendAsync(new ContributeProfitsI
{
var tokenHolderProfitScheme = await TokenHolderContractStub.GetScheme.CallAsync(Starter);
- tokenHolderProfitScheme.SchemeId.ShouldNotBeNull();
+ var schemeId = tokenHolderProfitScheme.SchemeId;
+ schemeId.ShouldNotBeNull();
+
+ var result = await TokenHolderContractStub.CreateScheme.SendWithExceptionAsync(new CreateTokenHolderProfitSchemeInput
+ {
+ Symbol = "AUG"
+ });
+
+ result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ result.TransactionResult.Error.ShouldContain("Token holder profit scheme already exists");
}
}
+ [Fact]
+ public async Task AddBeneficiaryWithWrongManagerTest()
+ {
+ var symbol = "AUG";
+ var totalSupply = 10000000;
+ var transferAmount = 1000;
+ await StarterCreateIssueAndApproveTokenAsync(symbol, totalSupply, totalSupply);
+ await TokenHolderContractStub.CreateScheme.SendAsync(new CreateTokenHolderProfitSchemeInput
+ {
+ Symbol = symbol
+ });
+
+ await TokenContractStub.Transfer.SendAsync(new TransferInput
+ {
+ To = Other,
+ Amount = transferAmount,
+ Symbol = symbol
+ });
+
+ await OtherTokenHolderContractStub.RegisterForProfits.SendAsync(new RegisterForProfitsInput
+ {
+ SchemeManager = Starter,
+ Amount = 10
+ });
+
+ var tokenHolderProfitScheme = await TokenHolderContractStub.GetScheme.CallAsync(Other);
+ tokenHolderProfitScheme.SchemeId.ShouldBeNull();
+ tokenHolderProfitScheme.Symbol.ShouldBeEmpty();
+
+ tokenHolderProfitScheme = await TokenHolderContractStub.GetScheme.CallAsync(Starter);
+
+ var scheme = await ProfitContractStub.GetScheme.CallAsync(tokenHolderProfitScheme.SchemeId);
+ scheme.TotalShares.ShouldBe(10);
+
+ var result = await OtherTokenHolderContractStub.AddBeneficiary.SendWithExceptionAsync(new AddTokenHolderBeneficiaryInput
+ {
+ Beneficiary = Other,
+ Shares = 100
+ });
+ result.TransactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
+ result.TransactionResult.Error.ShouldContain("Token holder profit scheme not found");
+
+ await TokenHolderContractStub.AddBeneficiary.SendAsync(new AddTokenHolderBeneficiaryInput
+ {
+ Beneficiary = Other,
+ Shares = 100
+ });
+
+ scheme = await ProfitContractStub.GetScheme.CallAsync(tokenHolderProfitScheme.SchemeId);
+ scheme.TotalShares.ShouldBe(110);
+ }
+
[Fact]
public async Task ContributeProfitsTest()
{
@@ -130,7 +191,7 @@ await TokenHolderContractStub.AddBeneficiary.SendAsync(new AddTokenHolderBenefic
{
var originScheme = await ProfitContractStub.GetScheme.CallAsync(tokenHolderProfitScheme.SchemeId);
- originScheme.TotalShares.ShouldBe(newShare);
+ originScheme.TotalShares.ShouldBe(newShare + 1);
}
}