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

dBFT 2.0 #547

Merged
merged 31 commits into from
Mar 3, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2c022c7
Add commit phase to consensus algorithm (#534)
erikzhang Jan 14, 2019
0ae8d62
Merge branch 'master' into consensus/improved_dbft
vncoelho Jan 14, 2019
c58cbfd
Minor fix on mempoolVerified
vncoelho Jan 14, 2019
cdedb79
Add MemoryPool Unit tests. Fix bug on initital start of Persisting th…
Jan 16, 2019
c90dec3
Merge branch 'master' into consensus/improved_dbft
Jan 16, 2019
485487f
Merge branch 'master' into consensus/improved_dbft
erikzhang Jan 24, 2019
b207227
Prevent `ConsensusService` from receiving messages before starting (#…
erikzhang Jan 24, 2019
9aa6527
Consensus recovery log (#572)
erikzhang Jan 24, 2019
0855bdc
Combine `ConsensusContext.ChangeView()` and `ConsensusContext.Reset()`
erikzhang Jan 25, 2019
0e87248
Add `PreparationHash` field to `PrepareResponse` to prevent replay at…
erikzhang Jan 27, 2019
bf0ca7c
Fixed a problem where `PrepareResponse.PreparationHash` was not assig…
erikzhang Jan 28, 2019
7304274
Load context from store only when height matches
erikzhang Jan 31, 2019
be37423
Recover nodes requesting ChangeView when possible (#579)
jsolman Feb 16, 2019
98aed4a
Merge branch 'master' into consensus/improved_dbft
erikzhang Feb 16, 2019
bf820d1
Merge branch 'master' into consensus/improved_dbft
erikzhang Feb 17, 2019
5c9568a
Fixes bug in `OnPrepareRequestReceived()`
erikzhang Feb 19, 2019
19ada04
Send `RecoveryMessage` only when `message.NewViewNumber <= context.Vi…
erikzhang Feb 19, 2019
445fa92
Fix and optimize view changing (#590)
erikzhang Feb 19, 2019
3cc0784
Allow to ignore the recovery logs
erikzhang Feb 19, 2019
68322a4
Add `isRecovering` (#594)
erikzhang Feb 20, 2019
2c56c07
Merge branch 'master' into consensus/improved_dbft
erikzhang Feb 21, 2019
2311524
Fix accepting own prepare request (#596)
jsolman Feb 21, 2019
bbcfc68
Pick some changes from #575.
erikzhang Feb 21, 2019
3b27f0a
Fixes `Prefixes`
erikzhang Feb 21, 2019
de64019
Restore transactions from saved consensus context (#598)
erikzhang Feb 22, 2019
eaeb0a5
Refactoring
erikzhang Feb 25, 2019
06dc6b9
AggressiveInlining (#606)
erikzhang Feb 25, 2019
5d5046c
Reset Block reference when consensus context is initialized after blo…
jsolman Feb 25, 2019
b9b595e
Merge branch 'master' into consensus/improved_dbft
erikzhang Feb 26, 2019
91e006c
Change `ConsensusPayload` for compatibility (#609)
erikzhang Feb 26, 2019
335d7b7
Merge branch 'master' into consensus/improved_dbft
erikzhang Mar 1, 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
28 changes: 26 additions & 2 deletions neo.UnitTests/TestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
using Neo.Network.P2P.Payloads;
using Neo.VM;
using System;
using System.Collections.Generic;
using Moq;
using Neo.Persistence;

namespace Neo.UnitTests
{
public static class TestUtils
{
public static readonly Random TestRandom = new Random(1337); // use fixed seed for guaranteed determinism

public static byte[] GetByteArray(int length, byte firstByte)
{
{
byte[] array = new byte[length];
array[0] = firstByte;
for (int i = 1; i < length; i++)
Expand Down Expand Up @@ -95,5 +100,24 @@ private static void setupBlockBaseWithValues(BlockBase bb, UInt256 val256, out U
};
bb.Witness = scriptVal;
}
}

public static Mock<InvocationTransaction> CreateRandomHashInvocationMockTransaction()
{
var mockTx = new Mock<InvocationTransaction>
{
CallBase = true
};
mockTx.Setup(p => p.Verify(It.IsAny<Snapshot>(), It.IsAny<IEnumerable<Transaction>>())).Returns(true);
var tx = mockTx.Object;
var randomBytes = new byte[16];
TestRandom.NextBytes(randomBytes);
tx.Script = randomBytes;
tx.Attributes = new TransactionAttribute[0];
tx.Inputs = new CoinReference[0];
tx.Outputs = new TransactionOutput[0];
tx.Witnesses = new Witness[0];

return mockTx;
}
}
}
101 changes: 95 additions & 6 deletions neo.UnitTests/UT_Consensus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
using Neo.Network.P2P;
using Neo.Network.P2P.Payloads;
using System;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using Neo.Persistence;
using ECPoint = Neo.Cryptography.ECC.ECPoint;

namespace Neo.UnitTests
{
Expand All @@ -28,6 +34,7 @@ public void ConsensusService_Primary_Sends_PrepareRequest_After_OnStart()
TestProbe subscriber = CreateTestProbe();

var mockConsensusContext = new Mock<IConsensusContext>();
var mockStore = new Mock<Store>();

// context.Reset(): do nothing
//mockConsensusContext.Setup(mr => mr.Reset()).Verifiable(); // void
Expand Down Expand Up @@ -99,8 +106,7 @@ public void ConsensusService_Primary_Sends_PrepareRequest_After_OnStart()
Nonce = mockConsensusContext.Object.Nonce,
NextConsensus = mockConsensusContext.Object.NextConsensus,
TransactionHashes = new UInt256[0],
MinerTransaction = minerTx, //(MinerTransaction)Transactions[TransactionHashes[0]],
Signature = new byte[64]//Signatures[MyIndex]
MinerTransaction = minerTx //(MinerTransaction)Transactions[TransactionHashes[0]],
};

ConsensusMessage mprep = prep;
Expand All @@ -123,11 +129,10 @@ public void ConsensusService_Primary_Sends_PrepareRequest_After_OnStart()
// ============================================================================

TestActorRef<ConsensusService> actorConsensus = ActorOfAsTestActorRef<ConsensusService>(
Akka.Actor.Props.Create(() => new ConsensusService(subscriber, subscriber, mockConsensusContext.Object))
Akka.Actor.Props.Create(() => new ConsensusService(subscriber, subscriber, mockStore.Object, mockConsensusContext.Object))
);

Console.WriteLine("will trigger OnPersistCompleted!");

actorConsensus.Tell(new Blockchain.PersistCompleted
{
Block = new Block
Expand All @@ -142,8 +147,10 @@ public void ConsensusService_Primary_Sends_PrepareRequest_After_OnStart()
}
});

//Console.WriteLine("will start consensus!");
//actorConsensus.Tell(new ConsensusService.Start());
// OnPersist will not launch timer, we need OnStart

Console.WriteLine("will start consensus!");
actorConsensus.Tell(new ConsensusService.Start());

Console.WriteLine("OnTimer should expire!");
Console.WriteLine("Waiting for subscriber message!");
Expand All @@ -162,5 +169,87 @@ public void ConsensusService_Primary_Sends_PrepareRequest_After_OnStart()

Assert.AreEqual(1, 1);
}

[TestMethod]
public void TestSerializeAndDeserializeConsensusContext()
{
var consensusContext = new ConsensusContext(null);
consensusContext.State = ConsensusState.CommitSent;
consensusContext.PrevHash = UInt256.Parse("3333333377777777333333337777777733333333777777773333333377777777");
consensusContext.BlockIndex = 1337;
consensusContext.ViewNumber = 2;
consensusContext.Validators = new ECPoint[7]
{
TestUtils.StandbyValidators[0],
ECPoint.Multiply(TestUtils.StandbyValidators[0], new BigInteger(2)),
ECPoint.Multiply(TestUtils.StandbyValidators[0], new BigInteger(3)),
ECPoint.Multiply(TestUtils.StandbyValidators[0], new BigInteger(4)),
ECPoint.Multiply(TestUtils.StandbyValidators[0], new BigInteger(5)),
ECPoint.Multiply(TestUtils.StandbyValidators[0], new BigInteger(6)),
ECPoint.Multiply(TestUtils.StandbyValidators[0], new BigInteger(7)),
};
consensusContext.MyIndex = 3;
consensusContext.PrimaryIndex = 6;
consensusContext.Timestamp = 4244941711;
consensusContext.Nonce = UInt64.MaxValue;
consensusContext.NextConsensus = UInt160.Parse("5555AAAA5555AAAA5555AAAA5555AAAA5555AAAA");
var testTx1 = TestUtils.CreateRandomHashInvocationMockTransaction().Object;
var testTx2 = TestUtils.CreateRandomHashInvocationMockTransaction().Object;

int txCountToInlcude = 256;
consensusContext.TransactionHashes = new UInt256[txCountToInlcude];
Transaction[] txs = new Transaction[txCountToInlcude];
for (int i = 0; i < txCountToInlcude; i++)
{
txs[i] = TestUtils.CreateRandomHashInvocationMockTransaction().Object;
consensusContext.TransactionHashes[i] = txs[i].Hash;
}
// consensusContext.TransactionHashes = new UInt256[2] {testTx1.Hash, testTx2.Hash};
consensusContext.Transactions = txs.ToDictionary(p => p.Hash);

consensusContext.Preparations = new [] {null, null, null, consensusContext.PrevHash, null, null, null };
consensusContext.Commits = new byte[consensusContext.Validators.Length][];
using (SHA256 sha256 = SHA256.Create())
{
consensusContext.Commits[3] = sha256.ComputeHash(testTx1.Hash.ToArray());
consensusContext.Commits[6] = sha256.ComputeHash(testTx2.Hash.ToArray());
}

consensusContext.ExpectedView = new byte[consensusContext.Validators.Length];
consensusContext.ExpectedView[0] = 2;
consensusContext.ExpectedView[1] = 2;
consensusContext.ExpectedView[2] = 1;
consensusContext.ExpectedView[3] = 2;
consensusContext.ExpectedView[4] = 1;
consensusContext.ExpectedView[5] = 1;
consensusContext.ExpectedView[6] = 2;

byte[] serializedContextData = consensusContext.ToArray();

var copiedContext = new ConsensusContext(null);

using (MemoryStream ms = new MemoryStream(serializedContextData, false))
using (BinaryReader reader = new BinaryReader(ms))
{
copiedContext.Deserialize(reader);
}

copiedContext.State.Should().Be(consensusContext.State);
copiedContext.PrevHash.Should().Be(consensusContext.PrevHash);
copiedContext.BlockIndex.Should().Be(consensusContext.BlockIndex);
copiedContext.ViewNumber.Should().Be(consensusContext.ViewNumber);
copiedContext.Validators.ShouldAllBeEquivalentTo(consensusContext.Validators);
copiedContext.MyIndex.Should().Be(consensusContext.MyIndex);
copiedContext.PrimaryIndex.Should().Be(consensusContext.PrimaryIndex);
copiedContext.Timestamp.Should().Be(consensusContext.Timestamp);
copiedContext.Nonce.Should().Be(consensusContext.Nonce);
copiedContext.NextConsensus.Should().Be(consensusContext.NextConsensus);
copiedContext.TransactionHashes.ShouldAllBeEquivalentTo(consensusContext.TransactionHashes);
copiedContext.Transactions.ShouldAllBeEquivalentTo(consensusContext.Transactions);
copiedContext.Transactions.Values.ShouldAllBeEquivalentTo(consensusContext.Transactions.Values);
copiedContext.Preparations.ShouldAllBeEquivalentTo(consensusContext.Preparations);
copiedContext.Commits.ShouldAllBeEquivalentTo(consensusContext.Commits);
copiedContext.ExpectedView.ShouldAllBeEquivalentTo(consensusContext.ExpectedView);
}
}
}
27 changes: 5 additions & 22 deletions neo.UnitTests/UT_MemoryPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public class UT_MemoryPool
{
private static NeoSystem TheNeoSystem;

private readonly Random _random = new Random(1337); // use fixed seed for guaranteed determinism

private MemoryPool _unit;

[TestInitialize]
Expand Down Expand Up @@ -47,7 +45,7 @@ public void TestSetup()

var mockStore = new Mock<Store>();

var defaultTx = CreateRandomHashInvocationMockTransaction().Object;
var defaultTx = TestUtils.CreateRandomHashInvocationMockTransaction().Object;
defaultTx.Outputs = new TransactionOutput[1];
defaultTx.Outputs[0] = new TransactionOutput
{
Expand Down Expand Up @@ -92,22 +90,7 @@ public void TestSetup()
_unit.Count.ShouldBeEquivalentTo(0);
}

private Mock<InvocationTransaction> CreateRandomHashInvocationMockTransaction()
{
var mockTx = new Mock<InvocationTransaction>();
mockTx.CallBase = true;
mockTx.Setup(p => p.Verify(It.IsAny<Snapshot>(), It.IsAny<IEnumerable<Transaction>>())).Returns(true);
var tx = mockTx.Object;
var randomBytes = new byte[16];
_random.NextBytes(randomBytes);
tx.Script = randomBytes;
tx.Attributes = new TransactionAttribute[0];
tx.Inputs = new CoinReference[0];
tx.Outputs = new TransactionOutput[0];
tx.Witnesses = new Witness[0];

return mockTx;
}


long LongRandom(long min, long max, Random rand)
{
Expand All @@ -118,7 +101,7 @@ long LongRandom(long min, long max, Random rand)

private Transaction CreateMockTransactionWithFee(long fee)
{
var mockTx = CreateRandomHashInvocationMockTransaction();
var mockTx = TestUtils.CreateRandomHashInvocationMockTransaction();
mockTx.SetupGet(p => p.NetworkFee).Returns(new Fixed8(fee));
var tx = mockTx.Object;
if (fee > 0)
Expand All @@ -136,12 +119,12 @@ private Transaction CreateMockTransactionWithFee(long fee)

private Transaction CreateMockHighPriorityTransaction()
{
return CreateMockTransactionWithFee(LongRandom(100000, 100000000, _random));
return CreateMockTransactionWithFee(LongRandom(100000, 100000000, TestUtils.TestRandom));
}

private Transaction CreateMockLowPriorityTransaction()
{
long rNetFee = LongRandom(0, 100000, _random);
long rNetFee = LongRandom(0, 100000, TestUtils.TestRandom);
// [0,0.001] GAS a fee lower than the threshold of 0.001 GAS (not enough to be a high priority TX)
return CreateMockTransactionWithFee(rNetFee);
}
Expand Down
25 changes: 25 additions & 0 deletions neo/Consensus/Commit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.IO;

namespace Neo.Consensus
{
internal class Commit : ConsensusMessage
{
public byte[] Signature;

public override int Size => base.Size + Signature.Length;

public Commit() : base(ConsensusMessageType.Commit) { }

public override void Deserialize(BinaryReader reader)
{
base.Deserialize(reader);
Signature = reader.ReadBytes(64);
}

public override void Serialize(BinaryWriter writer)
{
base.Serialize(writer);
writer.Write(Signature);
}
}
}
Loading