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

Remove some settings from policy contract #2300

Merged
merged 9 commits into from
Feb 12, 2021
7 changes: 2 additions & 5 deletions src/neo/Ledger/MemoryPool.cs
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.Plugins;
using Neo.SmartContract.Native;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -368,8 +367,7 @@ internal void UpdatePoolForBlockPersisted(Block block, DataCache snapshot)
if (block.Index > 0 && _system.HeaderCache.Count > 0)
return;

uint _maxTxPerBlock = NativeContract.Policy.GetMaxTransactionsPerBlock(snapshot);
ReverifyTransactions(_sortedTransactions, _unverifiedSortedTransactions, (int)_maxTxPerBlock, MaxMillisecondsToReverifyTx, snapshot);
ReverifyTransactions(_sortedTransactions, _unverifiedSortedTransactions, (int)ProtocolSettings.Default.MaxTransactionsPerBlock, MaxMillisecondsToReverifyTx, snapshot);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we eliminate the use of ProtocolSettings.Default here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be fixed by #2337

}

internal void InvalidateAllTransactions()
@@ -468,8 +466,7 @@ internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, DataCac

if (_unverifiedSortedTransactions.Count > 0)
{
uint _maxTxPerBlock = NativeContract.Policy.GetMaxTransactionsPerBlock(snapshot);
int verifyCount = _sortedTransactions.Count > _maxTxPerBlock ? 1 : maxToVerify;
int verifyCount = _sortedTransactions.Count > ProtocolSettings.Default.MaxTransactionsPerBlock ? 1 : maxToVerify;
ReverifyTransactions(_sortedTransactions, _unverifiedSortedTransactions,
verifyCount, MaxMillisecondsToReverifyTxPerIdle, snapshot);
}
4 changes: 1 addition & 3 deletions src/neo/Network/P2P/Payloads/Block.cs
Original file line number Diff line number Diff line change
@@ -11,8 +11,6 @@ namespace Neo.Network.P2P.Payloads
{
public sealed class Block : IEquatable<Block>, IInventory
{
public const int MaxTransactionsPerBlock = ushort.MaxValue;

public Header Header;
public Transaction[] Transactions;

@@ -33,7 +31,7 @@ public sealed class Block : IEquatable<Block>, IInventory
public void Deserialize(BinaryReader reader)
{
Header = reader.ReadSerializable<Header>();
Transactions = reader.ReadSerializableArray<Transaction>(MaxTransactionsPerBlock);
Transactions = reader.ReadSerializableArray<Transaction>((int)ProtocolSettings.Default.MaxTransactionsPerBlock);
if (Transactions.Distinct().Count() != Transactions.Length)
throw new FormatException();
if (MerkleTree.ComputeRoot(Transactions.Select(p => p.Hash).ToArray()) != Header.MerkleRoot)
2 changes: 1 addition & 1 deletion src/neo/Network/P2P/Payloads/MerkleBlockPayload.cs
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ public static MerkleBlockPayload Create(Block block, BitArray flags)
public void Deserialize(BinaryReader reader)
{
Header = reader.ReadSerializable<Header>();
TxCount = (int)reader.ReadVarInt(Block.MaxTransactionsPerBlock);
TxCount = (int)reader.ReadVarInt(ProtocolSettings.Default.MaxTransactionsPerBlock);
Hashes = reader.ReadSerializableArray<UInt256>(TxCount);
Flags = reader.ReadVarBytes((Math.Max(TxCount, 1) + 7) / 8);
}
2 changes: 0 additions & 2 deletions src/neo/Network/P2P/Payloads/Transaction.cs
Original file line number Diff line number Diff line change
@@ -288,8 +288,6 @@ public virtual VerifyResult VerifyStateDependent(ProtocolSettings settings, Data
foreach (UInt160 hash in hashes)
if (NativeContract.Policy.IsBlocked(snapshot, hash))
return VerifyResult.PolicyFail;
if (NativeContract.Policy.GetMaxBlockSystemFee(snapshot) < SystemFee)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this check is removed, how to stop such transactions from getting into Mempool?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should treat service, storage and CPU fees differently, otherwise the restrictions on fees are meaningless. This can be done later.

return VerifyResult.PolicyFail;
if (!(context?.CheckTransaction(this, snapshot) ?? true)) return VerifyResult.InsufficientFunds;
foreach (TransactionAttribute attribute in Attributes)
if (!attribute.Verify(snapshot, this))
3 changes: 3 additions & 0 deletions src/neo/ProtocolSettings.cs
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ public record ProtocolSettings
public string[] SeedList { get; init; }
public uint MillisecondsPerBlock { get; init; }
public TimeSpan TimePerBlock => TimeSpan.FromMilliseconds(MillisecondsPerBlock);
public uint MaxTransactionsPerBlock { get; init; }
public int MemoryPoolMaxTransactions { get; init; }
public uint MaxTraceableBlocks { get; init; }
public IReadOnlyDictionary<string, uint> NativeActivations { get; init; }
@@ -64,6 +65,7 @@ public record ProtocolSettings
"seed5.neo.org:10333"
},
MillisecondsPerBlock = 15000,
MaxTransactionsPerBlock = 512,
MemoryPoolMaxTransactions = 50_000,
MaxTraceableBlocks = 2_102_400,
NativeActivations = ImmutableDictionary<string, uint>.Empty
@@ -85,6 +87,7 @@ public static ProtocolSettings Load(string path, bool optional = true)
? section.GetSection("SeedList").GetChildren().Select(p => p.Get<string>()).ToArray()
: Default.SeedList,
MillisecondsPerBlock = section.GetValue("MillisecondsPerBlock", Default.MillisecondsPerBlock),
MaxTransactionsPerBlock = section.GetValue("MaxTransactionsPerBlock", Default.MaxTransactionsPerBlock),
MemoryPoolMaxTransactions = section.GetValue("MemoryPoolMaxTransactions", Default.MemoryPoolMaxTransactions),
MaxTraceableBlocks = section.GetValue("MaxTraceableBlocks", Default.MaxTraceableBlocks),
NativeActivations = section.GetSection("NativeActivations").Exists()
56 changes: 3 additions & 53 deletions src/neo/SmartContract/Native/PolicyContract.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#pragma warning disable IDE0051

using Neo.Network.P2P;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using System;
using System.Numerics;
@@ -12,14 +10,11 @@ public sealed class PolicyContract : NativeContract
{
public const uint DefaultExecFeeFactor = 30;
public const uint DefaultStoragePrice = 100000;
private const uint MaxExecFeeFactor = 1000;
private const uint MaxStoragePrice = 10000000;
public const uint MaxExecFeeFactor = 1000;
public const uint MaxStoragePrice = 10000000;

private const byte Prefix_MaxTransactionsPerBlock = 23;
private const byte Prefix_FeePerByte = 10;
private const byte Prefix_BlockedAccount = 15;
private const byte Prefix_MaxBlockSize = 12;
private const byte Prefix_MaxBlockSystemFee = 17;
private const byte Prefix_FeePerByte = 10;
private const byte Prefix_ExecFeeFactor = 18;
private const byte Prefix_StoragePrice = 19;

@@ -29,32 +24,11 @@ internal PolicyContract()

internal override void Initialize(ApplicationEngine engine)
{
engine.Snapshot.Add(CreateStorageKey(Prefix_MaxTransactionsPerBlock), new StorageItem(512));
engine.Snapshot.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem(1000));
engine.Snapshot.Add(CreateStorageKey(Prefix_MaxBlockSize), new StorageItem(1024 * 256));
engine.Snapshot.Add(CreateStorageKey(Prefix_MaxBlockSystemFee), new StorageItem(9000 * GAS.Factor)); // For the transfer method of NEP5, the maximum persisting time is about three seconds.
engine.Snapshot.Add(CreateStorageKey(Prefix_ExecFeeFactor), new StorageItem(DefaultExecFeeFactor));
engine.Snapshot.Add(CreateStorageKey(Prefix_StoragePrice), new StorageItem(DefaultStoragePrice));
}

[ContractMethod(0_01000000, CallFlags.ReadStates)]
public uint GetMaxTransactionsPerBlock(DataCache snapshot)
{
return (uint)(BigInteger)snapshot[CreateStorageKey(Prefix_MaxTransactionsPerBlock)];
}

[ContractMethod(0_01000000, CallFlags.ReadStates)]
public uint GetMaxBlockSize(DataCache snapshot)
{
return (uint)(BigInteger)snapshot[CreateStorageKey(Prefix_MaxBlockSize)];
}

[ContractMethod(0_01000000, CallFlags.ReadStates)]
public long GetMaxBlockSystemFee(DataCache snapshot)
{
return (long)(BigInteger)snapshot[CreateStorageKey(Prefix_MaxBlockSystemFee)];
}

[ContractMethod(0_01000000, CallFlags.ReadStates)]
public long GetFeePerByte(DataCache snapshot)
{
@@ -79,30 +53,6 @@ public bool IsBlocked(DataCache snapshot, UInt160 account)
return snapshot.Contains(CreateStorageKey(Prefix_BlockedAccount).Add(account));
}

[ContractMethod(0_03000000, CallFlags.WriteStates)]
private void SetMaxBlockSize(ApplicationEngine engine, uint value)
{
if (value > Message.PayloadMaxSize) throw new ArgumentOutOfRangeException(nameof(value));
if (!CheckCommittee(engine)) throw new InvalidOperationException();
engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_MaxBlockSize)).Set(value);
}

[ContractMethod(0_03000000, CallFlags.WriteStates)]
private void SetMaxTransactionsPerBlock(ApplicationEngine engine, uint value)
{
if (value > Block.MaxTransactionsPerBlock) throw new ArgumentOutOfRangeException(nameof(value));
if (!CheckCommittee(engine)) throw new InvalidOperationException();
engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_MaxTransactionsPerBlock)).Set(value);
}

