Skip to content

[Add] ApplicationEngineBase Settings, tools and FasterDb store #3810

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

Merged
Merged
141 changes: 141 additions & 0 deletions src/Shared/Neo.Build.Core/Builders/BlockBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright (C) 2015-2025 The Neo Project.
//
// BlockBuilder.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.Build.Core.Factories;
using Neo.Builders;
using Neo.Cryptography;
using Neo.Network.P2P.Payloads;
using System;
using System.Linq;

namespace Neo.Build.Core.Builders
{
public class BlockBuilder
{
private BlockBuilder() { }

private readonly Block _block = new()
{
Header = new()
{
Nonce = RandomFactory.NextUInt64(),
Timestamp = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
MerkleRoot = new(),
NextConsensus = new(),
PrevHash = new(),
Witness = new()
{
InvocationScript = Memory<byte>.Empty,
VerificationScript = Memory<byte>.Empty,
},
},
Transactions = [],
};

public static BlockBuilder Create() =>
new();

public static BlockBuilder CreateNext(Block prevBlock) =>
new BlockBuilder()
.AddPrevHash(prevBlock.Hash)
.AddIndex(prevBlock.Index + 1);

public static BlockBuilder CreateNext(Block prevBlock, ProtocolSettings protocolSettings) =>
new BlockBuilder()
.AddPrevHash(prevBlock.Hash)
.AddIndex(prevBlock.Index + 1)
.AddTimestamp(config => config += protocolSettings.MillisecondsPerBlock);

public BlockBuilder AddIndex(uint index)
{
_block.Header.Index = index;

return this;
}

public BlockBuilder AddPrimaryIndex(byte index)
{
_block.Header.PrimaryIndex = index;

return this;
}

public BlockBuilder AddNextConsensus(UInt160 hash)
{
_block.Header.NextConsensus = hash;

return this;
}

public BlockBuilder AddNonce(ulong nonce)
{
_block.Header.Nonce = nonce;

return this;
}

public BlockBuilder AddPrevHash(UInt256 hash)
{
_block.Header.PrevHash = hash;

return this;
}

public BlockBuilder AddTimestamp(ulong timestamp)
{
_block.Header.Timestamp = timestamp;

return this;
}

public BlockBuilder AddTimestamp(Action<ulong> config)
{
var timestamp = _block.Header.Timestamp;
config(timestamp);
_block.Header.Timestamp = timestamp;

return this;
}

public BlockBuilder AddVersion(uint version)
{
_block.Header.Version = version;

return this;
}

public BlockBuilder AddWitness(Action<WitnessBuilder> config)
{

var wb = WitnessBuilder.CreateEmpty();
config(wb);
_block.Header.Witness = wb.Build();

return this;
}

public BlockBuilder AddTransaction(Action<TransactionBuilder> config)
{

var tx = TransactionBuilder.CreateEmpty();
config(tx);
_block.Transactions = [.. _block.Transactions, tx.Build()];

return this;
}

public Block Build()
{
_block.Header.MerkleRoot = MerkleTree.ComputeRoot([.. _block.Transactions.Select(static s => s.Hash)]);
return _block;
}
}
}
2 changes: 1 addition & 1 deletion src/Shared/Neo.Build.Core/Models/ProtocolOptionsModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ProtocolOptionsModel : JsonModel, IConvertToObject<ProtocolSettings
public ulong InitialGasDistribution { get; set; }

