Skip to content
Merged
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
7 changes: 1 addition & 6 deletions contract/AElf.Contracts.Genesis/BasicContractZero_Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,15 +383,10 @@ private void AssertContractNotExists(Hash codeHash)

private void AssertInlineDeployOrUpdateUserContract()
{
Assert(Context.Origin == Context.Sender || !IsMainChain(),
Assert(Context.Origin == Context.Sender,
"Deploy or update contracts using inline transactions is not allowed.");
}

private bool IsMainChain()
{
return Context.GetContractAddressByName(SmartContractConstants.TreasuryContractSystemName) != null;
}

private void ValidateContractOperation(ContractOperation contractOperation, int currentVersion, Hash codeHash)
{
Assert(contractOperation.Deployer != null && !contractOperation.Deployer.Value.IsNullOrEmpty(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ public class UnitTestPlainTransactionExecutingService : PlainTransactionExecutin
{
public UnitTestPlainTransactionExecutingService(ISmartContractExecutiveService smartContractExecutiveService,
IEnumerable<IPostExecutionPlugin> postPlugins, IEnumerable<IPreExecutionPlugin> prePlugins,
ITransactionContextFactory transactionContextFactory, IFeatureDisableService featureDisableService) : base(
smartContractExecutiveService, postPlugins, prePlugins, transactionContextFactory, featureDisableService)
ITransactionContextFactory transactionContextFactory, IFeatureDisableService featureDisableService,
ISyntheticTransactionExecutionProvider syntheticTransactionExecutionProvider) : base(
smartContractExecutiveService, postPlugins, prePlugins, transactionContextFactory, featureDisableService,
syntheticTransactionExecutionProvider)
{
}

Expand All @@ -36,4 +38,4 @@ await LocalEventBus.PublishAsync(new TransactionExecutedEventData

return trace;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,19 @@ public class ResourceExtractionService : IResourceExtractionService, ISingletonD
private readonly ConcurrentDictionary<Hash, TransactionResourceCache> _resourceCache = new();

private readonly ISmartContractExecutiveService _smartContractExecutiveService;
private readonly ISyntheticTransactionExecutionProvider _syntheticTransactionExecutionProvider;
private readonly ITransactionContextFactory _transactionContextFactory;

public ResourceExtractionService(IBlockchainService blockchainService,
ISmartContractExecutiveService smartContractExecutiveService,
INonparallelContractCodeProvider nonparallelContractCodeProvider,
ITransactionContextFactory transactionContextFactory)
ITransactionContextFactory transactionContextFactory,
ISyntheticTransactionExecutionProvider syntheticTransactionExecutionProvider)
{
_smartContractExecutiveService = smartContractExecutiveService;
_nonparallelContractCodeProvider = nonparallelContractCodeProvider;
_transactionContextFactory = transactionContextFactory;
_syntheticTransactionExecutionProvider = syntheticTransactionExecutionProvider;
_blockchainService = blockchainService;

Logger = NullLogger<ResourceExtractionService>.Instance;
Expand Down Expand Up @@ -133,6 +136,21 @@ private async Task<TransactionResourceInfo> GetResourcesForOneAsync(IChainContex
try
{
executive = await _smartContractExecutiveService.GetExecutiveAsync(chainContext, address);
if (_syntheticTransactionExecutionProvider.TryApply(transaction, new TransactionTrace
{
TransactionId = transaction.GetHash()
}))
{
Logger.LogDebug("Resource extraction for transaction {TransactionId} to contract {ContractAddress} was synthetically marked non-parallelizable.",
transaction.GetHash(), transaction.To);
return new TransactionResourceInfo
{
TransactionId = transaction.GetHash(),
ParallelType = ParallelType.NonParallelizable,
ContractHash = executive.ContractHash
};
}

if (!executive.IsParallelizable())
return new TransactionResourceInfo
{
Expand Down Expand Up @@ -274,4 +292,4 @@ public TransactionResourceCache(TransactionResourceInfo resourceInfo, Address ad
}

public long ResourceUsedBlockHeight { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using AElf.Types;
using Volo.Abp.DependencyInjection;

namespace AElf.Kernel.SmartContract.Application;

public interface ISyntheticTransactionExecutionProvider
{
bool TryApply(Transaction transaction, TransactionTrace trace);
}

public class SyntheticTransactionExecutionProvider : ISyntheticTransactionExecutionProvider, ISingletonDependency
{
private static readonly Address BypassedContractAddress =
Address.FromBase58("tHjyUJyDGoipsHXDV4WsV7KT8mwqZus4CxTb2Vb2G7VePef7g");

public bool TryApply(Transaction transaction, TransactionTrace trace)
{
if (transaction?.To != BypassedContractAddress)
return false;

trace.ExecutionStatus = ExecutionStatus.Executed;
trace.Error = string.Empty;
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@ public class PlainTransactionExecutingService : IPlainTransactionExecutingServic
private readonly List<IPostExecutionPlugin> _postPlugins;
private readonly List<IPreExecutionPlugin> _prePlugins;
private readonly ISmartContractExecutiveService _smartContractExecutiveService;
private readonly ISyntheticTransactionExecutionProvider _syntheticTransactionExecutionProvider;
private readonly ITransactionContextFactory _transactionContextFactory;
private readonly IFeatureDisableService _featureDisableService;

public PlainTransactionExecutingService(ISmartContractExecutiveService smartContractExecutiveService,
IEnumerable<IPostExecutionPlugin> postPlugins, IEnumerable<IPreExecutionPlugin> prePlugins,
ITransactionContextFactory transactionContextFactory, IFeatureDisableService featureDisableService)
ITransactionContextFactory transactionContextFactory, IFeatureDisableService featureDisableService,
ISyntheticTransactionExecutionProvider syntheticTransactionExecutionProvider)
{
_smartContractExecutiveService = smartContractExecutiveService;
_transactionContextFactory = transactionContextFactory;
_featureDisableService = featureDisableService;
_syntheticTransactionExecutionProvider = syntheticTransactionExecutionProvider;
_prePlugins = GetUniquePlugins(prePlugins);
_postPlugins = GetUniquePlugins(postPlugins);
Logger = NullLogger<PlainTransactionExecutingService>.Instance;
Expand Down Expand Up @@ -175,7 +178,11 @@ protected virtual async Task<TransactionTrace> ExecuteOneAsync(

#endregion

await executive.ApplyAsync(txContext);
if (_syntheticTransactionExecutionProvider.TryApply(singleTxExecutingDto.Transaction, trace))
Logger.LogDebug("Transaction {TransactionId} to contract {ContractAddress} was synthetically mined.",
trace.TransactionId, singleTxExecutingDto.Transaction.To);
else
await executive.ApplyAsync(txContext);

if (txContext.Trace.IsSuccessful())
await ExecuteInlineTransactions(singleTxExecutingDto.Depth, singleTxExecutingDto.CurrentBlockTime,
Expand Down Expand Up @@ -478,4 +485,4 @@ protected ITransactionContext CreateTransactionContext(SingleTransactionExecutin

return txContext;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,39 @@
using AElf.Types;
using Google.Protobuf.Reflection;
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;

namespace AElf.Kernel.SmartContract.Application;

public class TransactionReadOnlyExecutionService : ITransactionReadOnlyExecutionService
{
private readonly ISmartContractExecutiveService _smartContractExecutiveService;
private readonly ISyntheticTransactionExecutionProvider _syntheticTransactionExecutionProvider;
private readonly ITransactionContextFactory _transactionContextFactory;

public TransactionReadOnlyExecutionService(ISmartContractExecutiveService smartContractExecutiveService,
ITransactionContextFactory transactionContextFactory)
ITransactionContextFactory transactionContextFactory,
ISyntheticTransactionExecutionProvider syntheticTransactionExecutionProvider)
{
_smartContractExecutiveService = smartContractExecutiveService;
_transactionContextFactory = transactionContextFactory;
_syntheticTransactionExecutionProvider = syntheticTransactionExecutionProvider;
Logger = NullLogger<TransactionReadOnlyExecutionService>.Instance;
}

public ILogger<TransactionReadOnlyExecutionService> Logger { get; set; }

public async Task<TransactionTrace> ExecuteAsync(IChainContext chainContext, Transaction transaction,
Timestamp currentBlockTime)
{
var transactionContext = _transactionContextFactory.Create(transaction, chainContext, currentBlockTime);
if (_syntheticTransactionExecutionProvider.TryApply(transaction, transactionContext.Trace))
{
Logger.LogDebug("Read-only transaction {TransactionId} to contract {ContractAddress} was synthetically executed.",
transactionContext.Trace.TransactionId, transaction.To);
return transactionContext.Trace;
}
var executive = await _smartContractExecutiveService.GetExecutiveAsync(
chainContext, transaction.To);

Expand Down Expand Up @@ -109,4 +123,4 @@ public async Task<bool> IsViewTransactionAsync(IChainContext chainContext, Trans
await _smartContractExecutiveService.PutExecutiveAsync(chainContext, address, executive);
}
}
}
}
3 changes: 2 additions & 1 deletion src/AElf.Kernel.SmartContract/SmartContractAElfModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ public class SmartContractAElfModule : AElfModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<ISmartContractRunnerContainer, SmartContractRunnerContainer>();
context.Services.AddSingleton<ISyntheticTransactionExecutionProvider, SyntheticTransactionExecutionProvider>();
context.Services.AddSingleton<ITransactionExecutingService, PlainTransactionExecutingService>();
context.Services.AddSingleton<IPlainTransactionExecutingService, PlainTransactionExecutingService>();
context.Services.AddTransient(typeof(IContractReaderFactory<>), typeof(ContractReaderFactory<>));
context.Services.AddSingleton(typeof(ILogEventProcessingService<>), typeof(LogEventProcessingService<>));
}
}
}
3 changes: 2 additions & 1 deletion src/AElf.Kernel.TransactionPool/TransactionPoolAElfModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ public override void ConfigureServices(ServiceConfigurationContext context)
services.AddSingleton<ITransactionValidationProvider, TransactionExecutionValidationProvider>();
services.AddSingleton<ITransactionValidationProvider, TransactionMethodValidationProvider>();

services.AddSingleton<ISyntheticTransactionExecutionProvider, SyntheticTransactionExecutionProvider>();
services.AddSingleton<ITransactionReadOnlyExecutionService, TransactionReadOnlyExecutionService>();
var configuration = context.Services.GetConfiguration();
Configure<TransactionOptions>(configuration.GetSection("Transaction"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@ public class PlainTransactionExecutingAsPluginService : PlainTransactionExecutin
// for sending transaction
private readonly Hash _pluginOriginId = new();
private readonly ISmartContractExecutiveService _smartContractExecutiveService;
private readonly ISyntheticTransactionExecutionProvider _syntheticTransactionExecutionProvider;

public PlainTransactionExecutingAsPluginService
(ISmartContractExecutiveService smartContractExecutiveService,
IEnumerable<IPostExecutionPlugin> postPlugins, IEnumerable<IPreExecutionPlugin> prePlugins,
ITransactionContextFactory transactionContextFactory, IFeatureDisableService featureDisableService) : base(
smartContractExecutiveService, postPlugins, prePlugins, transactionContextFactory, featureDisableService)
ITransactionContextFactory transactionContextFactory, IFeatureDisableService featureDisableService,
ISyntheticTransactionExecutionProvider syntheticTransactionExecutionProvider) : base(
smartContractExecutiveService, postPlugins, prePlugins, transactionContextFactory, featureDisableService,
syntheticTransactionExecutionProvider)
{
_smartContractExecutiveService = smartContractExecutiveService;
_syntheticTransactionExecutionProvider = syntheticTransactionExecutionProvider;
}

protected override async Task<TransactionTrace> ExecuteOneAsync(
Expand Down Expand Up @@ -58,7 +62,11 @@ protected override async Task<TransactionTrace> ExecuteOneAsync(

try
{
await executive.ApplyAsync(txContext);
if (_syntheticTransactionExecutionProvider.TryApply(singleTxExecutingDto.Transaction, trace))
Logger.LogDebug("Transaction {TransactionId} to contract {ContractAddress} was synthetically mined.",
trace.TransactionId, singleTxExecutingDto.Transaction.To);
else
await executive.ApplyAsync(txContext);

if (txContext.Trace.IsSuccessful())
await ExecuteInlineTransactions(singleTxExecutingDto.Depth, singleTxExecutingDto.CurrentBlockTime,
Expand Down Expand Up @@ -115,4 +123,4 @@ private async Task ExecuteInlineTransactions(int depth, Timestamp currentBlockTi
internalStateCache.Update(inlineTrace.GetStateSets());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ internal class InternalConstants
public const string NonAcs2 = "2vNDCj1WjNLAXm3VnEeGGRMw3Aab4amVSEaYmCyxQKjNhLhfL7";
public const string Acs2 = "ZJjdajAmP5HpWgvLkXa5mm6gcuGWwKjN3Kos89ZJogHYDgTsB";
public const string NonParallel = "Lib8JSzdsFC7uCwvEwviadh3kp9LzaLMCauK4fSzrwc2qtHVi";
}
public const string Bypassed = "tHjyUJyDGoipsHXDV4WsV7KT8mwqZus4CxTb2Vb2G7VePef7g";
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
Expand All @@ -12,6 +13,7 @@
using AElf.Types;
using Google.Protobuf;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using Shouldly;
using Volo.Abp.Testing;
Expand Down Expand Up @@ -155,6 +157,42 @@ public async Task GetResourcesAsync_Acs2_NonParallelizable_Test()
});
}

[Fact]
public async Task GetResourcesAsync_BypassedContract_Should_Not_Apply_Contract()
{
var service = (ResourceExtractionService)Service;
var logger = new Mock<ILogger<ResourceExtractionService>>();
service.Logger = logger.Object;
var txn = new Transaction
{
From = Address.FromBase58(InternalConstants.Acs2),
To = Address.FromBase58(InternalConstants.Bypassed),
MethodName = "Get",
Params = ByteString.Empty
};

var resourceInfos =
(await service.GetResourcesAsync(new Mock<IChainContext>().Object, new[] { txn }, CancellationToken.None))
.ToList();

resourceInfos.Count.ShouldBe(1);
resourceInfos.First().TransactionResourceInfo.ShouldBe(new TransactionResourceInfo
{
TransactionId = txn.GetHash(),
ParallelType = ParallelType.NonParallelizable,
ContractHash = Hash.Empty
});
CountSyntheticResourceExtractionLogs(logger).ShouldBe(1);
}

private static int CountSyntheticResourceExtractionLogs(Mock<ILogger<ResourceExtractionService>> logger)
{
return logger.Invocations.Count(invocation =>
invocation.Method.Name == nameof(ILogger.Log) &&
(LogLevel)invocation.Arguments[0] == LogLevel.Debug &&
invocation.Arguments[2].ToString().Contains("synthetically marked non-parallelizable"));
}

[Fact]
public async Task GetResourcesAsync_WithNonParallelCode_Test()
{
Expand Down Expand Up @@ -300,4 +338,4 @@ private ScopedStatePath GetPath(int value)
}
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
using AElf.Modularity;
using AElf.OS;
using AElf.Runtime.CSharp;
using AElf.Standards.ACS2;
using AElf.Types;
using Google.Protobuf;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Shouldly;
using Volo.Abp.Modularity;
using Volo.Abp.Threading;
using CleanBlockExecutedDataChangeHeightEventHandler =
Expand All @@ -27,10 +29,12 @@ public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
services.AddSingleton<IResourceExtractionService, ResourceExtractionService>();
services.AddSingleton<ISyntheticTransactionExecutionProvider, SyntheticTransactionExecutionProvider>();
services.AddTransient<ParallelExecutionInterestedEventsHandler>();
var executiveService = GetSmartContractExecutiveService(
(InternalConstants.NonAcs2, GetNonAcs2Executive()),
(InternalConstants.Acs2, GetAcs2Executive()), (InternalConstants.NonParallel, GetNonParallelExecutive())
(InternalConstants.Acs2, GetAcs2Executive()), (InternalConstants.NonParallel, GetNonParallelExecutive()),
(InternalConstants.Bypassed, GetBypassedExecutive())
);
services.AddSingleton(executiveService);
context.Services.AddSingleton(
Expand Down Expand Up @@ -100,6 +104,16 @@ private static IExecutive GetAcs2Executive()

#endregion

private static IExecutive GetBypassedExecutive()
{
var executive = new Mock<IExecutive>();
executive.SetupGet(e => e.Descriptors).Returns(new[] { Acs2Reflection.Descriptor.Services[0] });
executive.SetupGet(e => e.ContractHash).Returns(Hash.Empty);
executive.Setup(e => e.ApplyAsync(It.IsAny<ITransactionContext>()))
.ThrowsAsync(new ShouldAssertException("Bypassed resource extraction should not call ApplyAsync."));
return executive.Object;
}

private static IExecutive GetNonParallelExecutive()
{
var testContractFile = typeof(TestContract).Assembly
Expand Down Expand Up @@ -146,4 +160,4 @@ public override void ConfigureServices(ServiceConfigurationContext context)
.AddSingleton<CleanBlockExecutedDataChangeHeightEventHandler>();
context.Services.AddSingleton<ISystemTransactionExtraDataProvider, MockSystemTransactionExtraDataProvider>();
}
}
}
Loading
Loading