[ContractMethod(0_03000000, CallFlags.WriteStates)]
private void SetMaxBlockSystemFee(ApplicationEngine engine, long value)
{
if (value <= 4007600) throw new ArgumentOutOfRangeException(nameof(value));
if (!CheckCommittee(engine)) throw new InvalidOperationException();
engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_MaxBlockSystemFee)).Set(value);
}

[ContractMethod(0_03000000, CallFlags.WriteStates)]
private void SetFeePerByte(ApplicationEngine engine, long value)
{
2 changes: 1 addition & 1 deletion src/neo/SmartContract/Native/TrimmedBlock.cs
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ public class TrimmedBlock : IInteroperable, ISerializable
public void Deserialize(BinaryReader reader)
{
Header = reader.ReadSerializable<Header>();
Hashes = reader.ReadSerializableArray<UInt256>(Block.MaxTransactionsPerBlock);
Hashes = reader.ReadSerializableArray<UInt256>((int)ProtocolSettings.Default.MaxTransactionsPerBlock);
}

public void Serialize(BinaryWriter writer)
157 changes: 1 addition & 156 deletions tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs
Original file line number Diff line number Diff line change
@@ -30,166 +30,11 @@ public void Check_Default()
{
var snapshot = _snapshot.CreateSnapshot();

var ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(512);

ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSize");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(1024 * 256);

ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSystemFee");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(9000 * 100000000L);

ret = NativeContract.Policy.Call(snapshot, "getFeePerByte");
var ret = NativeContract.Policy.Call(snapshot, "getFeePerByte");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(1000);
}

[TestMethod]
public void Check_SetMaxBlockSize()
{
var snapshot = _snapshot.CreateSnapshot();

// Fake blockchain

Block block = new Block()
{
Header = new Header
{
Index = 1000,
PrevHash = UInt256.Zero
}
};
UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot);

// Without signature

Assert.ThrowsException<InvalidOperationException>(() =>
{
NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(null), block,
"setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 });
});

var ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSize");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(1024 * 256);

// More than expected

Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
{
NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block,
"setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = Neo.Network.P2P.Message.PayloadMaxSize + 1 });
});

ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSize");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(1024 * 256);

