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

Set max block size #953

Merged
merged 54 commits into from
Aug 20, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
dfa6dc6
Draft
shargon Jul 24, 2019
d1616d8
Take into account p2p max payload
shargon Jul 24, 2019
89fe5b0
Move max allowed to policy
shargon Jul 25, 2019
0ddf1e9
Check block size on prepResponse
shargon Jul 25, 2019
5d97f71
Change reason
shargon Jul 25, 2019
f622e57
Prevent overflow
shargon Jul 25, 2019
618d2d9
Merge branch 'master' into max-block-size
shargon Jul 25, 2019
4a111bc
Optimization
shargon Jul 26, 2019
a013394
Reduce the length of the array
shargon Jul 26, 2019
94a29dc
Organizing consensus code
vncoelho Jul 30, 2019
dba9733
Revert "Organizing consensus code"
vncoelho Jul 30, 2019
b38c9a7
Remove Policy UT
shargon Jul 31, 2019
643af4d
Merge branch 'master' into max-block-size
shargon Jul 31, 2019
b05fc39
Resolve Policy conflicts
shargon Jul 31, 2019
2d54874
prepare unit test
shargon Jul 31, 2019
3c35703
Small unit test
shargon Jul 31, 2019
63d64c8
More ut
shargon Jul 31, 2019
9419e4a
Add one check
shargon Jul 31, 2019
138a342
Clean using
shargon Jul 31, 2019
5d4ebe8
Organizing consensus and comments
vncoelho Jul 31, 2019
aa6cbee
Split unit test
shargon Aug 2, 2019
bad503f
Merge branch 'master' into max-block-size
shargon Aug 2, 2019
a942fc5
UT check block size
shargon Aug 2, 2019
6821ee5
Clean
shargon Aug 2, 2019
f9dcbeb
Expected witness size
shargon Aug 2, 2019
5ad4500
optimize
erikzhang Aug 5, 2019
33b68c9
Merge branch 'master' into max-block-size
shargon Aug 5, 2019
7209503
Remove fakeWitness
shargon Aug 5, 2019
165fe96
Format comments
shargon Aug 5, 2019
94b8fc9
rename var
shargon Aug 5, 2019
7a26d2e
Add (..)
shargon Aug 5, 2019
2ef7c2f
Remove SetKey method
shargon Aug 6, 2019
1847366
Merge branch 'master' into max-block-size
shargon Aug 6, 2019
7a799db
Centralize expected block size
shargon Aug 6, 2019
13ccd2a
Merge remote-tracking branch 'shargon/max-block-size' into max-block-…
shargon Aug 6, 2019
1dca8d5
Optimize
shargon Aug 6, 2019
dbda619
Fix
shargon Aug 6, 2019
8d385a8
Add one test
shargon Aug 6, 2019
754541a
Merge branch 'master' into max-block-size
lock9 Aug 7, 2019
accbf72
Optimize `EnsureMaxBlockSize()`
erikzhang Aug 8, 2019
b8e80b0
Fix unit tests
shargon Aug 8, 2019
44de151
Rename
shargon Aug 8, 2019
fa5b743
Indent
shargon Aug 8, 2019
a5b1eb3
Merge branch 'master' into max-block-size
erikzhang Aug 9, 2019
f98a40a
Merge branch 'master' into max-block-size
shargon Aug 12, 2019
9aa49b4
Vitor suggestion
shargon Aug 12, 2019
dc9fd12
Merge with Scoped signatures
shargon Aug 12, 2019
e134881
Remove extra line
vncoelho Aug 12, 2019
a9282c0
Revert "Remove extra line"
vncoelho Aug 12, 2019
c7a063e
Remove extra line
vncoelho Aug 12, 2019
863611c
Merge branch 'master' into max-block-size
shargon Aug 12, 2019
396bd1a
Merge branch 'master' into max-block-size
igormcoelho Aug 16, 2019
7b5ebc1
Merge branch 'master' into max-block-size
vncoelho Aug 16, 2019
f42a7c9
Merge branch 'master' into max-block-size
shargon Aug 20, 2019
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
52 changes: 51 additions & 1 deletion neo.UnitTests/UT_Policy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ public void Check_Initialize()

NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue();

(keyCount + 3).Should().Be(snapshot.Storages.GetChangeSet().Count());
(keyCount + 4).Should().Be(snapshot.Storages.GetChangeSet().Count());

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

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

ret = NativeContract.Policy.Call(snapshot, "getFeePerByte");
ret.Should().BeOfType<VM.Types.Integer>();
ret.GetBigInteger().Should().Be(1000);
Expand All @@ -47,6 +51,52 @@ public void Check_Initialize()
((VM.Types.Array)ret).Count.Should().Be(0);
}

[TestMethod]
public void Check_SetMaxBlockSize()
{
var snapshot = Store.GetSnapshot().Clone();

// Fake blockchain

snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero };
snapshot.Blocks.Add(UInt256.Zero, new Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero });

NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue();

// Without signature

var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(null),
"setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 });
ret.Should().BeOfType<VM.Types.Boolean>();
ret.GetBoolean().Should().BeFalse();

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

// More than expected

ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero),
"setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = Network.P2P.Message.PayloadMaxSize });
ret.Should().BeOfType<VM.Types.Boolean>();
ret.GetBoolean().Should().BeFalse();

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

// With signature

ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero),
"setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 });
ret.Should().BeOfType<VM.Types.Boolean>();
ret.GetBoolean().Should().BeTrue();

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