public ProtocolSettings ToObject() =>
ProtocolSettings.Custom with
ProtocolSettings.Default with
{
Network = Network,
AddressVersion = AddressVersion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ public class AppEngineOptionsModel : JsonModel, IConvertToObject<ApplicationEngi
{
public long MaxGas { get; set; }

public StorageSettingsModel? Storage { get; set; }

public ApplicationEngineSettings ToObject() =>
new()
{
MaxGas = MaxGas,
Storage = Storage?.ToObject() ?? new(),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (C) 2015-2025 The Neo Project.
//
// StorageSettingsModel.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.Build.Core.Interfaces;
using Neo.Build.Core.SmartContract;

namespace Neo.Build.Core.Models.SmartContract
{
public class StorageSettingsModel : JsonModel, IConvertToObject<StorageSettings>
{
public TextFormatterType KeyFormat { get; set; }
public TextFormatterType ValueFormat { get; set; }

public StorageSettings ToObject() =>
new()
{
KeyFormat = KeyFormat,
ValueFormat = ValueFormat,
};
}
}
1 change: 1 addition & 0 deletions src/Shared/Neo.Build.Core/Neo.Build.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="9.0.*" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.*" />
<PackageReference Include="Microsoft.FASTER.Core" Version="2.6.*" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2015-2025 The Neo Project.
//
// FasterDbStoreProvider.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.Build.Core.Storage;
using Neo.Persistence;

namespace Neo.Build.Core.Providers.Storage
{
internal class FasterDbStoreProvider : IStoreProvider
{
public string Name => nameof(FasterDbStore);

public IStore GetStore(string path) => new FasterDbStore(path);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@

using Microsoft.Extensions.Logging;
using Neo.Build.Core.Logging;
using Neo.Extensions;
using Neo.SmartContract;
using Neo.SmartContract.Iterators;
using System;
using System.Linq;

namespace Neo.Build.Core.SmartContract
{
Expand Down Expand Up @@ -72,15 +74,15 @@ protected virtual StorageContext SystemStorageAsReadOnly(StorageContext storageC

protected virtual ReadOnlyMemory<byte>? SystemStorageGet(StorageContext storageContext, byte[] key)
{
var keyString = System.Convert.ToBase64String(key);
var keyString = GetStorageKeyValueString(key, _storageSettings.KeyFormat);

_traceLogger.LogInformation(VMEventLog.StorageGet,
"{SysCall} id={Id}, readonly={ReadOnly}, key={Key}",
nameof(System_Storage_Get), storageContext.Id, storageContext.IsReadOnly, keyString);

var result = Get(storageContext, key);
var result = Get(storageContext, key)?.Span.ToArray() ?? [];

var resultString = System.Convert.ToBase64String(result?.Span.ToArray() ?? []);
var resultString = GetStorageKeyValueString(result, _storageSettings.ValueFormat);

_traceLogger.LogInformation(VMEventLog.StorageGet,
"{SysCall} result={Result}",
Expand All @@ -91,7 +93,7 @@ protected virtual StorageContext SystemStorageAsReadOnly(StorageContext storageC

protected virtual IIterator SystemStorageFind(StorageContext storageContext, byte[] prefix, FindOptions options)
{
var prefixString = System.Convert.ToBase64String(prefix);
var prefixString = GetStorageKeyValueString(prefix, _storageSettings.KeyFormat);

_traceLogger.LogInformation(VMEventLog.StorageFind,
"{SysCall} id={Id}, readonly={ReadOnly}, prefix={Prefix}, options={Options}",
Expand All @@ -108,8 +110,8 @@ protected virtual IIterator SystemStorageFind(StorageContext storageContext, byt

protected virtual void SystemStoragePut(StorageContext storageContext, byte[] key, byte[] value)
{
var keyString = System.Convert.ToBase64String(key);
var valueString = System.Convert.ToBase64String(value);
var keyString = GetStorageKeyValueString(key, _storageSettings.KeyFormat);
var valueString = GetStorageKeyValueString(value, _storageSettings.ValueFormat);

_traceLogger.LogInformation(VMEventLog.StoragePut,
"{SysCall} id={Id}, readonly={ReadOnly}, key={Key}, value={Value}",
Expand All @@ -120,13 +122,24 @@ protected virtual void SystemStoragePut(StorageContext storageContext, byte[] ke

protected virtual void SystemStorageDelete(StorageContext storageContext, byte[] key)
{
var keyString = System.Convert.ToBase64String(key);
var keyString = GetStorageKeyValueString(key, _storageSettings.KeyFormat);

_traceLogger.LogInformation(VMEventLog.StorageDelete,
"{SysCall} id={Id}, readonly={ReadOnly}, key={Key}",
nameof(System_Runtime_Platform), storageContext.Id, storageContext.IsReadOnly, keyString);

Delete(storageContext, key);
}

private string GetStorageKeyValueString(byte[] data, TextFormatterType formatter) =>
formatter switch
{
TextFormatterType.HexString => data.ToHexString(),
TextFormatterType.String => _encoding.GetString(data),
TextFormatterType.ArrayString => $"[{string.Join(',', data.Select(static s => s.ToString("x02")))}]",
TextFormatterType.Default or
TextFormatterType.Base64String or
_ => System.Convert.ToBase64String(data),
};
}
}
20 changes: 19 additions & 1 deletion src/Shared/Neo.Build.Core/SmartContract/ApplicationEngineBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ protected ApplicationEngineBase(
ProtocolSettings protocolSettings,
DataCache snapshotCache,
long maxGas,
StorageSettings? storageSettings = null,
TriggerType trigger = TriggerType.Application,
IVerifiable? container = null,
Block? persistingBlock = null,
Expand All @@ -49,6 +50,7 @@ protected ApplicationEngineBase(
_systemCallMethods = systemCallMethods ?? ApplicationEngineFactory.SystemCallBaseServices;
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
_traceLogger = _loggerFactory.CreateLogger(nameof(ApplicationEngine));
_storageSettings = storageSettings ?? new();
}

protected ApplicationEngineBase(
Expand All @@ -65,6 +67,7 @@ protected ApplicationEngineBase(
protocolSettings,
snapshotCache,
engineSettings.MaxGas,
engineSettings.Storage,
trigger,
container,
persistingBlock,
Expand All @@ -86,16 +89,21 @@ protected ApplicationEngineBase(
EncoderFallback = EncoderFallback.ExceptionFallback,
};

private readonly StorageSettings _storageSettings;

public override void Dispose()
{
base.Dispose();
}

public override VMState Execute()
{
ReadOnlyMemory<byte> memoryScript = CurrentContext?.Script ?? ReadOnlyMemory<byte>.Empty;
var scriptString = System.Convert.ToBase64String(memoryScript.Span);

_traceLogger.LogInformation(VMEventLog.Execute,
"Executing container={TxHash}, script={Script}",
ScriptContainer.Hash, CurrentTransaction?.Script);
ScriptContainer?.Hash, scriptString);

var result = base.Execute();

Expand All @@ -118,11 +126,21 @@ public override void LoadContext(ExecutionContext context)
_traceLogger.LogInformation(VMEventLog.Load,
"Loaded name={Name}, hash={ScriptHash}",
contractState.Manifest.Name, contextState.ScriptHash);
else
{
ReadOnlyMemory<byte> memBytes = context.Script;
var scriptString = System.Convert.ToBase64String(memBytes.Span);

_traceLogger.LogInformation(VMEventLog.Load,
"Loaded script={Script}",
scriptString);
}
}

protected override void OnFault(Exception ex)
{
base.OnFault(ex);

_traceLogger.LogError(VMEventLog.Fault, ex,
"{Message}",
ex.InnerException?.Message ?? ex.Message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ namespace Neo.Build.Core.SmartContract
public class ApplicationEngineSettings
{
public long MaxGas { get; internal set; } = (long)BigInteger.Pow(20L, NativeContract.GAS.Decimals);

public StorageSettings Storage { get; set; } = new();
}
}
Loading