// With signature

ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block,
"setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 });
ret.IsNull.Should().BeTrue();

ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSize");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(1024);
}

[TestMethod]
public void Check_SetMaxBlockSystemFee()
{
var snapshot = _snapshot.CreateSnapshot();

// Fake blockchain

Block block = new Block()
{
Header = new Header
{
Index = 1000,
PrevHash = UInt256.Zero
}
};
UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot);

// Without signature

Assert.ThrowsException<InvalidOperationException>(() =>
{
NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(null), block,
"setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = 1024 * (long)NativeContract.GAS.Factor });
});

var ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSystemFee");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(9000 * (long)NativeContract.GAS.Factor);

// Less than expected

Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
{
NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block,
"setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = -1000 });
});

ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSystemFee");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(9000 * (long)NativeContract.GAS.Factor);

// With signature

ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block,
"setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = 1024 * (long)NativeContract.GAS.Factor });
ret.IsNull.Should().BeTrue();

ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSystemFee");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(1024 * (long)NativeContract.GAS.Factor);
}

[TestMethod]
public void Check_SetMaxTransactionsPerBlock()
{
var snapshot = _snapshot.CreateSnapshot();

// Fake blockchain

Block block = new Block()
{
Header = new Header
{
Index = 1000,
PrevHash = UInt256.Zero
}
};

// Without signature

Assert.ThrowsException<InvalidOperationException>(() =>
{
NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(), block,
"setMaxTransactionsPerBlock", new ContractParameter(ContractParameterType.Integer) { Value = 1 });
});

var ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(512);

// With signature

ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(NativeContract.NEO.GetCommitteeAddress(snapshot)), block,
"setMaxTransactionsPerBlock", new ContractParameter(ContractParameterType.Integer) { Value = 1 });
ret.IsNull.Should().BeTrue();

ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetInteger().Should().Be(1);
}

[TestMethod]
public void Check_SetFeePerByte()
{