[TestMethod]
public void Check_SetMaxTransactionsPerBlock()
{
Expand Down
1 change: 1 addition & 0 deletions neo/Consensus/ChangeViewReason.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public enum ChangeViewReason : byte
TxNotFound = 0x2,
TxRejectedByPolicy = 0x3,
TxInvalid = 0x4,
BlockRejectedByPolicy = 0x5
shargon marked this conversation as resolved.
Show resolved Hide resolved
}
}
37 changes: 34 additions & 3 deletions neo/Consensus/ConsensusContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,14 +210,45 @@ public ConsensusPayload MakePrepareRequest()
{
shargon marked this conversation as resolved.
Show resolved Hide resolved
byte[] buffer = new byte[sizeof(ulong)];
random.NextBytes(buffer);
Block.ConsensusData.Nonce = BitConverter.ToUInt64(buffer, 0);
shargon marked this conversation as resolved.
Show resolved Hide resolved

IEnumerable<Transaction> memoryPoolTransactions = Blockchain.Singleton.MemPool.GetSortedVerifiedTransactions();
foreach (IPolicyPlugin plugin in Plugin.Policies)
memoryPoolTransactions = plugin.FilterForBlock(memoryPoolTransactions);

List<Transaction> transactions = memoryPoolTransactions.ToList();
TransactionHashes = transactions.Select(p => p.Hash).ToArray();
Transactions = transactions.ToDictionary(p => p.Hash);

uint maxBlockSize;
Transactions = new Dictionary<UInt256, Transaction>();
shargon marked this conversation as resolved.
Show resolved Hide resolved
using (var snapshot = Blockchain.Singleton.GetSnapshot())
shargon marked this conversation as resolved.
Show resolved Hide resolved
{
maxBlockSize = NativeContract.Policy.GetMaxBlockSize(snapshot);
TransactionHashes = new UInt256[NativeContract.Policy.GetMaxTransactionsPerBlock(snapshot)];
}

// Prevent that block exceed the max size

Block.Transactions = new Transaction[0];
var fixedSize = Block.Size + IO.Helper.GetVarSize(TransactionHashes.Length); // ensure that the var size grows without exceed the max size

for (int x = 0, max = Math.Min(Transactions.Count, transactions.Count); x < max; x++)
{
var tx = transactions[x];

// Check if exceed
if (fixedSize + UInt256.Length + tx.Size > maxBlockSize) break;

TransactionHashes[x] = tx.Hash;
Transactions.Add(tx.Hash, tx);
}

// Truncate null values

Array.Resize(ref TransactionHashes, Transactions.Count);

// Create valid request

Block.Timestamp = Math.Max(TimeProvider.Current.UtcNow.ToTimestampMS(), PrevHeader.Timestamp + 1);
Block.ConsensusData.Nonce = BitConverter.ToUInt64(buffer, 0);
return PreparationPayloads[MyIndex] = MakeSignedPayload(new PrepareRequest
{
Timestamp = Block.Timestamp,
Expand Down
14 changes: 14 additions & 0 deletions neo/Consensus/ConsensusService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.Plugins;
using Neo.SmartContract.Native;
using Neo.Wallets;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -79,6 +80,19 @@ private bool AddTransaction(Transaction tx, bool verify)
// previously sent prepare request, then we don't want to send a prepare response.
if (context.IsPrimary || context.WatchOnly) return true;

// Check policy
using (var snapshot = Blockchain.Singleton.GetSnapshot())
shargon marked this conversation as resolved.
Show resolved Hide resolved
{
var block = context.CreateBlock();

if (block.Size > NativeContract.Policy.GetMaxBlockSize(snapshot))
{
Log($"rejected block: {block.Hash}{Environment.NewLine} The size '{block.Size}' exceed the policy", LogLevel.Warning);
RequestChangeView(ChangeViewReason.BlockRejectedByPolicy);
return false;
}
}

// Timeout extension due to prepare response sent
// around 2*15/M=30.0/5 ~ 40% block time (for M=5)
ExtendTimerByFactor(2);
Expand Down
27 changes: 27 additions & 0 deletions neo/SmartContract/Native/PolicyContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public sealed class PolicyContract : NativeContract
private const byte Prefix_MaxTransactionsPerBlock = 23;
private const byte Prefix_FeePerByte = 10;
private const byte Prefix_BlockedAccounts = 15;
private const byte Prefix_MaxBlockSize = 16;

public PolicyContract()
{
Expand All @@ -36,6 +37,10 @@ private bool CheckValidators(ApplicationEngine engine)
internal override bool Initialize(ApplicationEngine engine)
{
if (!base.Initialize(engine)) return false;
engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_MaxBlockSize), new StorageItem
{
Value = BitConverter.GetBytes(1024u * 256u)
});
engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_MaxTransactionsPerBlock), new StorageItem
{
Value = BitConverter.GetBytes(512u)
Expand All @@ -62,6 +67,17 @@ public uint GetMaxTransactionsPerBlock(Snapshot snapshot)
return BitConverter.ToUInt32(snapshot.Storages[CreateStorageKey(Prefix_MaxTransactionsPerBlock)].Value, 0);
}

[ContractMethod(0_01000000, ContractParameterType.Integer, SafeMethod = true)]
private StackItem GetMaxBlockSize(ApplicationEngine engine, VMArray args)
{
return GetMaxBlockSize(engine.Snapshot);
}

public uint GetMaxBlockSize(Snapshot snapshot)
{
return BitConverter.ToUInt32(snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSize)].Value, 0);
}

[ContractMethod(0_01000000, ContractParameterType.Integer, SafeMethod = true)]
private StackItem GetFeePerByte(ApplicationEngine engine, VMArray args)
{
Expand All @@ -84,6 +100,17 @@ public UInt160[] GetBlockedAccounts(Snapshot snapshot)
return snapshot.Storages[CreateStorageKey(Prefix_BlockedAccounts)].Value.AsSerializableArray<UInt160>();
}

[ContractMethod(0_03000000, ContractParameterType.Boolean, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "value" })]
private StackItem SetMaxBlockSize(ApplicationEngine engine, VMArray args)
{
if (!CheckValidators(engine)) return false;
uint value = (uint)args[0].GetBigInteger();
if (Network.P2P.Message.PayloadMaxSize <= value) return false;
StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSize));
storage.Value = BitConverter.GetBytes(value);
return true;
}

[ContractMethod(0_03000000, ContractParameterType.Boolean, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "value" })]
private StackItem SetMaxTransactionsPerBlock(ApplicationEngine engine, VMArray args)
{
Expand Down