From f114093c327669a01f02559f22fdc563d8b2c030 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 5 Jun 2020 16:18:56 +0800 Subject: [PATCH 01/40] don't use snapshot directly in plugin --- src/neo/Ledger/Blockchain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index b10a60e870..4e67789072 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -443,7 +443,7 @@ private void Persist(Block block) } snapshot.BlockHashIndex.GetAndChange().Set(block); foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) - plugin.OnPersist(snapshot, all_application_executed); + plugin.OnPersist(snapshot.Clone(), all_application_executed); snapshot.Commit(); List commitExceptions = null; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) From b05068f00168547f61f7b23afd91945dfadfc950 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 13:15:59 +0800 Subject: [PATCH 02/40] recover --- src/neo/Ledger/Blockchain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 4e67789072..b10a60e870 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -443,7 +443,7 @@ private void Persist(Block block) } snapshot.BlockHashIndex.GetAndChange().Set(block); foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) - plugin.OnPersist(snapshot.Clone(), all_application_executed); + plugin.OnPersist(snapshot, all_application_executed); snapshot.Commit(); List commitExceptions = null; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) From 8594d139d6f46dff28f33ea185bd5daef5b5f5e7 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 14:41:44 +0800 Subject: [PATCH 03/40] consensus state root --- src/neo/Consensus/Commit.cs | 12 ++-- src/neo/Consensus/ConsensusContext.cs | 59 ++++++++++++++++--- src/neo/Consensus/ConsensusService.cs | 21 +++++-- src/neo/Consensus/PrepareRequest.cs | 6 +- .../RecoveryMessage.CommitPayloadCompact.cs | 15 +++-- src/neo/Consensus/RecoveryMessage.cs | 3 +- 6 files changed, 90 insertions(+), 26 deletions(-) diff --git a/src/neo/Consensus/Commit.cs b/src/neo/Consensus/Commit.cs index fce9b8caaf..f635a1a504 100644 --- a/src/neo/Consensus/Commit.cs +++ b/src/neo/Consensus/Commit.cs @@ -5,22 +5,24 @@ namespace Neo.Consensus { public class Commit : ConsensusMessage { - public byte[] Signature; - - public override int Size => base.Size + Signature.Length; + public byte[] BlockSignature; + public byte[] StateRootSignature; + public override int Size => base.Size + BlockSignature.Length + StateRootSignature.Length; public Commit() : base(ConsensusMessageType.Commit) { } public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); - Signature = reader.ReadFixedBytes(64); + BlockSignature = reader.ReadFixedBytes(64); + StateRootSignature = reader.ReadFixedBytes(64); } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); - writer.Write(Signature); + writer.Write(BlockSignature); + writer.Write(StateRootSignature); } } } diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 3d3a4fcb5d..3091ea706e 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -1,18 +1,20 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using Neo; using Neo.Cryptography; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Ledger; +using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; using Neo.Wallets; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; namespace Neo.Consensus { @@ -24,6 +26,8 @@ internal class ConsensusContext : IDisposable, ISerializable private const byte ConsensusStatePrefix = 0xf4; public Block Block; + public UInt256 ProposalStateRoot { get; set; } + public StateRoot StateRoot { get; set; } public byte ViewNumber; public ECPoint[] Validators; public int MyIndex; @@ -88,7 +92,7 @@ public Block CreateBlock() for (int i = 0, j = 0; i < Validators.Length && j < M; i++) { if (CommitPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; - sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().Signature); + sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().BlockSignature); j++; } Block.Witness = sc.GetWitnesses()[0]; @@ -96,6 +100,22 @@ public Block CreateBlock() return Block; } + public StateRoot CreateStateRoot() + { + EnsureStateRoot(); + if (StateRoot == null) return null; + Contract contract = Contract.CreateMultiSigContract(M, Validators); + ContractParametersContext sc = new ContractParametersContext(StateRoot); + for (int i = 0, j = 0; i < Validators.Length && j < M; i++) + { + if (CommitPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; + sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().StateRootSignature); + j++; + } + StateRoot.Witness = sc.GetWitnesses()[0]; + return StateRoot; + } + public void Deserialize(BinaryReader reader) { Reset(0); @@ -106,6 +126,7 @@ public void Deserialize(BinaryReader reader) if (Block.NextConsensus.Equals(UInt160.Zero)) Block.NextConsensus = null; Block.ConsensusData = reader.ReadSerializable(); + ProposalStateRoot.Deserialize(reader); ViewNumber = reader.ReadByte(); TransactionHashes = reader.ReadSerializableArray(); Transaction[] transactions = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); @@ -137,6 +158,20 @@ public Block EnsureHeader() return Block; } + public StateRoot EnsureStateRoot() + { + if (StateRoot is null) + { + StateRoot = new StateRoot() + { + Version = 0, + Index = Block.Index - 1, + Root = ProposalStateRoot + }; + } + return StateRoot; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint GetPrimaryIndex(byte viewNumber) { @@ -176,7 +211,8 @@ public ConsensusPayload MakeCommit() { return CommitPayloads[MyIndex] ?? (CommitPayloads[MyIndex] = MakeSignedPayload(new Commit { - Signature = EnsureHeader().Sign(keyPair) + BlockSignature = EnsureHeader().Sign(keyPair), + StateRootSignature = EnsureStateRoot().Sign(keyPair), })); } @@ -304,7 +340,8 @@ public ConsensusPayload MakePrepareRequest() { Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes + TransactionHashes = TransactionHashes, + ProposalStateRoot = ProposalStateRoot }); } @@ -326,7 +363,8 @@ public ConsensusPayload MakeRecoveryMessage() ViewNumber = ViewNumber, Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes + TransactionHashes = TransactionHashes, + ProposalStateRoot = ProposalStateRoot }; } return MakeSignedPayload(new RecoveryMessage() @@ -399,6 +437,7 @@ public void Reset(byte viewNumber) keyPair = account.GetKey(); break; } + StateRoot = null; } else { @@ -419,6 +458,7 @@ public void Reset(byte viewNumber) TransactionHashes = null; PreparationPayloads = new ConsensusPayload[Validators.Length]; if (MyIndex >= 0) LastSeenMessage[MyIndex] = (int)Block.Index; + ProposalStateRoot = Blockchain.Singleton.GetStateRoot(Block.Index - 1); } public void Save() @@ -433,6 +473,7 @@ public void Serialize(BinaryWriter writer) writer.Write(Block.Timestamp); writer.Write(Block.NextConsensus ?? UInt160.Zero); writer.Write(Block.ConsensusData); + writer.Write(ProposalStateRoot); writer.Write(ViewNumber); writer.Write(TransactionHashes ?? new UInt256[0]); writer.Write(Transactions?.Values.ToArray() ?? new Transaction[0]); diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 26648c4429..bc3b9521c4 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -134,6 +134,9 @@ private void CheckCommits() Block block = context.CreateBlock(); Log($"relay block: height={block.Index} hash={block.Hash} tx={block.Transactions.Length}"); blockchain.Tell(block); + StateRoot root = context.CreateStateRoot(); + Log($"relay state root: height={root.Index} hash={root.Hash} root={root.Root}"); + blockchain.Tell(root); } } @@ -236,12 +239,14 @@ private void OnCommitReceived(ConsensusPayload payload, Commit commit) { Log($"{nameof(OnCommitReceived)}: height={payload.BlockIndex} view={commit.ViewNumber} index={payload.ValidatorIndex} nc={context.CountCommitted} nf={context.CountFailed}"); - byte[] hashData = context.EnsureHeader()?.GetHashData(); - if (hashData == null) + byte[] headerHashData = context.EnsureHeader()?.GetHashData(); + byte[] stateRootHashData = context.EnsureStateRoot()?.GetHashData(); + if (headerHashData == null || stateRootHashData == null) { existingCommitPayload = payload; } - else if (Crypto.VerifySignature(hashData, commit.Signature, context.Validators[payload.ValidatorIndex])) + else if (Crypto.VerifySignature(headerHashData, commit.BlockSignature, context.Validators[payload.ValidatorIndex]) + && Crypto.VerifySignature(stateRootHashData, commit.StateRootSignature, context.Validators[payload.ValidatorIndex])) { existingCommitPayload = payload; CheckCommits(); @@ -425,12 +430,17 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m return; } + if (message.ProposalStateRoot != Blockchain.Singleton.GetStateRoot(context.Block.Index - 1)) + { + Log($"Invalid request: state root incorrect.", LogLevel.Warning); + } // Timeout extension: prepare request has been received with success // around 2*15/M=30.0/5 ~ 40% block time (for M=5) ExtendTimerByFactor(2); context.Block.Timestamp = message.Timestamp; context.Block.ConsensusData.Nonce = message.Nonce; + context.ProposalStateRoot = message.ProposalStateRoot; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); context.SendersFeeMonitor = new SendersFeeMonitor(); @@ -439,10 +449,11 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m if (!context.PreparationPayloads[i].GetDeserializedMessage().PreparationHash.Equals(payload.Hash)) context.PreparationPayloads[i] = null; context.PreparationPayloads[payload.ValidatorIndex] = payload; - byte[] hashData = context.EnsureHeader().GetHashData(); + byte[] headerHashData = context.EnsureHeader().GetHashData(); + byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(hashData, context.CommitPayloads[i].GetDeserializedMessage().Signature, context.Validators[i])) + if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) || !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index 2369b4f9f7..5fb748d643 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -10,11 +10,13 @@ public class PrepareRequest : ConsensusMessage { public ulong Timestamp; public ulong Nonce; + public UInt256 ProposalStateRoot; public UInt256[] TransactionHashes; public override int Size => base.Size - + sizeof(ulong) //Timestamp + + sizeof(ulong) //Timestamp + sizeof(ulong) //Nonce + + UInt256.Length //ProposalStateRoot + TransactionHashes.GetVarSize(); //TransactionHashes public PrepareRequest() @@ -27,6 +29,7 @@ public override void Deserialize(BinaryReader reader) base.Deserialize(reader); Timestamp = reader.ReadUInt64(); Nonce = reader.ReadUInt64(); + ProposalStateRoot = reader.ReadSerializable(); TransactionHashes = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) throw new FormatException(); @@ -37,6 +40,7 @@ public override void Serialize(BinaryWriter writer) base.Serialize(writer); writer.Write(Timestamp); writer.Write(Nonce); + writer.Write(ProposalStateRoot); writer.Write(TransactionHashes); } } diff --git a/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs b/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs index 5d783c6796..2792c50c9e 100644 --- a/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs +++ b/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs @@ -10,20 +10,23 @@ public class CommitPayloadCompact : ISerializable { public byte ViewNumber; public ushort ValidatorIndex; - public byte[] Signature; + public byte[] BlockSignature; + public byte[] StateRootSignature; public byte[] InvocationScript; int ISerializable.Size => sizeof(byte) + //ViewNumber sizeof(ushort) + //ValidatorIndex - Signature.Length + //Signature + BlockSignature.Length + //BlockSignature + StateRootSignature.Length + //StateRootSignature InvocationScript.GetVarSize(); //InvocationScript void ISerializable.Deserialize(BinaryReader reader) { ViewNumber = reader.ReadByte(); ValidatorIndex = reader.ReadUInt16(); - Signature = reader.ReadFixedBytes(64); + BlockSignature = reader.ReadFixedBytes(64); + StateRootSignature = reader.ReadFixedBytes(64); InvocationScript = reader.ReadVarBytes(1024); } @@ -34,7 +37,8 @@ public static CommitPayloadCompact FromPayload(ConsensusPayload payload) { ViewNumber = message.ViewNumber, ValidatorIndex = payload.ValidatorIndex, - Signature = message.Signature, + BlockSignature = message.BlockSignature, + StateRootSignature = message.StateRootSignature, InvocationScript = payload.Witness.InvocationScript }; } @@ -43,7 +47,8 @@ void ISerializable.Serialize(BinaryWriter writer) { writer.Write(ViewNumber); writer.Write(ValidatorIndex); - writer.Write(Signature); + writer.Write(BlockSignature); + writer.Write(StateRootSignature); writer.WriteVarBytes(InvocationScript); } } diff --git a/src/neo/Consensus/RecoveryMessage.cs b/src/neo/Consensus/RecoveryMessage.cs index cadb137b80..01276874c1 100644 --- a/src/neo/Consensus/RecoveryMessage.cs +++ b/src/neo/Consensus/RecoveryMessage.cs @@ -77,7 +77,8 @@ internal ConsensusPayload[] GetCommitPayloadsFromRecoveryMessage(ConsensusContex ConsensusMessage = new Commit { ViewNumber = p.ViewNumber, - Signature = p.Signature + BlockSignature = p.BlockSignature, + StateRootSignature = p.StateRootSignature, }, Witness = new Witness { From 49a0d5e0a84823037430d12792ee489a9da6ef69 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 14:54:19 +0800 Subject: [PATCH 04/40] fix build error --- src/neo/Ledger/Blockchain.state.cs | 12 ++ src/neo/Network/P2P/MessageCommand.cs | 2 + src/neo/Network/P2P/Payloads/InventoryType.cs | 1 + src/neo/Network/P2P/Payloads/StateRoot.cs | 126 ++++++++++++++++++ tests/neo.UnitTests/Consensus/UT_Consensus.cs | 65 ++++++--- 5 files changed, 186 insertions(+), 20 deletions(-) create mode 100644 src/neo/Ledger/Blockchain.state.cs create mode 100644 src/neo/Network/P2P/Payloads/StateRoot.cs diff --git a/src/neo/Ledger/Blockchain.state.cs b/src/neo/Ledger/Blockchain.state.cs new file mode 100644 index 0000000000..a82e4977a1 --- /dev/null +++ b/src/neo/Ledger/Blockchain.state.cs @@ -0,0 +1,12 @@ +using Akka.Actor; + +namespace Neo.Ledger +{ + public sealed partial class Blockchain : UntypedActor + { + public UInt256 GetStateRoot(uint index) + { + return UInt256.Zero; + } + } +} diff --git a/src/neo/Network/P2P/MessageCommand.cs b/src/neo/Network/P2P/MessageCommand.cs index 89c21597cf..1c3ce68659 100644 --- a/src/neo/Network/P2P/MessageCommand.cs +++ b/src/neo/Network/P2P/MessageCommand.cs @@ -40,6 +40,8 @@ public enum MessageCommand : byte Block = 0x2c, [ReflectionCache(typeof(ConsensusPayload))] Consensus = 0x2d, + [ReflectionCache(typeof(StateRoot))] + StateRoot = 0x2e, Reject = 0x2f, //SPV protocol diff --git a/src/neo/Network/P2P/Payloads/InventoryType.cs b/src/neo/Network/P2P/Payloads/InventoryType.cs index 0a1b831d12..9effb99556 100644 --- a/src/neo/Network/P2P/Payloads/InventoryType.cs +++ b/src/neo/Network/P2P/Payloads/InventoryType.cs @@ -4,6 +4,7 @@ public enum InventoryType : byte { TX = MessageCommand.Transaction, Block = MessageCommand.Block, + StateRoot = MessageCommand.StateRoot, Consensus = MessageCommand.Consensus } } diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs new file mode 100644 index 0000000000..9767d4675d --- /dev/null +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -0,0 +1,126 @@ +using Neo.Cryptography; +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.IO; + +namespace Neo.Network.P2P.Payloads +{ + public class StateRoot : ICloneable, IInventory + { + public byte Version; + public uint Index; + public UInt256 Root; + public Witness Witness; + + InventoryType IInventory.InventoryType => InventoryType.StateRoot; + + private UInt256 _hash = null; + + public UInt256 Hash + { + get + { + if (_hash == null) + { + _hash = new UInt256(Crypto.Hash256(this.GetHashData())); + } + return _hash; + } + } + + Witness[] IVerifiable.Witnesses + { + get + { + return new[] { Witness }; + } + set + { + if (value.Length != 1) throw new ArgumentException(); + Witness = value[0]; + } + } + + public int Size => + sizeof(byte) + + sizeof(uint) + + UInt256.Length + + Witness.Size; + + StateRoot ICloneable.Clone() + { + return new StateRoot + { + Version = Version, + Index = Index, + Root = Root, + Witness = Witness, + }; + } + + void ICloneable.FromReplica(StateRoot replica) + { + Version = replica.Version; + Index = replica.Index; + Root = replica.Root; + Witness = replica.Witness; + } + + public void Deserialize(BinaryReader reader) + { + this.DeserializeUnsigned(reader); + Witness = reader.ReadSerializable(); + } + + public void DeserializeUnsigned(BinaryReader reader) + { + Version = reader.ReadByte(); + Index = reader.ReadUInt32(); + Root = reader.ReadSerializable(); + } + + public void Serialize(BinaryWriter writer) + { + this.SerializeUnsigned(writer); + writer.Write(Witness); + } + + public void SerializeUnsigned(BinaryWriter writer) + { + writer.Write(Version); + writer.Write(Index); + writer.Write(Root); + } + + public bool Verify(StoreView snapshot) + { + return this.VerifyWitnesses(snapshot, 1_00000000); + } + + public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) + { + var script_hash = Blockchain.Singleton.GetBlock(Index)?.NextConsensus; + return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; + } + + public byte[] GetMessage() + { + return this.GetHashData(); + } + + public JObject ToJson() + { + var json = new JObject(); + json["version"] = Version; + json["index"] = Index; + json["stateroot"] = Root.ToString(); + json["witness"] = Witness.ToJson(); + return json; + } + } +} diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 86eb6bc8c2..f55b4b4784 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -10,6 +10,7 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Cryptography; @@ -47,7 +48,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm var mockContext = new Mock(mockWallet.Object, Blockchain.Singleton.Store); mockContext.Object.LastSeenMessage = new int[] { 0, 0, 0, 0, 0, 0, 0 }; - + mockContext.Object.ProposalStateRoot = UInt256.Zero; KeyPair[] kp_array = new KeyPair[7] { UT_Crypto.generateKey(32), // not used, kept for index consistency, didactically @@ -283,6 +284,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm var originalBlockHashData = mockContext.Object.Block.GetHashData(); mockContext.Object.Block.NextConsensus = updatedContract.ScriptHash; mockContext.Object.Block.Header.NextConsensus = updatedContract.ScriptHash; + var originalStateRootData = mockContext.Object.EnsureStateRoot().GetHashData(); var originalBlockMerkleRoot = mockContext.Object.Block.MerkleRoot; Console.WriteLine($"\noriginalBlockMerkleRoot: {originalBlockMerkleRoot}"); var updatedBlockHashData = mockContext.Object.Block.GetHashData(); @@ -292,11 +294,11 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("\n\n=========================="); Console.WriteLine("\nBasic commits Signatures verification"); // Basic tests for understanding signatures and ensuring signatures of commits are correct on tests - var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData); - Crypto.VerifySignature(originalBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); - Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeTrue(); + var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData, originalStateRootData); + Crypto.VerifySignature(originalBlockHashData, cm.BlockSignature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, cm.BlockSignature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).BlockSignature, mockContext.Object.Validators[6]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).BlockSignature, mockContext.Object.Validators[6]).Should().BeTrue(); Console.WriteLine("\n=========================="); Console.WriteLine("\n=========================="); @@ -311,7 +313,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(1); Console.WriteLine("\nCN6 simulation time"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData, originalStateRootData)); tempPayloadToBlockAndWait = subscriber.ExpectMsg(); rmPayload = (ConsensusPayload)tempPayloadToBlockAndWait.Inventory; rmm = (RecoveryMessage)rmPayload.ConsensusMessage; @@ -321,7 +323,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(0); Console.WriteLine("\nCN5 simulation time"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData, originalStateRootData)); tempPayloadToBlockAndWait = subscriber.ExpectMsg(); Console.WriteLine("\nAsserting CountCommitted is 4..."); mockContext.Object.CountCommitted.Should().Be(4); @@ -350,6 +352,13 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.Block.PrevHash = UInt256.Zero; //Payload should also be forced, otherwise OnConsensus will not pass commitPayload.PrevHash = UInt256.Zero; + var root = mockContext.Object.EnsureStateRoot(); + var mockRoot = new Mock(); + mockRoot.Object.Version = root.Version; + mockRoot.Object.Index = root.Index; + mockRoot.Object.Root = root.Root; + mockRoot.Setup(p => p.GetScriptHashesForVerifying(It.IsAny())).Returns(p => new UInt160[] { updatedContract.ScriptHash }); + mockContext.Object.StateRoot = mockRoot.Object; Console.WriteLine($"\nNew Hash is {mockContext.Object.Block.GetHashData().ToScriptHash()}"); Console.WriteLine($"\nForcing block VerificationScript to {updatedContract.Script.ToScriptHash()}"); // The default behavior for BlockBase, when PrevHash = UInt256.Zero, is to use its own Witness @@ -359,10 +368,11 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"\nNew Hash is {mockContext.Object.Block.GetHashData().ToScriptHash()}"); Console.WriteLine("\nCN4 simulation time - Final needed signatures"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 3, kp_array[3], mockContext.Object.Block.GetHashData())); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 3, kp_array[3], mockContext.Object.Block.GetHashData(), originalStateRootData)); Console.WriteLine("\nWait for subscriber Block"); var utBlock = subscriber.ExpectMsg(); + var stateroot = subscriber.ExpectMsg(); Console.WriteLine("\nAsserting CountCommitted is 5..."); mockContext.Object.CountCommitted.Should().Be(5); @@ -377,7 +387,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.Block.Transactions = null; // ensuring same hash as snapshot mockContext.Object.Block.PrevHash = oldPrevHash; - Console.WriteLine("\nAsserting CountCommitted is 0..."); mockContext.Object.CountCommitted.Should().Be(0); Console.WriteLine($"\nAsserting CountFailed is 0..."); @@ -427,7 +436,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm /// new ValidatorIndex for the cpToCopy /// KeyPair that will be used for signing the Commit message used for creating blocks /// HashCode of the Block that is being produced and current being signed - public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload cpToCopy, ushort vI, KeyPair kp, byte[] blockHashToSign) + public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload cpToCopy, ushort vI, KeyPair kp, byte[] blockHashToSign, byte[] rootHashToSign) { var cpCommitTemp = cpToCopy.ToArray().AsSerializable(); cpCommitTemp.ValidatorIndex = vI; @@ -435,7 +444,8 @@ public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload c cpCommitTemp.ConsensusMessage = new Commit { ViewNumber = oldViewNumber, - Signature = Crypto.Sign(blockHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false).Skip(1).ToArray()) + BlockSignature = Crypto.Sign(blockHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false)[1..]), + StateRootSignature = Crypto.Sign(rootHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false)[1..]), }; SignPayload(cpCommitTemp, kp); return cpCommitTemp; @@ -486,6 +496,7 @@ public void TestSerializeAndDeserializeConsensusContext() } }, ViewNumber = 2, + ProposalStateRoot = UInt256.Zero, Validators = new ECPoint[7] { ECPoint.Parse("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", Neo.Cryptography.ECC.ECCurve.Secp256r1), @@ -517,7 +528,8 @@ public void TestSerializeAndDeserializeConsensusContext() var prepareRequestMessage = new PrepareRequest { TransactionHashes = consensusContext.TransactionHashes, - Timestamp = 23 + Timestamp = 23, + ProposalStateRoot = UInt256.Zero }; consensusContext.PreparationPayloads[6] = MakeSignedPayload(consensusContext, prepareRequestMessage, 6, new[] { (byte)'3', (byte)'!' }); consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 0, new[] { (byte)'t', (byte)'e' }); @@ -530,8 +542,16 @@ public void TestSerializeAndDeserializeConsensusContext() consensusContext.CommitPayloads = new ConsensusPayload[consensusContext.Validators.Length]; using (SHA256 sha256 = SHA256.Create()) { - consensusContext.CommitPayloads[3] = MakeSignedPayload(consensusContext, new Commit { Signature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() }, 3, new[] { (byte)'3', (byte)'4' }); - consensusContext.CommitPayloads[6] = MakeSignedPayload(consensusContext, new Commit { Signature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx2.Hash.ToArray())).ToArray() }, 3, new[] { (byte)'6', (byte)'7' }); + consensusContext.CommitPayloads[3] = MakeSignedPayload(consensusContext, new Commit + { + BlockSignature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray(), + StateRootSignature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() + }, 3, new[] { (byte)'3', (byte)'4' }); + consensusContext.CommitPayloads[6] = MakeSignedPayload(consensusContext, new Commit + { + BlockSignature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx2.Hash.ToArray())).ToArray(), + StateRootSignature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() + }, 3, new[] { (byte)'6', (byte)'7' }); } consensusContext.Block.Timestamp = TimeProvider.Current.UtcNow.ToTimestampMS(); @@ -711,7 +731,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR }, PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray() + TransactionHashes = txs.Select(p => p.Hash).ToArray(), + ProposalStateRoot = UInt256.Zero }, PreparationHash = new UInt256(Crypto.Hash256(new[] { (byte)'a' })), PreparationMessages = new Dictionary() @@ -764,7 +785,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray() + TransactionHashes = txs.Select(p => p.Hash).ToArray(), + ProposalStateRoot = UInt256.Zero }, PreparationMessages = new Dictionary() { @@ -824,7 +846,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray() + TransactionHashes = txs.Select(p => p.Hash).ToArray(), + ProposalStateRoot = UInt256.Zero }, PreparationMessages = new Dictionary() { @@ -868,7 +891,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.CommitPayloadCompact { ValidatorIndex = 1, - Signature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + BlockSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + StateRootSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, InvocationScript = new[] { (byte)'1', (byte)'2' } } }, @@ -877,7 +901,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.CommitPayloadCompact { ValidatorIndex = 6, - Signature = new byte[64] { (byte)'3', (byte)'D', (byte)'R', (byte)'I', (byte)'N', (byte)'K', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + BlockSignature = new byte[64] { (byte)'3', (byte)'D', (byte)'R', (byte)'I', (byte)'N', (byte)'K', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + StateRootSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, InvocationScript = new[] { (byte)'6', (byte)'7' } } } From 345f5810b6b78d2401147474d6cbc5f32f2564cd Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 15:09:16 +0800 Subject: [PATCH 05/40] rename --- src/neo/Consensus/ConsensusContext.cs | 2 +- src/neo/Consensus/ConsensusService.cs | 2 +- src/neo/Ledger/Blockchain.state.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 3091ea706e..c16d26785b 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -458,7 +458,7 @@ public void Reset(byte viewNumber) TransactionHashes = null; PreparationPayloads = new ConsensusPayload[Validators.Length]; if (MyIndex >= 0) LastSeenMessage[MyIndex] = (int)Block.Index; - ProposalStateRoot = Blockchain.Singleton.GetStateRoot(Block.Index - 1); + ProposalStateRoot = Blockchain.Singleton.GetLocalStateRoot(Block.Index - 1); } public void Save() diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index bc3b9521c4..0b06dab2f0 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -430,7 +430,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m return; } - if (message.ProposalStateRoot != Blockchain.Singleton.GetStateRoot(context.Block.Index - 1)) + if (message.ProposalStateRoot != Blockchain.Singleton.GetLocalStateRoot(context.Block.Index - 1)) { Log($"Invalid request: state root incorrect.", LogLevel.Warning); } diff --git a/src/neo/Ledger/Blockchain.state.cs b/src/neo/Ledger/Blockchain.state.cs index a82e4977a1..9c1a7eb479 100644 --- a/src/neo/Ledger/Blockchain.state.cs +++ b/src/neo/Ledger/Blockchain.state.cs @@ -4,7 +4,7 @@ namespace Neo.Ledger { public sealed partial class Blockchain : UntypedActor { - public UInt256 GetStateRoot(uint index) + public UInt256 GetLocalStateRoot(uint index) { return UInt256.Zero; } From 237622f5587aac35b4cac390fa2732da2776dd59 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 18:19:30 +0800 Subject: [PATCH 06/40] remerge --- src/neo/Network/P2P/Payloads/StateRoot.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 9767d4675d..301b7af32f 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -47,10 +47,10 @@ Witness[] IVerifiable.Witnesses } public int Size => - sizeof(byte) + - sizeof(uint) + - UInt256.Length + - Witness.Size; + sizeof(byte) + //Version + sizeof(uint) + //Index + UInt256.Length + //Root + Witness.Size; //Witness StateRoot ICloneable.Clone() { From 459f2a00ccb693de2ef6fc295e28599f303e9040 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 18:24:39 +0800 Subject: [PATCH 07/40] rm GetMessage --- src/neo/Network/P2P/Payloads/StateRoot.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 301b7af32f..e375c6c472 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -108,11 +108,6 @@ public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; } - public byte[] GetMessage() - { - return this.GetHashData(); - } - public JObject ToJson() { var json = new JObject(); From 2bacc69bd15813090bdc5543dbc36211c766fb91 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 16 Jun 2020 10:48:42 +0800 Subject: [PATCH 08/40] rename --- src/neo/Consensus/ConsensusContext.cs | 4 ++-- src/neo/Consensus/ConsensusService.cs | 4 ++-- src/neo/Consensus/PrepareRequest.cs | 6 +++--- src/neo/Network/P2P/Payloads/StateRoot.cs | 1 + tests/neo.UnitTests/Consensus/UT_Consensus.cs | 8 ++++---- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index c16d26785b..2dba033c47 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -341,7 +341,7 @@ public ConsensusPayload MakePrepareRequest() Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, TransactionHashes = TransactionHashes, - ProposalStateRoot = ProposalStateRoot + PreviousBlockStateRoot = ProposalStateRoot }); } @@ -364,7 +364,7 @@ public ConsensusPayload MakeRecoveryMessage() Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, TransactionHashes = TransactionHashes, - ProposalStateRoot = ProposalStateRoot + PreviousBlockStateRoot = ProposalStateRoot }; } return MakeSignedPayload(new RecoveryMessage() diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 0b06dab2f0..171e8db952 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -430,7 +430,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m return; } - if (message.ProposalStateRoot != Blockchain.Singleton.GetLocalStateRoot(context.Block.Index - 1)) + if (message.PreviousBlockStateRoot != Blockchain.Singleton.GetLocalStateRoot(context.Block.Index - 1)) { Log($"Invalid request: state root incorrect.", LogLevel.Warning); } @@ -440,7 +440,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m context.Block.Timestamp = message.Timestamp; context.Block.ConsensusData.Nonce = message.Nonce; - context.ProposalStateRoot = message.ProposalStateRoot; + context.ProposalStateRoot = message.PreviousBlockStateRoot; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); context.SendersFeeMonitor = new SendersFeeMonitor(); diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index 5fb748d643..460dc4c125 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -10,7 +10,7 @@ public class PrepareRequest : ConsensusMessage { public ulong Timestamp; public ulong Nonce; - public UInt256 ProposalStateRoot; + public UInt256 PreviousBlockStateRoot; public UInt256[] TransactionHashes; public override int Size => base.Size @@ -29,7 +29,7 @@ public override void Deserialize(BinaryReader reader) base.Deserialize(reader); Timestamp = reader.ReadUInt64(); Nonce = reader.ReadUInt64(); - ProposalStateRoot = reader.ReadSerializable(); + PreviousBlockStateRoot = reader.ReadSerializable(); TransactionHashes = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) throw new FormatException(); @@ -40,7 +40,7 @@ public override void Serialize(BinaryWriter writer) base.Serialize(writer); writer.Write(Timestamp); writer.Write(Nonce); - writer.Write(ProposalStateRoot); + writer.Write(PreviousBlockStateRoot); writer.Write(TransactionHashes); } } diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index e375c6c472..3456a965e6 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -17,6 +17,7 @@ public class StateRoot : ICloneable, IInventory public UInt256 Root; public Witness Witness; + InventoryType IInventory.InventoryType => InventoryType.StateRoot; private UInt256 _hash = null; diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index f55b4b4784..7ea0152799 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -529,7 +529,7 @@ public void TestSerializeAndDeserializeConsensusContext() { TransactionHashes = consensusContext.TransactionHashes, Timestamp = 23, - ProposalStateRoot = UInt256.Zero + PreviousBlockStateRoot = UInt256.Zero }; consensusContext.PreparationPayloads[6] = MakeSignedPayload(consensusContext, prepareRequestMessage, 6, new[] { (byte)'3', (byte)'!' }); consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 0, new[] { (byte)'t', (byte)'e' }); @@ -732,7 +732,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR PrepareRequestMessage = new PrepareRequest { TransactionHashes = txs.Select(p => p.Hash).ToArray(), - ProposalStateRoot = UInt256.Zero + PreviousBlockStateRoot = UInt256.Zero }, PreparationHash = new UInt256(Crypto.Hash256(new[] { (byte)'a' })), PreparationMessages = new Dictionary() @@ -786,7 +786,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC PrepareRequestMessage = new PrepareRequest { TransactionHashes = txs.Select(p => p.Hash).ToArray(), - ProposalStateRoot = UInt256.Zero + PreviousBlockStateRoot = UInt256.Zero }, PreparationMessages = new Dictionary() { @@ -847,7 +847,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm PrepareRequestMessage = new PrepareRequest { TransactionHashes = txs.Select(p => p.Hash).ToArray(), - ProposalStateRoot = UInt256.Zero + PreviousBlockStateRoot = UInt256.Zero }, PreparationMessages = new Dictionary() { From 58fb74f9956a9c587d59af350c7e74facaee8f9c Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 16 Jun 2020 11:21:50 +0800 Subject: [PATCH 09/40] throw exception when no script hash in state root --- src/neo/Network/P2P/Payloads/StateRoot.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 3456a965e6..4b23d19dbc 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -106,7 +106,8 @@ public bool Verify(StoreView snapshot) public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { var script_hash = Blockchain.Singleton.GetBlock(Index)?.NextConsensus; - return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; + if (script_hash is null) throw new System.InvalidOperationException("No script hash for state root verifying"); + return new UInt160[] { script_hash }; } public JObject ToJson() From ba1f1434f2017f8d8b727075c7bedee62afa5ae0 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 16 Jun 2020 09:13:44 +0200 Subject: [PATCH 10/40] Clean double enter --- src/neo/Network/P2P/Payloads/StateRoot.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 4b23d19dbc..5e7d2f57fa 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -17,7 +17,6 @@ public class StateRoot : ICloneable, IInventory public UInt256 Root; public Witness Witness; - InventoryType IInventory.InventoryType => InventoryType.StateRoot; private UInt256 _hash = null; From 9526939198128d821238ec817f9a18e0ab975948 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 16 Jun 2020 09:14:58 +0200 Subject: [PATCH 11/40] Clean big line --- src/neo/Consensus/ConsensusService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 171e8db952..8519f34450 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -453,7 +453,8 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) || !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) + if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) || + !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) From 9fb7143e2cbf61eb6375c66098dc23af1317cfe3 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 16 Jun 2020 15:34:15 +0800 Subject: [PATCH 12/40] format --- src/neo/Consensus/ConsensusService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 8519f34450..155cadaa80 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -453,8 +453,8 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) || - !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) + if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) + || !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) From b6ecba730a073c4d031a6884a7c95986ee6bc944 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Wed, 17 Jun 2020 19:00:16 +0800 Subject: [PATCH 13/40] put root sig into request and response --- src/neo/Consensus/Commit.cs | 12 +- src/neo/Consensus/ConsensusContext.cs | 59 +++--- src/neo/Consensus/ConsensusService.cs | 36 ++-- src/neo/Consensus/PrepareRequest.cs | 10 +- src/neo/Consensus/PrepareResponse.cs | 6 +- .../RecoveryMessage.CommitPayloadCompact.cs | 15 +- ...coveryMessage.PreparationPayloadCompact.cs | 12 +- src/neo/Consensus/RecoveryMessage.cs | 6 +- src/neo/Network/P2P/Payloads/StateRoot.cs | 25 +-- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 169 ++++++++++-------- 10 files changed, 187 insertions(+), 163 deletions(-) diff --git a/src/neo/Consensus/Commit.cs b/src/neo/Consensus/Commit.cs index f635a1a504..fce9b8caaf 100644 --- a/src/neo/Consensus/Commit.cs +++ b/src/neo/Consensus/Commit.cs @@ -5,24 +5,22 @@ namespace Neo.Consensus { public class Commit : ConsensusMessage { - public byte[] BlockSignature; - public byte[] StateRootSignature; - public override int Size => base.Size + BlockSignature.Length + StateRootSignature.Length; + 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); - BlockSignature = reader.ReadFixedBytes(64); - StateRootSignature = reader.ReadFixedBytes(64); + Signature = reader.ReadFixedBytes(64); } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); - writer.Write(BlockSignature); - writer.Write(StateRootSignature); + writer.Write(Signature); } } } diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 2dba033c47..ff0fbbadbf 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -1,20 +1,18 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using Neo; using Neo.Cryptography; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Ledger; -using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; namespace Neo.Consensus { @@ -26,8 +24,7 @@ internal class ConsensusContext : IDisposable, ISerializable private const byte ConsensusStatePrefix = 0xf4; public Block Block; - public UInt256 ProposalStateRoot { get; set; } - public StateRoot StateRoot { get; set; } + public StateRoot PreviousBlockStateRoot; public byte ViewNumber; public ECPoint[] Validators; public int MyIndex; @@ -92,7 +89,7 @@ public Block CreateBlock() for (int i = 0, j = 0; i < Validators.Length && j < M; i++) { if (CommitPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; - sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().BlockSignature); + sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().Signature); j++; } Block.Witness = sc.GetWitnesses()[0]; @@ -102,18 +99,20 @@ public Block CreateBlock() public StateRoot CreateStateRoot() { - EnsureStateRoot(); - if (StateRoot == null) return null; + EnsureHeader(); Contract contract = Contract.CreateMultiSigContract(M, Validators); - ContractParametersContext sc = new ContractParametersContext(StateRoot); + ContractParametersContext sc = new ContractParametersContext(PreviousBlockStateRoot); for (int i = 0, j = 0; i < Validators.Length && j < M; i++) { - if (CommitPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; - sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().StateRootSignature); + if (PreparationPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; + if (i == GetPrimaryIndex(ViewNumber)) + sc.AddSignature(contract, Validators[i], PreparationPayloads[i].GetDeserializedMessage().StateRootSignature); + else + sc.AddSignature(contract, Validators[i], PreparationPayloads[i].GetDeserializedMessage().StateRootSignature); j++; } - StateRoot.Witness = sc.GetWitnesses()[0]; - return StateRoot; + PreviousBlockStateRoot.Witness = sc.GetWitnesses()[0]; + return PreviousBlockStateRoot; } public void Deserialize(BinaryReader reader) @@ -126,7 +125,6 @@ public void Deserialize(BinaryReader reader) if (Block.NextConsensus.Equals(UInt160.Zero)) Block.NextConsensus = null; Block.ConsensusData = reader.ReadSerializable(); - ProposalStateRoot.Deserialize(reader); ViewNumber = reader.ReadByte(); TransactionHashes = reader.ReadSerializableArray(); Transaction[] transactions = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); @@ -160,16 +158,16 @@ public Block EnsureHeader() public StateRoot EnsureStateRoot() { - if (StateRoot is null) + if (PreviousBlockStateRoot is null) { - StateRoot = new StateRoot() + PreviousBlockStateRoot = new StateRoot { Version = 0, Index = Block.Index - 1, - Root = ProposalStateRoot + RootHash = Blockchain.Singleton.GetLocalStateRoot(Block.Index - 1) }; } - return StateRoot; + return PreviousBlockStateRoot; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -211,8 +209,7 @@ public ConsensusPayload MakeCommit() { return CommitPayloads[MyIndex] ?? (CommitPayloads[MyIndex] = MakeSignedPayload(new Commit { - BlockSignature = EnsureHeader().Sign(keyPair), - StateRootSignature = EnsureStateRoot().Sign(keyPair), + Signature = EnsureHeader().Sign(keyPair) })); } @@ -340,8 +337,8 @@ public ConsensusPayload MakePrepareRequest() { Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes, - PreviousBlockStateRoot = ProposalStateRoot + StateRootSignature = EnsureStateRoot().Sign(keyPair), + TransactionHashes = TransactionHashes }); } @@ -363,8 +360,7 @@ public ConsensusPayload MakeRecoveryMessage() ViewNumber = ViewNumber, Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes, - PreviousBlockStateRoot = ProposalStateRoot + TransactionHashes = TransactionHashes }; } return MakeSignedPayload(new RecoveryMessage() @@ -384,7 +380,8 @@ public ConsensusPayload MakePrepareResponse() { return PreparationPayloads[MyIndex] = MakeSignedPayload(new PrepareResponse { - PreparationHash = PreparationPayloads[Block.ConsensusData.PrimaryIndex].Hash + PreparationHash = PreparationPayloads[Block.ConsensusData.PrimaryIndex].Hash, + StateRootSignature = EnsureStateRoot().Sign(keyPair) }); } @@ -437,7 +434,7 @@ public void Reset(byte viewNumber) keyPair = account.GetKey(); break; } - StateRoot = null; + PreviousBlockStateRoot = null; } else { @@ -458,7 +455,6 @@ public void Reset(byte viewNumber) TransactionHashes = null; PreparationPayloads = new ConsensusPayload[Validators.Length]; if (MyIndex >= 0) LastSeenMessage[MyIndex] = (int)Block.Index; - ProposalStateRoot = Blockchain.Singleton.GetLocalStateRoot(Block.Index - 1); } public void Save() @@ -473,7 +469,6 @@ public void Serialize(BinaryWriter writer) writer.Write(Block.Timestamp); writer.Write(Block.NextConsensus ?? UInt160.Zero); writer.Write(Block.ConsensusData); - writer.Write(ProposalStateRoot); writer.Write(ViewNumber); writer.Write(TransactionHashes ?? new UInt256[0]); writer.Write(Transactions?.Values.ToArray() ?? new Transaction[0]); diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 155cadaa80..2a93ebeef1 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -134,9 +134,6 @@ private void CheckCommits() Block block = context.CreateBlock(); Log($"relay block: height={block.Index} hash={block.Hash} tx={block.Transactions.Length}"); blockchain.Tell(block); - StateRoot root = context.CreateStateRoot(); - Log($"relay state root: height={root.Index} hash={root.Hash} root={root.Root}"); - blockchain.Tell(root); } } @@ -168,6 +165,10 @@ private void CheckPreparations() localNode.Tell(new LocalNode.SendDirectly { Inventory = payload }); // Set timer, so we will resend the commit in case of a networking issue ChangeTimer(TimeSpan.FromMilliseconds(Blockchain.MillisecondsPerBlock)); + + StateRoot stateRoot = context.CreateStateRoot(); + Log($"relay state root, index={stateRoot.Index}, root_hash={stateRoot.RootHash}"); + blockchain.Tell(stateRoot); CheckCommits(); } } @@ -239,14 +240,12 @@ private void OnCommitReceived(ConsensusPayload payload, Commit commit) { Log($"{nameof(OnCommitReceived)}: height={payload.BlockIndex} view={commit.ViewNumber} index={payload.ValidatorIndex} nc={context.CountCommitted} nf={context.CountFailed}"); - byte[] headerHashData = context.EnsureHeader()?.GetHashData(); - byte[] stateRootHashData = context.EnsureStateRoot()?.GetHashData(); - if (headerHashData == null || stateRootHashData == null) + byte[] hashData = context.EnsureHeader()?.GetHashData(); + if (hashData == null) { existingCommitPayload = payload; } - else if (Crypto.VerifySignature(headerHashData, commit.BlockSignature, context.Validators[payload.ValidatorIndex]) - && Crypto.VerifySignature(stateRootHashData, commit.StateRootSignature, context.Validators[payload.ValidatorIndex])) + else if (Crypto.VerifySignature(hashData, commit.Signature, context.Validators[payload.ValidatorIndex])) { existingCommitPayload = payload; CheckCommits(); @@ -429,18 +428,19 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m Log($"Invalid request: transaction already exists", LogLevel.Warning); return; } - - if (message.PreviousBlockStateRoot != Blockchain.Singleton.GetLocalStateRoot(context.Block.Index - 1)) + var stateRootHashData = context.EnsureStateRoot().GetHashData(); + if (!Crypto.VerifySignature(stateRootHashData, message.StateRootSignature, context.Validators[payload.ValidatorIndex])) { - Log($"Invalid request: state root incorrect.", LogLevel.Warning); + Log($"Invalid request: invalid state root signature", LogLevel.Warning); + return; } + // Timeout extension: prepare request has been received with success // around 2*15/M=30.0/5 ~ 40% block time (for M=5) ExtendTimerByFactor(2); context.Block.Timestamp = message.Timestamp; context.Block.ConsensusData.Nonce = message.Nonce; - context.ProposalStateRoot = message.PreviousBlockStateRoot; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); context.SendersFeeMonitor = new SendersFeeMonitor(); @@ -449,12 +449,10 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m if (!context.PreparationPayloads[i].GetDeserializedMessage().PreparationHash.Equals(payload.Hash)) context.PreparationPayloads[i] = null; context.PreparationPayloads[payload.ValidatorIndex] = payload; - byte[] headerHashData = context.EnsureHeader().GetHashData(); - byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); + byte[] hashData = context.EnsureHeader().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) - || !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) + if (!Crypto.VerifySignature(hashData, context.CommitPayloads[i].GetDeserializedMessage().Signature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) @@ -498,6 +496,12 @@ private void OnPrepareResponseReceived(ConsensusPayload payload, PrepareResponse if (context.PreparationPayloads[payload.ValidatorIndex] != null || context.NotAcceptingPayloadsDueToViewChanging) return; if (context.PreparationPayloads[context.Block.ConsensusData.PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[context.Block.ConsensusData.PrimaryIndex].Hash)) return; + byte[] stateRootHashData = context.EnsureStateRoot()?.GetHashData(); + if (!Crypto.VerifySignature(stateRootHashData, message.StateRootSignature, context.Validators[payload.ValidatorIndex])) + { + Log($"Invalid response: invalid state root signature, height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex}", LogLevel.Warning); + return; + } // Timeout extension: prepare response has been received with success // around 2*15/M=30.0/5 ~ 40% block time (for M=5) diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index 460dc4c125..d9d128b9e7 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -10,13 +10,13 @@ public class PrepareRequest : ConsensusMessage { public ulong Timestamp; public ulong Nonce; - public UInt256 PreviousBlockStateRoot; + public byte[] StateRootSignature; public UInt256[] TransactionHashes; public override int Size => base.Size - + sizeof(ulong) //Timestamp + + sizeof(ulong) //Timestamp + sizeof(ulong) //Nonce - + UInt256.Length //ProposalStateRoot + + StateRootSignature.GetVarSize() //StateRootSignature + TransactionHashes.GetVarSize(); //TransactionHashes public PrepareRequest() @@ -29,7 +29,7 @@ public override void Deserialize(BinaryReader reader) base.Deserialize(reader); Timestamp = reader.ReadUInt64(); Nonce = reader.ReadUInt64(); - PreviousBlockStateRoot = reader.ReadSerializable(); + StateRootSignature = reader.ReadVarBytes(1024); TransactionHashes = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) throw new FormatException(); @@ -40,7 +40,7 @@ public override void Serialize(BinaryWriter writer) base.Serialize(writer); writer.Write(Timestamp); writer.Write(Nonce); - writer.Write(PreviousBlockStateRoot); + writer.WriteVarBytes(StateRootSignature); writer.Write(TransactionHashes); } } diff --git a/src/neo/Consensus/PrepareResponse.cs b/src/neo/Consensus/PrepareResponse.cs index 7c2956ccc2..399e58604f 100644 --- a/src/neo/Consensus/PrepareResponse.cs +++ b/src/neo/Consensus/PrepareResponse.cs @@ -6,8 +6,8 @@ namespace Neo.Consensus public class PrepareResponse : ConsensusMessage { public UInt256 PreparationHash; - - public override int Size => base.Size + PreparationHash.Size; + public byte[] StateRootSignature; + public override int Size => base.Size + PreparationHash.Size + StateRootSignature.GetVarSize(); public PrepareResponse() : base(ConsensusMessageType.PrepareResponse) @@ -18,12 +18,14 @@ public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); PreparationHash = reader.ReadSerializable(); + StateRootSignature = reader.ReadVarBytes(1024); } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); writer.Write(PreparationHash); + writer.WriteVarBytes(StateRootSignature); } } } diff --git a/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs b/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs index 2792c50c9e..5d783c6796 100644 --- a/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs +++ b/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs @@ -10,23 +10,20 @@ public class CommitPayloadCompact : ISerializable { public byte ViewNumber; public ushort ValidatorIndex; - public byte[] BlockSignature; - public byte[] StateRootSignature; + public byte[] Signature; public byte[] InvocationScript; int ISerializable.Size => sizeof(byte) + //ViewNumber sizeof(ushort) + //ValidatorIndex - BlockSignature.Length + //BlockSignature - StateRootSignature.Length + //StateRootSignature + Signature.Length + //Signature InvocationScript.GetVarSize(); //InvocationScript void ISerializable.Deserialize(BinaryReader reader) { ViewNumber = reader.ReadByte(); ValidatorIndex = reader.ReadUInt16(); - BlockSignature = reader.ReadFixedBytes(64); - StateRootSignature = reader.ReadFixedBytes(64); + Signature = reader.ReadFixedBytes(64); InvocationScript = reader.ReadVarBytes(1024); } @@ -37,8 +34,7 @@ public static CommitPayloadCompact FromPayload(ConsensusPayload payload) { ViewNumber = message.ViewNumber, ValidatorIndex = payload.ValidatorIndex, - BlockSignature = message.BlockSignature, - StateRootSignature = message.StateRootSignature, + Signature = message.Signature, InvocationScript = payload.Witness.InvocationScript }; } @@ -47,8 +43,7 @@ void ISerializable.Serialize(BinaryWriter writer) { writer.Write(ViewNumber); writer.Write(ValidatorIndex); - writer.Write(BlockSignature); - writer.Write(StateRootSignature); + writer.Write(Signature); writer.WriteVarBytes(InvocationScript); } } diff --git a/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs b/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs index 962ae69185..5a55da1670 100644 --- a/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs +++ b/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs @@ -1,5 +1,6 @@ using Neo.IO; using Neo.Network.P2P.Payloads; +using System; using System.IO; namespace Neo.Consensus @@ -10,6 +11,7 @@ public class PreparationPayloadCompact : ISerializable { public ushort ValidatorIndex; public byte[] InvocationScript; + public byte[] StateRootSignature; int ISerializable.Size => sizeof(ushort) + //ValidatorIndex @@ -19,14 +21,21 @@ void ISerializable.Deserialize(BinaryReader reader) { ValidatorIndex = reader.ReadUInt16(); InvocationScript = reader.ReadVarBytes(1024); + StateRootSignature = reader.ReadVarBytes(1024); } public static PreparationPayloadCompact FromPayload(ConsensusPayload payload) { + byte[] state_root_sig = Array.Empty(); + if (payload.ConsensusMessage is PrepareResponse req) + state_root_sig = req.StateRootSignature; + else if (payload.ConsensusMessage is PrepareResponse resp) + state_root_sig = resp.StateRootSignature; return new PreparationPayloadCompact { ValidatorIndex = payload.ValidatorIndex, - InvocationScript = payload.Witness.InvocationScript + InvocationScript = payload.Witness.InvocationScript, + StateRootSignature = state_root_sig }; } @@ -34,6 +43,7 @@ void ISerializable.Serialize(BinaryWriter writer) { writer.Write(ValidatorIndex); writer.WriteVarBytes(InvocationScript); + writer.WriteVarBytes(StateRootSignature); } } } diff --git a/src/neo/Consensus/RecoveryMessage.cs b/src/neo/Consensus/RecoveryMessage.cs index 01276874c1..9a0aabf94a 100644 --- a/src/neo/Consensus/RecoveryMessage.cs +++ b/src/neo/Consensus/RecoveryMessage.cs @@ -77,8 +77,7 @@ internal ConsensusPayload[] GetCommitPayloadsFromRecoveryMessage(ConsensusContex ConsensusMessage = new Commit { ViewNumber = p.ViewNumber, - BlockSignature = p.BlockSignature, - StateRootSignature = p.StateRootSignature, + Signature = p.Signature }, Witness = new Witness { @@ -121,7 +120,8 @@ internal ConsensusPayload[] GetPrepareResponsePayloads(ConsensusContext context, ConsensusMessage = new PrepareResponse { ViewNumber = ViewNumber, - PreparationHash = preparationHash + PreparationHash = preparationHash, + StateRootSignature = p.StateRootSignature }, Witness = new Witness { diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 5e7d2f57fa..72f053f6e5 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -14,7 +14,7 @@ public class StateRoot : ICloneable, IInventory { public byte Version; public uint Index; - public UInt256 Root; + public UInt256 RootHash; public Witness Witness; InventoryType IInventory.InventoryType => InventoryType.StateRoot; @@ -47,10 +47,10 @@ Witness[] IVerifiable.Witnesses } public int Size => - sizeof(byte) + //Version - sizeof(uint) + //Index - UInt256.Length + //Root - Witness.Size; //Witness + sizeof(byte) + + sizeof(uint) + + UInt256.Length + + Witness.Size; StateRoot ICloneable.Clone() { @@ -58,7 +58,7 @@ StateRoot ICloneable.Clone() { Version = Version, Index = Index, - Root = Root, + RootHash = RootHash, Witness = Witness, }; } @@ -67,7 +67,7 @@ void ICloneable.FromReplica(StateRoot replica) { Version = replica.Version; Index = replica.Index; - Root = replica.Root; + RootHash = replica.RootHash; Witness = replica.Witness; } @@ -81,7 +81,7 @@ public void DeserializeUnsigned(BinaryReader reader) { Version = reader.ReadByte(); Index = reader.ReadUInt32(); - Root = reader.ReadSerializable(); + RootHash = reader.ReadSerializable(); } public void Serialize(BinaryWriter writer) @@ -94,7 +94,7 @@ public void SerializeUnsigned(BinaryWriter writer) { writer.Write(Version); writer.Write(Index); - writer.Write(Root); + writer.Write(RootHash); } public bool Verify(StoreView snapshot) @@ -109,12 +109,17 @@ public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) return new UInt160[] { script_hash }; } + public byte[] GetMessage() + { + return this.GetHashData(); + } + public JObject ToJson() { var json = new JObject(); json["version"] = Version; json["index"] = Index; - json["stateroot"] = Root.ToString(); + json["stateroot"] = RootHash.ToString(); json["witness"] = Witness.ToJson(); return json; } diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 7ea0152799..cf6b021824 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -10,7 +10,6 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Cryptography; @@ -48,7 +47,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm var mockContext = new Mock(mockWallet.Object, Blockchain.Singleton.Store); mockContext.Object.LastSeenMessage = new int[] { 0, 0, 0, 0, 0, 0, 0 }; - mockContext.Object.ProposalStateRoot = UInt256.Zero; + KeyPair[] kp_array = new KeyPair[7] { UT_Crypto.generateKey(32), // not used, kept for index consistency, didactically @@ -199,9 +198,23 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(6); Console.WriteLine("\nFailed because it is not primary and it created the prereq...Time to adjust"); - prepReq.ValidatorIndex = 1; //simulating primary as prepreq creator (signature is skip, no problem) + var stateRootData = mockContext.Object.EnsureStateRoot().GetHashData(); + prepReq = GetPrepareRequestAndSignStateRoot(prepReq, 1, kp_array[1], stateRootData); + //prepReq.ValidatorIndex = 1; //simulating primary as prepreq creator (signature is skip, no problem) // cleaning old try with Self ValidatorIndex mockContext.Object.PreparationPayloads[mockContext.Object.MyIndex] = null; + for (int i = 0; i < mockContext.Object.Validators.Length; i++) + Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}"); + mockContext.Object.Validators = new ECPoint[7] + { + kp_array[0].PublicKey, + kp_array[1].PublicKey, + kp_array[2].PublicKey, + kp_array[3].PublicKey, + kp_array[4].PublicKey, + kp_array[5].PublicKey, + kp_array[6].PublicKey + }; TellConsensusPayload(actorConsensus, prepReq); var OnPrepResponse = subscriber.ExpectMsg(); @@ -214,7 +227,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(5); // Simulating CN 3 - TellConsensusPayload(actorConsensus, GetPayloadAndModifyValidator(prepResponsePayload, 2)); + TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 2, kp_array[2], stateRootData)); //Waiting for RecoveryRequest for a more deterministic UT backupOnRecoveryDueToFailedNodes = subscriber.ExpectMsg(); recoveryPayload = (ConsensusPayload)backupOnRecoveryDueToFailedNodes.Inventory; @@ -227,7 +240,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(4); // Simulating CN 5 - TellConsensusPayload(actorConsensus, GetPayloadAndModifyValidator(prepResponsePayload, 4)); + TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 4, kp_array[4], stateRootData)); //Waiting for RecoveryRequest for a more deterministic UT backupOnRecoveryDueToFailedNodes = subscriber.ExpectMsg(); recoveryPayload = (ConsensusPayload)backupOnRecoveryDueToFailedNodes.Inventory; @@ -240,7 +253,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(3); // Simulating CN 4 - TellConsensusPayload(actorConsensus, GetPayloadAndModifyValidator(prepResponsePayload, 3)); + TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 3, kp_array[3], stateRootData)); var onCommitPayload = subscriber.ExpectMsg(); var commitPayload = (ConsensusPayload)onCommitPayload.Inventory; Commit cm = (Commit)commitPayload.ConsensusMessage; @@ -254,18 +267,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"ORIGINAL BlockHash: {mockContext.Object.Block.Hash}"); Console.WriteLine($"ORIGINAL Block NextConsensus: {mockContext.Object.Block.NextConsensus}"); - for (int i = 0; i < mockContext.Object.Validators.Length; i++) - Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}"); - mockContext.Object.Validators = new ECPoint[7] - { - kp_array[0].PublicKey, - kp_array[1].PublicKey, - kp_array[2].PublicKey, - kp_array[3].PublicKey, - kp_array[4].PublicKey, - kp_array[5].PublicKey, - kp_array[6].PublicKey - }; Console.WriteLine($"Generated keypairs PKey:"); for (int i = 0; i < mockContext.Object.Validators.Length; i++) Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}"); @@ -284,7 +285,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm var originalBlockHashData = mockContext.Object.Block.GetHashData(); mockContext.Object.Block.NextConsensus = updatedContract.ScriptHash; mockContext.Object.Block.Header.NextConsensus = updatedContract.ScriptHash; - var originalStateRootData = mockContext.Object.EnsureStateRoot().GetHashData(); var originalBlockMerkleRoot = mockContext.Object.Block.MerkleRoot; Console.WriteLine($"\noriginalBlockMerkleRoot: {originalBlockMerkleRoot}"); var updatedBlockHashData = mockContext.Object.Block.GetHashData(); @@ -294,15 +294,16 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("\n\n=========================="); Console.WriteLine("\nBasic commits Signatures verification"); // Basic tests for understanding signatures and ensuring signatures of commits are correct on tests - var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData, originalStateRootData); - Crypto.VerifySignature(originalBlockHashData, cm.BlockSignature, mockContext.Object.Validators[0]).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, cm.BlockSignature, mockContext.Object.Validators[0]).Should().BeFalse(); - Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).BlockSignature, mockContext.Object.Validators[6]).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).BlockSignature, mockContext.Object.Validators[6]).Should().BeTrue(); + var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData); + Crypto.VerifySignature(originalBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeTrue(); Console.WriteLine("\n=========================="); Console.WriteLine("\n=========================="); Console.WriteLine("\nCN7 simulation time"); + TellConsensusPayload(actorConsensus, cmPayloadTemp); var tempPayloadToBlockAndWait = subscriber.ExpectMsg(); var rmPayload = (ConsensusPayload)tempPayloadToBlockAndWait.Inventory; @@ -313,7 +314,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(1); Console.WriteLine("\nCN6 simulation time"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData, originalStateRootData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData)); tempPayloadToBlockAndWait = subscriber.ExpectMsg(); rmPayload = (ConsensusPayload)tempPayloadToBlockAndWait.Inventory; rmm = (RecoveryMessage)rmPayload.ConsensusMessage; @@ -323,7 +324,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(0); Console.WriteLine("\nCN5 simulation time"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData, originalStateRootData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData)); tempPayloadToBlockAndWait = subscriber.ExpectMsg(); Console.WriteLine("\nAsserting CountCommitted is 4..."); mockContext.Object.CountCommitted.Should().Be(4); @@ -352,13 +353,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.Block.PrevHash = UInt256.Zero; //Payload should also be forced, otherwise OnConsensus will not pass commitPayload.PrevHash = UInt256.Zero; - var root = mockContext.Object.EnsureStateRoot(); - var mockRoot = new Mock(); - mockRoot.Object.Version = root.Version; - mockRoot.Object.Index = root.Index; - mockRoot.Object.Root = root.Root; - mockRoot.Setup(p => p.GetScriptHashesForVerifying(It.IsAny())).Returns(p => new UInt160[] { updatedContract.ScriptHash }); - mockContext.Object.StateRoot = mockRoot.Object; Console.WriteLine($"\nNew Hash is {mockContext.Object.Block.GetHashData().ToScriptHash()}"); Console.WriteLine($"\nForcing block VerificationScript to {updatedContract.Script.ToScriptHash()}"); // The default behavior for BlockBase, when PrevHash = UInt256.Zero, is to use its own Witness @@ -368,11 +362,10 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"\nNew Hash is {mockContext.Object.Block.GetHashData().ToScriptHash()}"); Console.WriteLine("\nCN4 simulation time - Final needed signatures"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 3, kp_array[3], mockContext.Object.Block.GetHashData(), originalStateRootData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 3, kp_array[3], mockContext.Object.Block.GetHashData())); Console.WriteLine("\nWait for subscriber Block"); var utBlock = subscriber.ExpectMsg(); - var stateroot = subscriber.ExpectMsg(); Console.WriteLine("\nAsserting CountCommitted is 5..."); mockContext.Object.CountCommitted.Should().Be(5); @@ -387,6 +380,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.Block.Transactions = null; // ensuring same hash as snapshot mockContext.Object.Block.PrevHash = oldPrevHash; + Console.WriteLine("\nAsserting CountCommitted is 0..."); mockContext.Object.CountCommitted.Should().Be(0); Console.WriteLine($"\nAsserting CountFailed is 0..."); @@ -436,7 +430,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm /// new ValidatorIndex for the cpToCopy /// KeyPair that will be used for signing the Commit message used for creating blocks /// HashCode of the Block that is being produced and current being signed - public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload cpToCopy, ushort vI, KeyPair kp, byte[] blockHashToSign, byte[] rootHashToSign) + public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload cpToCopy, ushort vI, KeyPair kp, byte[] blockHashToSign) { var cpCommitTemp = cpToCopy.ToArray().AsSerializable(); cpCommitTemp.ValidatorIndex = vI; @@ -444,8 +438,7 @@ public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload c cpCommitTemp.ConsensusMessage = new Commit { ViewNumber = oldViewNumber, - BlockSignature = Crypto.Sign(blockHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false)[1..]), - StateRootSignature = Crypto.Sign(rootHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false)[1..]), + Signature = Crypto.Sign(blockHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false).Skip(1).ToArray()) }; SignPayload(cpCommitTemp, kp); return cpCommitTemp; @@ -463,6 +456,25 @@ public ConsensusPayload GetPayloadAndModifyValidator(ConsensusPayload cpToCopy, return cpTemp; } + public ConsensusPayload GetPrepareRequestAndSignStateRoot(ConsensusPayload req, ushort vI, KeyPair kp, byte[] stateRootData) + { + var tmp = req.ToArray().AsSerializable(); + tmp.ValidatorIndex = vI; + var message = tmp.GetDeserializedMessage(); + message.StateRootSignature = Crypto.Sign(stateRootData, kp.PrivateKey, kp.PublicKey.EncodePoint(false).Skip(1).ToArray()); + tmp.ConsensusMessage = message; + return tmp; + } + public ConsensusPayload GetPrepareResponsePayloadAndSignStateRoot(ConsensusPayload resp, ushort vI, KeyPair kp, byte[] stateRootData) + { + var tmp = resp.ToArray().AsSerializable(); + tmp.ValidatorIndex = vI; + var message = tmp.GetDeserializedMessage(); + message.StateRootSignature = Crypto.Sign(stateRootData, kp.PrivateKey, kp.PublicKey.EncodePoint(false).Skip(1).ToArray()); + tmp.ConsensusMessage = message; + return tmp; + } + private void SignPayload(ConsensusPayload payload, KeyPair kp) { ContractParametersContext sc; @@ -496,7 +508,6 @@ public void TestSerializeAndDeserializeConsensusContext() } }, ViewNumber = 2, - ProposalStateRoot = UInt256.Zero, Validators = new ECPoint[7] { ECPoint.Parse("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", Neo.Cryptography.ECC.ECCurve.Secp256r1), @@ -529,29 +540,21 @@ public void TestSerializeAndDeserializeConsensusContext() { TransactionHashes = consensusContext.TransactionHashes, Timestamp = 23, - PreviousBlockStateRoot = UInt256.Zero + StateRootSignature = new byte[] { 0x01 } }; consensusContext.PreparationPayloads[6] = MakeSignedPayload(consensusContext, prepareRequestMessage, 6, new[] { (byte)'3', (byte)'!' }); - consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 0, new[] { (byte)'t', (byte)'e' }); - consensusContext.PreparationPayloads[1] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 1, new[] { (byte)'s', (byte)'t' }); + consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 0, new[] { (byte)'t', (byte)'e' }); + consensusContext.PreparationPayloads[1] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 1, new[] { (byte)'s', (byte)'t' }); consensusContext.PreparationPayloads[2] = null; - consensusContext.PreparationPayloads[3] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 3, new[] { (byte)'1', (byte)'2' }); + consensusContext.PreparationPayloads[3] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 3, new[] { (byte)'1', (byte)'2' }); consensusContext.PreparationPayloads[4] = null; consensusContext.PreparationPayloads[5] = null; consensusContext.CommitPayloads = new ConsensusPayload[consensusContext.Validators.Length]; using (SHA256 sha256 = SHA256.Create()) { - consensusContext.CommitPayloads[3] = MakeSignedPayload(consensusContext, new Commit - { - BlockSignature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray(), - StateRootSignature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() - }, 3, new[] { (byte)'3', (byte)'4' }); - consensusContext.CommitPayloads[6] = MakeSignedPayload(consensusContext, new Commit - { - BlockSignature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx2.Hash.ToArray())).ToArray(), - StateRootSignature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() - }, 3, new[] { (byte)'6', (byte)'7' }); + consensusContext.CommitPayloads[3] = MakeSignedPayload(consensusContext, new Commit { Signature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() }, 3, new[] { (byte)'3', (byte)'4' }); + consensusContext.CommitPayloads[6] = MakeSignedPayload(consensusContext, new Commit { Signature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx2.Hash.ToArray())).ToArray() }, 3, new[] { (byte)'6', (byte)'7' }); } consensusContext.Block.Timestamp = TimeProvider.Current.UtcNow.ToTimestampMS(); @@ -641,7 +644,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 0, - InvocationScript = new[] { (byte)'t', (byte)'e' } + InvocationScript = new[] { (byte)'t', (byte)'e' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -649,7 +653,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 3, - InvocationScript = new[] { (byte)'1', (byte)'2' } + InvocationScript = new[] { (byte)'1', (byte)'2' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -657,7 +662,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 6, - InvocationScript = new[] { (byte)'3', (byte)'!' } + InvocationScript = new[] { (byte)'3', (byte)'!' }, + StateRootSignature = new byte[] { 0x01 } } } }, @@ -731,8 +737,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR }, PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray(), - PreviousBlockStateRoot = UInt256.Zero + StateRootSignature = new byte[] { 0x01 }, + TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationHash = new UInt256(Crypto.Hash256(new[] { (byte)'a' })), PreparationMessages = new Dictionary() @@ -742,7 +748,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 0, - InvocationScript = new[] { (byte)'t', (byte)'e' } + InvocationScript = new[] { (byte)'t', (byte)'e' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -750,7 +757,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 1, - InvocationScript = new[] { (byte)'s', (byte)'t' } + InvocationScript = new[] { (byte)'s', (byte)'t' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -758,7 +766,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 3, - InvocationScript = new[] { (byte)'1', (byte)'2' } + InvocationScript = new[] { (byte)'1', (byte)'2' }, + StateRootSignature = new byte[] { 0x01 }, } } }, @@ -785,8 +794,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray(), - PreviousBlockStateRoot = UInt256.Zero + StateRootSignature = new byte[] { 0x01 }, + TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationMessages = new Dictionary() { @@ -795,7 +804,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 0, - InvocationScript = new[] { (byte)'t', (byte)'e' } + InvocationScript = new[] { (byte)'t', (byte)'e' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -803,7 +813,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 1, - InvocationScript = new[] { (byte)'s', (byte)'t' } + InvocationScript = new[] { (byte)'s', (byte)'t' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -811,7 +822,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 3, - InvocationScript = new[] { (byte)'1', (byte)'2' } + InvocationScript = new[] { (byte)'1', (byte)'2' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -819,7 +831,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 6, - InvocationScript = new[] { (byte)'3', (byte)'!' } + InvocationScript = new[] { (byte)'3', (byte)'!' }, + StateRootSignature = new byte[] { 0x01 } } } }, @@ -846,8 +859,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray(), - PreviousBlockStateRoot = UInt256.Zero + StateRootSignature = new byte[] { 0x01 }, + TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationMessages = new Dictionary() { @@ -856,7 +869,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 0, - InvocationScript = new[] { (byte)'t', (byte)'e' } + InvocationScript = new[] { (byte)'t', (byte)'e' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -864,7 +878,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 1, - InvocationScript = new[] { (byte)'s', (byte)'t' } + InvocationScript = new[] { (byte)'s', (byte)'t' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -872,7 +887,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 3, - InvocationScript = new[] { (byte)'1', (byte)'2' } + InvocationScript = new[] { (byte)'1', (byte)'2' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -880,7 +896,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 6, - InvocationScript = new[] { (byte)'3', (byte)'!' } + InvocationScript = new[] { (byte)'3', (byte)'!' }, + StateRootSignature = new byte[] { 0x01 }, } } }, @@ -891,8 +908,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.CommitPayloadCompact { ValidatorIndex = 1, - BlockSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - StateRootSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + Signature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, InvocationScript = new[] { (byte)'1', (byte)'2' } } }, @@ -901,8 +917,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.CommitPayloadCompact { ValidatorIndex = 6, - BlockSignature = new byte[64] { (byte)'3', (byte)'D', (byte)'R', (byte)'I', (byte)'N', (byte)'K', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - StateRootSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + Signature = new byte[64] { (byte)'3', (byte)'D', (byte)'R', (byte)'I', (byte)'N', (byte)'K', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, InvocationScript = new[] { (byte)'6', (byte)'7' } } } From 1e6ecf65d3b4350b889723656c16fc2569d7f674 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 14:21:22 +0800 Subject: [PATCH 14/40] update consensus ut --- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index cf6b021824..3b4a259b35 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -10,6 +10,7 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Cryptography; @@ -182,6 +183,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm // Forcing hashes to 0 because mempool is currently shared ppToSend.TransactionHashes = new UInt256[0]; ppToSend.TransactionHashes.Length.Should().Be(0); + prepReq.Data = ppToSend.ToArray(); Console.WriteLine($"\nAsserting PreparationPayloads is 1 (After MakePrepareRequest)..."); mockContext.Object.PreparationPayloads.Count(p => p != null).Should().Be(1); mockContext.Object.PreparationPayloads[prepReq.ValidatorIndex] = null; @@ -215,6 +217,10 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm kp_array[5].PublicKey, kp_array[6].PublicKey }; + mockContext.Object.GetPrimaryIndex(mockContext.Object.ViewNumber).Should().Be(1); + mockContext.Object.MyIndex.Should().Be(0); + Console.WriteLine($"\nAsserting tx count is 0..."); + prepReq.GetDeserializedMessage().TransactionHashes.Count().Should().Be(0); TellConsensusPayload(actorConsensus, prepReq); var OnPrepResponse = subscriber.ExpectMsg(); @@ -225,6 +231,10 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.PreparationPayloads.Count(p => p != null).Should().Be(2); Console.WriteLine($"\nAsserting CountFailed is 5..."); mockContext.Object.CountFailed.Should().Be(5); + Console.WriteLine("\nAsserting PrepareResponse ValidatorIndex is 0..."); + prepResponsePayload.ValidatorIndex.Should().Be(0); + // Using correct signed response to replace prepareresponse sent + mockContext.Object.PreparationPayloads[prepResponsePayload.ValidatorIndex] = GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 0, kp_array[0], stateRootData); // Simulating CN 3 TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 2, kp_array[2], stateRootData)); @@ -251,10 +261,20 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.PreparationPayloads.Count(p => p != null).Should().Be(4); Console.WriteLine($"\nAsserting CountFailed is 3..."); mockContext.Object.CountFailed.Should().Be(3); + var updatedContract = Contract.CreateMultiSigContract(mockContext.Object.M, mockContext.Object.Validators); + // Mock StateRoot to use mock Validators to sign + var root = mockContext.Object.EnsureStateRoot(); + var mockRoot = new Mock(); + mockRoot.Object.Version = root.Version; + mockRoot.Object.Index = root.Index; + mockRoot.Object.RootHash = root.RootHash; + mockRoot.Setup(p => p.GetScriptHashesForVerifying(It.IsAny())).Returns(p => new UInt160[] { updatedContract.ScriptHash }); + mockContext.Object.PreviousBlockStateRoot = mockRoot.Object; // Simulating CN 4 TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 3, kp_array[3], stateRootData)); var onCommitPayload = subscriber.ExpectMsg(); + var onStateRoot = subscriber.ExpectMsg(); var commitPayload = (ConsensusPayload)onCommitPayload.Inventory; Commit cm = (Commit)commitPayload.ConsensusMessage; Console.WriteLine("\nAsserting PreparationPayloads count is 5..."); @@ -270,7 +290,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"Generated keypairs PKey:"); for (int i = 0; i < mockContext.Object.Validators.Length; i++) Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}"); - var updatedContract = Contract.CreateMultiSigContract(mockContext.Object.M, mockContext.Object.Validators); Console.WriteLine($"\nContract updated: {updatedContract.ScriptHash}"); // =============================================================== From 821fd737f976f65f969742f3aeabe3d79c9a5273 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 17 Jun 2020 07:58:38 +0200 Subject: [PATCH 15/40] Check Json.Serialize map keys (#1705) --- src/neo/SmartContract/JsonSerializer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/neo/SmartContract/JsonSerializer.cs b/src/neo/SmartContract/JsonSerializer.cs index 375709a13d..5ed1369c8c 100644 --- a/src/neo/SmartContract/JsonSerializer.cs +++ b/src/neo/SmartContract/JsonSerializer.cs @@ -48,6 +48,8 @@ public static JObject Serialize(StackItem item) foreach (var entry in map) { + if (!(entry.Key is ByteString)) throw new FormatException(); + var key = entry.Key.GetString(); var value = Serialize(entry.Value); @@ -106,6 +108,7 @@ public static byte[] SerializeToByteArray(StackItem item, uint maxSize) stack.Push(JsonTokenType.EndObject); foreach (var pair in map.Reverse()) { + if (!(pair.Key is ByteString)) throw new FormatException(); stack.Push(pair.Value); stack.Push(pair.Key); stack.Push(JsonTokenType.PropertyName); @@ -115,7 +118,7 @@ public static byte[] SerializeToByteArray(StackItem item, uint maxSize) writer.WriteEndObject(); break; case JsonTokenType.PropertyName: - writer.WritePropertyName(((PrimitiveType)stack.Pop()).GetSpan()); + writer.WritePropertyName(((ByteString)stack.Pop()).GetSpan()); break; case Null _: writer.WriteNullValue(); From 52272ec7cfd57f9d2d7166380df43a4f7e880ea4 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 5 Jun 2020 16:18:56 +0800 Subject: [PATCH 16/40] don't use snapshot directly in plugin --- src/neo/Ledger/Blockchain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index b937d8c0a4..b7903d4a00 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -443,7 +443,7 @@ private void Persist(Block block) } snapshot.BlockHashIndex.GetAndChange().Set(block); foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) - plugin.OnPersist(snapshot, all_application_executed); + plugin.OnPersist(snapshot.Clone(), all_application_executed); snapshot.Commit(); List commitExceptions = null; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) From f029ddecc232fce55f44b8a8b579787b771dcdc2 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Fri, 12 Jun 2020 13:15:59 +0800 Subject: [PATCH 17/40] recover --- src/neo/Ledger/Blockchain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index b7903d4a00..b937d8c0a4 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -443,7 +443,7 @@ private void Persist(Block block) } snapshot.BlockHashIndex.GetAndChange().Set(block); foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) - plugin.OnPersist(snapshot.Clone(), all_application_executed); + plugin.OnPersist(snapshot, all_application_executed); snapshot.Commit(); List commitExceptions = null; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) From d04529aaa3e6ce91ce8c38eb86861440d00620b1 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 14:41:44 +0800 Subject: [PATCH 18/40] consensus state root --- src/neo/Consensus/Commit.cs | 12 ++-- src/neo/Consensus/ConsensusContext.cs | 59 ++++++++++++++++--- src/neo/Consensus/ConsensusService.cs | 21 +++++-- src/neo/Consensus/PrepareRequest.cs | 6 +- .../RecoveryMessage.CommitPayloadCompact.cs | 15 +++-- src/neo/Consensus/RecoveryMessage.cs | 3 +- 6 files changed, 90 insertions(+), 26 deletions(-) diff --git a/src/neo/Consensus/Commit.cs b/src/neo/Consensus/Commit.cs index fce9b8caaf..f635a1a504 100644 --- a/src/neo/Consensus/Commit.cs +++ b/src/neo/Consensus/Commit.cs @@ -5,22 +5,24 @@ namespace Neo.Consensus { public class Commit : ConsensusMessage { - public byte[] Signature; - - public override int Size => base.Size + Signature.Length; + public byte[] BlockSignature; + public byte[] StateRootSignature; + public override int Size => base.Size + BlockSignature.Length + StateRootSignature.Length; public Commit() : base(ConsensusMessageType.Commit) { } public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); - Signature = reader.ReadFixedBytes(64); + BlockSignature = reader.ReadFixedBytes(64); + StateRootSignature = reader.ReadFixedBytes(64); } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); - writer.Write(Signature); + writer.Write(BlockSignature); + writer.Write(StateRootSignature); } } } diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 3d3a4fcb5d..3091ea706e 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -1,18 +1,20 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using Neo; using Neo.Cryptography; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Ledger; +using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; using Neo.Wallets; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; namespace Neo.Consensus { @@ -24,6 +26,8 @@ internal class ConsensusContext : IDisposable, ISerializable private const byte ConsensusStatePrefix = 0xf4; public Block Block; + public UInt256 ProposalStateRoot { get; set; } + public StateRoot StateRoot { get; set; } public byte ViewNumber; public ECPoint[] Validators; public int MyIndex; @@ -88,7 +92,7 @@ public Block CreateBlock() for (int i = 0, j = 0; i < Validators.Length && j < M; i++) { if (CommitPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; - sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().Signature); + sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().BlockSignature); j++; } Block.Witness = sc.GetWitnesses()[0]; @@ -96,6 +100,22 @@ public Block CreateBlock() return Block; } + public StateRoot CreateStateRoot() + { + EnsureStateRoot(); + if (StateRoot == null) return null; + Contract contract = Contract.CreateMultiSigContract(M, Validators); + ContractParametersContext sc = new ContractParametersContext(StateRoot); + for (int i = 0, j = 0; i < Validators.Length && j < M; i++) + { + if (CommitPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; + sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().StateRootSignature); + j++; + } + StateRoot.Witness = sc.GetWitnesses()[0]; + return StateRoot; + } + public void Deserialize(BinaryReader reader) { Reset(0); @@ -106,6 +126,7 @@ public void Deserialize(BinaryReader reader) if (Block.NextConsensus.Equals(UInt160.Zero)) Block.NextConsensus = null; Block.ConsensusData = reader.ReadSerializable(); + ProposalStateRoot.Deserialize(reader); ViewNumber = reader.ReadByte(); TransactionHashes = reader.ReadSerializableArray(); Transaction[] transactions = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); @@ -137,6 +158,20 @@ public Block EnsureHeader() return Block; } + public StateRoot EnsureStateRoot() + { + if (StateRoot is null) + { + StateRoot = new StateRoot() + { + Version = 0, + Index = Block.Index - 1, + Root = ProposalStateRoot + }; + } + return StateRoot; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint GetPrimaryIndex(byte viewNumber) { @@ -176,7 +211,8 @@ public ConsensusPayload MakeCommit() { return CommitPayloads[MyIndex] ?? (CommitPayloads[MyIndex] = MakeSignedPayload(new Commit { - Signature = EnsureHeader().Sign(keyPair) + BlockSignature = EnsureHeader().Sign(keyPair), + StateRootSignature = EnsureStateRoot().Sign(keyPair), })); } @@ -304,7 +340,8 @@ public ConsensusPayload MakePrepareRequest() { Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes + TransactionHashes = TransactionHashes, + ProposalStateRoot = ProposalStateRoot }); } @@ -326,7 +363,8 @@ public ConsensusPayload MakeRecoveryMessage() ViewNumber = ViewNumber, Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes + TransactionHashes = TransactionHashes, + ProposalStateRoot = ProposalStateRoot }; } return MakeSignedPayload(new RecoveryMessage() @@ -399,6 +437,7 @@ public void Reset(byte viewNumber) keyPair = account.GetKey(); break; } + StateRoot = null; } else { @@ -419,6 +458,7 @@ public void Reset(byte viewNumber) TransactionHashes = null; PreparationPayloads = new ConsensusPayload[Validators.Length]; if (MyIndex >= 0) LastSeenMessage[MyIndex] = (int)Block.Index; + ProposalStateRoot = Blockchain.Singleton.GetStateRoot(Block.Index - 1); } public void Save() @@ -433,6 +473,7 @@ public void Serialize(BinaryWriter writer) writer.Write(Block.Timestamp); writer.Write(Block.NextConsensus ?? UInt160.Zero); writer.Write(Block.ConsensusData); + writer.Write(ProposalStateRoot); writer.Write(ViewNumber); writer.Write(TransactionHashes ?? new UInt256[0]); writer.Write(Transactions?.Values.ToArray() ?? new Transaction[0]); diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 26648c4429..bc3b9521c4 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -134,6 +134,9 @@ private void CheckCommits() Block block = context.CreateBlock(); Log($"relay block: height={block.Index} hash={block.Hash} tx={block.Transactions.Length}"); blockchain.Tell(block); + StateRoot root = context.CreateStateRoot(); + Log($"relay state root: height={root.Index} hash={root.Hash} root={root.Root}"); + blockchain.Tell(root); } } @@ -236,12 +239,14 @@ private void OnCommitReceived(ConsensusPayload payload, Commit commit) { Log($"{nameof(OnCommitReceived)}: height={payload.BlockIndex} view={commit.ViewNumber} index={payload.ValidatorIndex} nc={context.CountCommitted} nf={context.CountFailed}"); - byte[] hashData = context.EnsureHeader()?.GetHashData(); - if (hashData == null) + byte[] headerHashData = context.EnsureHeader()?.GetHashData(); + byte[] stateRootHashData = context.EnsureStateRoot()?.GetHashData(); + if (headerHashData == null || stateRootHashData == null) { existingCommitPayload = payload; } - else if (Crypto.VerifySignature(hashData, commit.Signature, context.Validators[payload.ValidatorIndex])) + else if (Crypto.VerifySignature(headerHashData, commit.BlockSignature, context.Validators[payload.ValidatorIndex]) + && Crypto.VerifySignature(stateRootHashData, commit.StateRootSignature, context.Validators[payload.ValidatorIndex])) { existingCommitPayload = payload; CheckCommits(); @@ -425,12 +430,17 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m return; } + if (message.ProposalStateRoot != Blockchain.Singleton.GetStateRoot(context.Block.Index - 1)) + { + Log($"Invalid request: state root incorrect.", LogLevel.Warning); + } // Timeout extension: prepare request has been received with success // around 2*15/M=30.0/5 ~ 40% block time (for M=5) ExtendTimerByFactor(2); context.Block.Timestamp = message.Timestamp; context.Block.ConsensusData.Nonce = message.Nonce; + context.ProposalStateRoot = message.ProposalStateRoot; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); context.SendersFeeMonitor = new SendersFeeMonitor(); @@ -439,10 +449,11 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m if (!context.PreparationPayloads[i].GetDeserializedMessage().PreparationHash.Equals(payload.Hash)) context.PreparationPayloads[i] = null; context.PreparationPayloads[payload.ValidatorIndex] = payload; - byte[] hashData = context.EnsureHeader().GetHashData(); + byte[] headerHashData = context.EnsureHeader().GetHashData(); + byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(hashData, context.CommitPayloads[i].GetDeserializedMessage().Signature, context.Validators[i])) + if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) || !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index 2369b4f9f7..5fb748d643 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -10,11 +10,13 @@ public class PrepareRequest : ConsensusMessage { public ulong Timestamp; public ulong Nonce; + public UInt256 ProposalStateRoot; public UInt256[] TransactionHashes; public override int Size => base.Size - + sizeof(ulong) //Timestamp + + sizeof(ulong) //Timestamp + sizeof(ulong) //Nonce + + UInt256.Length //ProposalStateRoot + TransactionHashes.GetVarSize(); //TransactionHashes public PrepareRequest() @@ -27,6 +29,7 @@ public override void Deserialize(BinaryReader reader) base.Deserialize(reader); Timestamp = reader.ReadUInt64(); Nonce = reader.ReadUInt64(); + ProposalStateRoot = reader.ReadSerializable(); TransactionHashes = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) throw new FormatException(); @@ -37,6 +40,7 @@ public override void Serialize(BinaryWriter writer) base.Serialize(writer); writer.Write(Timestamp); writer.Write(Nonce); + writer.Write(ProposalStateRoot); writer.Write(TransactionHashes); } } diff --git a/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs b/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs index 5d783c6796..2792c50c9e 100644 --- a/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs +++ b/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs @@ -10,20 +10,23 @@ public class CommitPayloadCompact : ISerializable { public byte ViewNumber; public ushort ValidatorIndex; - public byte[] Signature; + public byte[] BlockSignature; + public byte[] StateRootSignature; public byte[] InvocationScript; int ISerializable.Size => sizeof(byte) + //ViewNumber sizeof(ushort) + //ValidatorIndex - Signature.Length + //Signature + BlockSignature.Length + //BlockSignature + StateRootSignature.Length + //StateRootSignature InvocationScript.GetVarSize(); //InvocationScript void ISerializable.Deserialize(BinaryReader reader) { ViewNumber = reader.ReadByte(); ValidatorIndex = reader.ReadUInt16(); - Signature = reader.ReadFixedBytes(64); + BlockSignature = reader.ReadFixedBytes(64); + StateRootSignature = reader.ReadFixedBytes(64); InvocationScript = reader.ReadVarBytes(1024); } @@ -34,7 +37,8 @@ public static CommitPayloadCompact FromPayload(ConsensusPayload payload) { ViewNumber = message.ViewNumber, ValidatorIndex = payload.ValidatorIndex, - Signature = message.Signature, + BlockSignature = message.BlockSignature, + StateRootSignature = message.StateRootSignature, InvocationScript = payload.Witness.InvocationScript }; } @@ -43,7 +47,8 @@ void ISerializable.Serialize(BinaryWriter writer) { writer.Write(ViewNumber); writer.Write(ValidatorIndex); - writer.Write(Signature); + writer.Write(BlockSignature); + writer.Write(StateRootSignature); writer.WriteVarBytes(InvocationScript); } } diff --git a/src/neo/Consensus/RecoveryMessage.cs b/src/neo/Consensus/RecoveryMessage.cs index cadb137b80..01276874c1 100644 --- a/src/neo/Consensus/RecoveryMessage.cs +++ b/src/neo/Consensus/RecoveryMessage.cs @@ -77,7 +77,8 @@ internal ConsensusPayload[] GetCommitPayloadsFromRecoveryMessage(ConsensusContex ConsensusMessage = new Commit { ViewNumber = p.ViewNumber, - Signature = p.Signature + BlockSignature = p.BlockSignature, + StateRootSignature = p.StateRootSignature, }, Witness = new Witness { From 82c11a512925599614e9bfcf09a7fa05cca3de09 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 14:54:19 +0800 Subject: [PATCH 19/40] fix build error --- src/neo/Ledger/Blockchain.state.cs | 12 ++ src/neo/Network/P2P/MessageCommand.cs | 2 + src/neo/Network/P2P/Payloads/InventoryType.cs | 1 + src/neo/Network/P2P/Payloads/StateRoot.cs | 126 ++++++++++++++++++ tests/neo.UnitTests/Consensus/UT_Consensus.cs | 65 ++++++--- 5 files changed, 186 insertions(+), 20 deletions(-) create mode 100644 src/neo/Ledger/Blockchain.state.cs create mode 100644 src/neo/Network/P2P/Payloads/StateRoot.cs diff --git a/src/neo/Ledger/Blockchain.state.cs b/src/neo/Ledger/Blockchain.state.cs new file mode 100644 index 0000000000..a82e4977a1 --- /dev/null +++ b/src/neo/Ledger/Blockchain.state.cs @@ -0,0 +1,12 @@ +using Akka.Actor; + +namespace Neo.Ledger +{ + public sealed partial class Blockchain : UntypedActor + { + public UInt256 GetStateRoot(uint index) + { + return UInt256.Zero; + } + } +} diff --git a/src/neo/Network/P2P/MessageCommand.cs b/src/neo/Network/P2P/MessageCommand.cs index 89c21597cf..1c3ce68659 100644 --- a/src/neo/Network/P2P/MessageCommand.cs +++ b/src/neo/Network/P2P/MessageCommand.cs @@ -40,6 +40,8 @@ public enum MessageCommand : byte Block = 0x2c, [ReflectionCache(typeof(ConsensusPayload))] Consensus = 0x2d, + [ReflectionCache(typeof(StateRoot))] + StateRoot = 0x2e, Reject = 0x2f, //SPV protocol diff --git a/src/neo/Network/P2P/Payloads/InventoryType.cs b/src/neo/Network/P2P/Payloads/InventoryType.cs index 0a1b831d12..9effb99556 100644 --- a/src/neo/Network/P2P/Payloads/InventoryType.cs +++ b/src/neo/Network/P2P/Payloads/InventoryType.cs @@ -4,6 +4,7 @@ public enum InventoryType : byte { TX = MessageCommand.Transaction, Block = MessageCommand.Block, + StateRoot = MessageCommand.StateRoot, Consensus = MessageCommand.Consensus } } diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs new file mode 100644 index 0000000000..9767d4675d --- /dev/null +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -0,0 +1,126 @@ +using Neo.Cryptography; +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.IO; + +namespace Neo.Network.P2P.Payloads +{ + public class StateRoot : ICloneable, IInventory + { + public byte Version; + public uint Index; + public UInt256 Root; + public Witness Witness; + + InventoryType IInventory.InventoryType => InventoryType.StateRoot; + + private UInt256 _hash = null; + + public UInt256 Hash + { + get + { + if (_hash == null) + { + _hash = new UInt256(Crypto.Hash256(this.GetHashData())); + } + return _hash; + } + } + + Witness[] IVerifiable.Witnesses + { + get + { + return new[] { Witness }; + } + set + { + if (value.Length != 1) throw new ArgumentException(); + Witness = value[0]; + } + } + + public int Size => + sizeof(byte) + + sizeof(uint) + + UInt256.Length + + Witness.Size; + + StateRoot ICloneable.Clone() + { + return new StateRoot + { + Version = Version, + Index = Index, + Root = Root, + Witness = Witness, + }; + } + + void ICloneable.FromReplica(StateRoot replica) + { + Version = replica.Version; + Index = replica.Index; + Root = replica.Root; + Witness = replica.Witness; + } + + public void Deserialize(BinaryReader reader) + { + this.DeserializeUnsigned(reader); + Witness = reader.ReadSerializable(); + } + + public void DeserializeUnsigned(BinaryReader reader) + { + Version = reader.ReadByte(); + Index = reader.ReadUInt32(); + Root = reader.ReadSerializable(); + } + + public void Serialize(BinaryWriter writer) + { + this.SerializeUnsigned(writer); + writer.Write(Witness); + } + + public void SerializeUnsigned(BinaryWriter writer) + { + writer.Write(Version); + writer.Write(Index); + writer.Write(Root); + } + + public bool Verify(StoreView snapshot) + { + return this.VerifyWitnesses(snapshot, 1_00000000); + } + + public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) + { + var script_hash = Blockchain.Singleton.GetBlock(Index)?.NextConsensus; + return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; + } + + public byte[] GetMessage() + { + return this.GetHashData(); + } + + public JObject ToJson() + { + var json = new JObject(); + json["version"] = Version; + json["index"] = Index; + json["stateroot"] = Root.ToString(); + json["witness"] = Witness.ToJson(); + return json; + } + } +} diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 86eb6bc8c2..f55b4b4784 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -10,6 +10,7 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Cryptography; @@ -47,7 +48,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm var mockContext = new Mock(mockWallet.Object, Blockchain.Singleton.Store); mockContext.Object.LastSeenMessage = new int[] { 0, 0, 0, 0, 0, 0, 0 }; - + mockContext.Object.ProposalStateRoot = UInt256.Zero; KeyPair[] kp_array = new KeyPair[7] { UT_Crypto.generateKey(32), // not used, kept for index consistency, didactically @@ -283,6 +284,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm var originalBlockHashData = mockContext.Object.Block.GetHashData(); mockContext.Object.Block.NextConsensus = updatedContract.ScriptHash; mockContext.Object.Block.Header.NextConsensus = updatedContract.ScriptHash; + var originalStateRootData = mockContext.Object.EnsureStateRoot().GetHashData(); var originalBlockMerkleRoot = mockContext.Object.Block.MerkleRoot; Console.WriteLine($"\noriginalBlockMerkleRoot: {originalBlockMerkleRoot}"); var updatedBlockHashData = mockContext.Object.Block.GetHashData(); @@ -292,11 +294,11 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("\n\n=========================="); Console.WriteLine("\nBasic commits Signatures verification"); // Basic tests for understanding signatures and ensuring signatures of commits are correct on tests - var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData); - Crypto.VerifySignature(originalBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); - Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeTrue(); + var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData, originalStateRootData); + Crypto.VerifySignature(originalBlockHashData, cm.BlockSignature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, cm.BlockSignature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).BlockSignature, mockContext.Object.Validators[6]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).BlockSignature, mockContext.Object.Validators[6]).Should().BeTrue(); Console.WriteLine("\n=========================="); Console.WriteLine("\n=========================="); @@ -311,7 +313,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(1); Console.WriteLine("\nCN6 simulation time"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData, originalStateRootData)); tempPayloadToBlockAndWait = subscriber.ExpectMsg(); rmPayload = (ConsensusPayload)tempPayloadToBlockAndWait.Inventory; rmm = (RecoveryMessage)rmPayload.ConsensusMessage; @@ -321,7 +323,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(0); Console.WriteLine("\nCN5 simulation time"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData, originalStateRootData)); tempPayloadToBlockAndWait = subscriber.ExpectMsg(); Console.WriteLine("\nAsserting CountCommitted is 4..."); mockContext.Object.CountCommitted.Should().Be(4); @@ -350,6 +352,13 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.Block.PrevHash = UInt256.Zero; //Payload should also be forced, otherwise OnConsensus will not pass commitPayload.PrevHash = UInt256.Zero; + var root = mockContext.Object.EnsureStateRoot(); + var mockRoot = new Mock(); + mockRoot.Object.Version = root.Version; + mockRoot.Object.Index = root.Index; + mockRoot.Object.Root = root.Root; + mockRoot.Setup(p => p.GetScriptHashesForVerifying(It.IsAny())).Returns(p => new UInt160[] { updatedContract.ScriptHash }); + mockContext.Object.StateRoot = mockRoot.Object; Console.WriteLine($"\nNew Hash is {mockContext.Object.Block.GetHashData().ToScriptHash()}"); Console.WriteLine($"\nForcing block VerificationScript to {updatedContract.Script.ToScriptHash()}"); // The default behavior for BlockBase, when PrevHash = UInt256.Zero, is to use its own Witness @@ -359,10 +368,11 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"\nNew Hash is {mockContext.Object.Block.GetHashData().ToScriptHash()}"); Console.WriteLine("\nCN4 simulation time - Final needed signatures"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 3, kp_array[3], mockContext.Object.Block.GetHashData())); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 3, kp_array[3], mockContext.Object.Block.GetHashData(), originalStateRootData)); Console.WriteLine("\nWait for subscriber Block"); var utBlock = subscriber.ExpectMsg(); + var stateroot = subscriber.ExpectMsg(); Console.WriteLine("\nAsserting CountCommitted is 5..."); mockContext.Object.CountCommitted.Should().Be(5); @@ -377,7 +387,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.Block.Transactions = null; // ensuring same hash as snapshot mockContext.Object.Block.PrevHash = oldPrevHash; - Console.WriteLine("\nAsserting CountCommitted is 0..."); mockContext.Object.CountCommitted.Should().Be(0); Console.WriteLine($"\nAsserting CountFailed is 0..."); @@ -427,7 +436,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm /// new ValidatorIndex for the cpToCopy /// KeyPair that will be used for signing the Commit message used for creating blocks /// HashCode of the Block that is being produced and current being signed - public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload cpToCopy, ushort vI, KeyPair kp, byte[] blockHashToSign) + public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload cpToCopy, ushort vI, KeyPair kp, byte[] blockHashToSign, byte[] rootHashToSign) { var cpCommitTemp = cpToCopy.ToArray().AsSerializable(); cpCommitTemp.ValidatorIndex = vI; @@ -435,7 +444,8 @@ public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload c cpCommitTemp.ConsensusMessage = new Commit { ViewNumber = oldViewNumber, - Signature = Crypto.Sign(blockHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false).Skip(1).ToArray()) + BlockSignature = Crypto.Sign(blockHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false)[1..]), + StateRootSignature = Crypto.Sign(rootHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false)[1..]), }; SignPayload(cpCommitTemp, kp); return cpCommitTemp; @@ -486,6 +496,7 @@ public void TestSerializeAndDeserializeConsensusContext() } }, ViewNumber = 2, + ProposalStateRoot = UInt256.Zero, Validators = new ECPoint[7] { ECPoint.Parse("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", Neo.Cryptography.ECC.ECCurve.Secp256r1), @@ -517,7 +528,8 @@ public void TestSerializeAndDeserializeConsensusContext() var prepareRequestMessage = new PrepareRequest { TransactionHashes = consensusContext.TransactionHashes, - Timestamp = 23 + Timestamp = 23, + ProposalStateRoot = UInt256.Zero }; consensusContext.PreparationPayloads[6] = MakeSignedPayload(consensusContext, prepareRequestMessage, 6, new[] { (byte)'3', (byte)'!' }); consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 0, new[] { (byte)'t', (byte)'e' }); @@ -530,8 +542,16 @@ public void TestSerializeAndDeserializeConsensusContext() consensusContext.CommitPayloads = new ConsensusPayload[consensusContext.Validators.Length]; using (SHA256 sha256 = SHA256.Create()) { - consensusContext.CommitPayloads[3] = MakeSignedPayload(consensusContext, new Commit { Signature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() }, 3, new[] { (byte)'3', (byte)'4' }); - consensusContext.CommitPayloads[6] = MakeSignedPayload(consensusContext, new Commit { Signature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx2.Hash.ToArray())).ToArray() }, 3, new[] { (byte)'6', (byte)'7' }); + consensusContext.CommitPayloads[3] = MakeSignedPayload(consensusContext, new Commit + { + BlockSignature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray(), + StateRootSignature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() + }, 3, new[] { (byte)'3', (byte)'4' }); + consensusContext.CommitPayloads[6] = MakeSignedPayload(consensusContext, new Commit + { + BlockSignature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx2.Hash.ToArray())).ToArray(), + StateRootSignature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() + }, 3, new[] { (byte)'6', (byte)'7' }); } consensusContext.Block.Timestamp = TimeProvider.Current.UtcNow.ToTimestampMS(); @@ -711,7 +731,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR }, PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray() + TransactionHashes = txs.Select(p => p.Hash).ToArray(), + ProposalStateRoot = UInt256.Zero }, PreparationHash = new UInt256(Crypto.Hash256(new[] { (byte)'a' })), PreparationMessages = new Dictionary() @@ -764,7 +785,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray() + TransactionHashes = txs.Select(p => p.Hash).ToArray(), + ProposalStateRoot = UInt256.Zero }, PreparationMessages = new Dictionary() { @@ -824,7 +846,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray() + TransactionHashes = txs.Select(p => p.Hash).ToArray(), + ProposalStateRoot = UInt256.Zero }, PreparationMessages = new Dictionary() { @@ -868,7 +891,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.CommitPayloadCompact { ValidatorIndex = 1, - Signature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + BlockSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + StateRootSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, InvocationScript = new[] { (byte)'1', (byte)'2' } } }, @@ -877,7 +901,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.CommitPayloadCompact { ValidatorIndex = 6, - Signature = new byte[64] { (byte)'3', (byte)'D', (byte)'R', (byte)'I', (byte)'N', (byte)'K', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + BlockSignature = new byte[64] { (byte)'3', (byte)'D', (byte)'R', (byte)'I', (byte)'N', (byte)'K', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + StateRootSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, InvocationScript = new[] { (byte)'6', (byte)'7' } } } From c87bc170070503dff76fa2ea06f9c830a2ccbf4c Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 15:09:16 +0800 Subject: [PATCH 20/40] rename --- src/neo/Consensus/ConsensusContext.cs | 2 +- src/neo/Consensus/ConsensusService.cs | 2 +- src/neo/Ledger/Blockchain.state.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 3091ea706e..c16d26785b 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -458,7 +458,7 @@ public void Reset(byte viewNumber) TransactionHashes = null; PreparationPayloads = new ConsensusPayload[Validators.Length]; if (MyIndex >= 0) LastSeenMessage[MyIndex] = (int)Block.Index; - ProposalStateRoot = Blockchain.Singleton.GetStateRoot(Block.Index - 1); + ProposalStateRoot = Blockchain.Singleton.GetLocalStateRoot(Block.Index - 1); } public void Save() diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index bc3b9521c4..0b06dab2f0 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -430,7 +430,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m return; } - if (message.ProposalStateRoot != Blockchain.Singleton.GetStateRoot(context.Block.Index - 1)) + if (message.ProposalStateRoot != Blockchain.Singleton.GetLocalStateRoot(context.Block.Index - 1)) { Log($"Invalid request: state root incorrect.", LogLevel.Warning); } diff --git a/src/neo/Ledger/Blockchain.state.cs b/src/neo/Ledger/Blockchain.state.cs index a82e4977a1..9c1a7eb479 100644 --- a/src/neo/Ledger/Blockchain.state.cs +++ b/src/neo/Ledger/Blockchain.state.cs @@ -4,7 +4,7 @@ namespace Neo.Ledger { public sealed partial class Blockchain : UntypedActor { - public UInt256 GetStateRoot(uint index) + public UInt256 GetLocalStateRoot(uint index) { return UInt256.Zero; } From 44d72109c2939cffaf477b1012f69705e97a39da Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 18:19:30 +0800 Subject: [PATCH 21/40] remerge --- src/neo/Network/P2P/Payloads/StateRoot.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 9767d4675d..301b7af32f 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -47,10 +47,10 @@ Witness[] IVerifiable.Witnesses } public int Size => - sizeof(byte) + - sizeof(uint) + - UInt256.Length + - Witness.Size; + sizeof(byte) + //Version + sizeof(uint) + //Index + UInt256.Length + //Root + Witness.Size; //Witness StateRoot ICloneable.Clone() { From 0d8723cecc75c92eba116b4ceae70ba0dd2c1642 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Mon, 15 Jun 2020 18:24:39 +0800 Subject: [PATCH 22/40] rm GetMessage --- src/neo/Network/P2P/Payloads/StateRoot.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 301b7af32f..e375c6c472 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -108,11 +108,6 @@ public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; } - public byte[] GetMessage() - { - return this.GetHashData(); - } - public JObject ToJson() { var json = new JObject(); From 9c2415d4b0ee41d79da6a93ea53e1d3e8e0d07fe Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 16 Jun 2020 10:48:42 +0800 Subject: [PATCH 23/40] rename --- src/neo/Consensus/ConsensusContext.cs | 4 ++-- src/neo/Consensus/ConsensusService.cs | 4 ++-- src/neo/Consensus/PrepareRequest.cs | 6 +++--- src/neo/Network/P2P/Payloads/StateRoot.cs | 1 + tests/neo.UnitTests/Consensus/UT_Consensus.cs | 8 ++++---- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index c16d26785b..2dba033c47 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -341,7 +341,7 @@ public ConsensusPayload MakePrepareRequest() Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, TransactionHashes = TransactionHashes, - ProposalStateRoot = ProposalStateRoot + PreviousBlockStateRoot = ProposalStateRoot }); } @@ -364,7 +364,7 @@ public ConsensusPayload MakeRecoveryMessage() Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, TransactionHashes = TransactionHashes, - ProposalStateRoot = ProposalStateRoot + PreviousBlockStateRoot = ProposalStateRoot }; } return MakeSignedPayload(new RecoveryMessage() diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 0b06dab2f0..171e8db952 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -430,7 +430,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m return; } - if (message.ProposalStateRoot != Blockchain.Singleton.GetLocalStateRoot(context.Block.Index - 1)) + if (message.PreviousBlockStateRoot != Blockchain.Singleton.GetLocalStateRoot(context.Block.Index - 1)) { Log($"Invalid request: state root incorrect.", LogLevel.Warning); } @@ -440,7 +440,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m context.Block.Timestamp = message.Timestamp; context.Block.ConsensusData.Nonce = message.Nonce; - context.ProposalStateRoot = message.ProposalStateRoot; + context.ProposalStateRoot = message.PreviousBlockStateRoot; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); context.SendersFeeMonitor = new SendersFeeMonitor(); diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index 5fb748d643..460dc4c125 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -10,7 +10,7 @@ public class PrepareRequest : ConsensusMessage { public ulong Timestamp; public ulong Nonce; - public UInt256 ProposalStateRoot; + public UInt256 PreviousBlockStateRoot; public UInt256[] TransactionHashes; public override int Size => base.Size @@ -29,7 +29,7 @@ public override void Deserialize(BinaryReader reader) base.Deserialize(reader); Timestamp = reader.ReadUInt64(); Nonce = reader.ReadUInt64(); - ProposalStateRoot = reader.ReadSerializable(); + PreviousBlockStateRoot = reader.ReadSerializable(); TransactionHashes = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) throw new FormatException(); @@ -40,7 +40,7 @@ public override void Serialize(BinaryWriter writer) base.Serialize(writer); writer.Write(Timestamp); writer.Write(Nonce); - writer.Write(ProposalStateRoot); + writer.Write(PreviousBlockStateRoot); writer.Write(TransactionHashes); } } diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index e375c6c472..3456a965e6 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -17,6 +17,7 @@ public class StateRoot : ICloneable, IInventory public UInt256 Root; public Witness Witness; + InventoryType IInventory.InventoryType => InventoryType.StateRoot; private UInt256 _hash = null; diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index f55b4b4784..7ea0152799 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -529,7 +529,7 @@ public void TestSerializeAndDeserializeConsensusContext() { TransactionHashes = consensusContext.TransactionHashes, Timestamp = 23, - ProposalStateRoot = UInt256.Zero + PreviousBlockStateRoot = UInt256.Zero }; consensusContext.PreparationPayloads[6] = MakeSignedPayload(consensusContext, prepareRequestMessage, 6, new[] { (byte)'3', (byte)'!' }); consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 0, new[] { (byte)'t', (byte)'e' }); @@ -732,7 +732,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR PrepareRequestMessage = new PrepareRequest { TransactionHashes = txs.Select(p => p.Hash).ToArray(), - ProposalStateRoot = UInt256.Zero + PreviousBlockStateRoot = UInt256.Zero }, PreparationHash = new UInt256(Crypto.Hash256(new[] { (byte)'a' })), PreparationMessages = new Dictionary() @@ -786,7 +786,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC PrepareRequestMessage = new PrepareRequest { TransactionHashes = txs.Select(p => p.Hash).ToArray(), - ProposalStateRoot = UInt256.Zero + PreviousBlockStateRoot = UInt256.Zero }, PreparationMessages = new Dictionary() { @@ -847,7 +847,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm PrepareRequestMessage = new PrepareRequest { TransactionHashes = txs.Select(p => p.Hash).ToArray(), - ProposalStateRoot = UInt256.Zero + PreviousBlockStateRoot = UInt256.Zero }, PreparationMessages = new Dictionary() { From 2db1fbefebe6a6f26ae9b2b9aff6d9b5f77aa382 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 16 Jun 2020 11:21:50 +0800 Subject: [PATCH 24/40] throw exception when no script hash in state root --- src/neo/Network/P2P/Payloads/StateRoot.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 3456a965e6..4b23d19dbc 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -106,7 +106,8 @@ public bool Verify(StoreView snapshot) public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { var script_hash = Blockchain.Singleton.GetBlock(Index)?.NextConsensus; - return script_hash is null ? Array.Empty() : new UInt160[] { script_hash }; + if (script_hash is null) throw new System.InvalidOperationException("No script hash for state root verifying"); + return new UInt160[] { script_hash }; } public JObject ToJson() From 96db344ff92cec251f5e839cde0bb40d1309e24a Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 16 Jun 2020 09:13:44 +0200 Subject: [PATCH 25/40] Clean double enter --- src/neo/Network/P2P/Payloads/StateRoot.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 4b23d19dbc..5e7d2f57fa 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -17,7 +17,6 @@ public class StateRoot : ICloneable, IInventory public UInt256 Root; public Witness Witness; - InventoryType IInventory.InventoryType => InventoryType.StateRoot; private UInt256 _hash = null; From a9bc94b8db5d403c1f85eceea49bc62db9bcd09e Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 16 Jun 2020 09:14:58 +0200 Subject: [PATCH 26/40] Clean big line --- src/neo/Consensus/ConsensusService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 171e8db952..8519f34450 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -453,7 +453,8 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) || !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) + if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) || + !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) From cfe7322d7b77982630079bacd328babfd2953540 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Tue, 16 Jun 2020 15:34:15 +0800 Subject: [PATCH 27/40] format --- src/neo/Consensus/ConsensusService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 8519f34450..155cadaa80 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -453,8 +453,8 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) || - !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) + if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) + || !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) From 880957d9cf99e818335fe42a09978f693850225e Mon Sep 17 00:00:00 2001 From: KickSeason Date: Wed, 17 Jun 2020 19:00:16 +0800 Subject: [PATCH 28/40] put root sig into request and response --- src/neo/Consensus/Commit.cs | 12 +- src/neo/Consensus/ConsensusContext.cs | 59 +++--- src/neo/Consensus/ConsensusService.cs | 36 ++-- src/neo/Consensus/PrepareRequest.cs | 10 +- src/neo/Consensus/PrepareResponse.cs | 6 +- .../RecoveryMessage.CommitPayloadCompact.cs | 15 +- ...coveryMessage.PreparationPayloadCompact.cs | 12 +- src/neo/Consensus/RecoveryMessage.cs | 6 +- src/neo/Network/P2P/Payloads/StateRoot.cs | 25 +-- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 169 ++++++++++-------- 10 files changed, 187 insertions(+), 163 deletions(-) diff --git a/src/neo/Consensus/Commit.cs b/src/neo/Consensus/Commit.cs index f635a1a504..fce9b8caaf 100644 --- a/src/neo/Consensus/Commit.cs +++ b/src/neo/Consensus/Commit.cs @@ -5,24 +5,22 @@ namespace Neo.Consensus { public class Commit : ConsensusMessage { - public byte[] BlockSignature; - public byte[] StateRootSignature; - public override int Size => base.Size + BlockSignature.Length + StateRootSignature.Length; + 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); - BlockSignature = reader.ReadFixedBytes(64); - StateRootSignature = reader.ReadFixedBytes(64); + Signature = reader.ReadFixedBytes(64); } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); - writer.Write(BlockSignature); - writer.Write(StateRootSignature); + writer.Write(Signature); } } } diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 2dba033c47..ff0fbbadbf 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -1,20 +1,18 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using Neo; using Neo.Cryptography; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Ledger; -using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; namespace Neo.Consensus { @@ -26,8 +24,7 @@ internal class ConsensusContext : IDisposable, ISerializable private const byte ConsensusStatePrefix = 0xf4; public Block Block; - public UInt256 ProposalStateRoot { get; set; } - public StateRoot StateRoot { get; set; } + public StateRoot PreviousBlockStateRoot; public byte ViewNumber; public ECPoint[] Validators; public int MyIndex; @@ -92,7 +89,7 @@ public Block CreateBlock() for (int i = 0, j = 0; i < Validators.Length && j < M; i++) { if (CommitPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; - sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().BlockSignature); + sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().Signature); j++; } Block.Witness = sc.GetWitnesses()[0]; @@ -102,18 +99,20 @@ public Block CreateBlock() public StateRoot CreateStateRoot() { - EnsureStateRoot(); - if (StateRoot == null) return null; + EnsureHeader(); Contract contract = Contract.CreateMultiSigContract(M, Validators); - ContractParametersContext sc = new ContractParametersContext(StateRoot); + ContractParametersContext sc = new ContractParametersContext(PreviousBlockStateRoot); for (int i = 0, j = 0; i < Validators.Length && j < M; i++) { - if (CommitPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; - sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().StateRootSignature); + if (PreparationPayloads[i]?.ConsensusMessage.ViewNumber != ViewNumber) continue; + if (i == GetPrimaryIndex(ViewNumber)) + sc.AddSignature(contract, Validators[i], PreparationPayloads[i].GetDeserializedMessage().StateRootSignature); + else + sc.AddSignature(contract, Validators[i], PreparationPayloads[i].GetDeserializedMessage().StateRootSignature); j++; } - StateRoot.Witness = sc.GetWitnesses()[0]; - return StateRoot; + PreviousBlockStateRoot.Witness = sc.GetWitnesses()[0]; + return PreviousBlockStateRoot; } public void Deserialize(BinaryReader reader) @@ -126,7 +125,6 @@ public void Deserialize(BinaryReader reader) if (Block.NextConsensus.Equals(UInt160.Zero)) Block.NextConsensus = null; Block.ConsensusData = reader.ReadSerializable(); - ProposalStateRoot.Deserialize(reader); ViewNumber = reader.ReadByte(); TransactionHashes = reader.ReadSerializableArray(); Transaction[] transactions = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); @@ -160,16 +158,16 @@ public Block EnsureHeader() public StateRoot EnsureStateRoot() { - if (StateRoot is null) + if (PreviousBlockStateRoot is null) { - StateRoot = new StateRoot() + PreviousBlockStateRoot = new StateRoot { Version = 0, Index = Block.Index - 1, - Root = ProposalStateRoot + RootHash = Blockchain.Singleton.GetLocalStateRoot(Block.Index - 1) }; } - return StateRoot; + return PreviousBlockStateRoot; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -211,8 +209,7 @@ public ConsensusPayload MakeCommit() { return CommitPayloads[MyIndex] ?? (CommitPayloads[MyIndex] = MakeSignedPayload(new Commit { - BlockSignature = EnsureHeader().Sign(keyPair), - StateRootSignature = EnsureStateRoot().Sign(keyPair), + Signature = EnsureHeader().Sign(keyPair) })); } @@ -340,8 +337,8 @@ public ConsensusPayload MakePrepareRequest() { Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes, - PreviousBlockStateRoot = ProposalStateRoot + StateRootSignature = EnsureStateRoot().Sign(keyPair), + TransactionHashes = TransactionHashes }); } @@ -363,8 +360,7 @@ public ConsensusPayload MakeRecoveryMessage() ViewNumber = ViewNumber, Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes, - PreviousBlockStateRoot = ProposalStateRoot + TransactionHashes = TransactionHashes }; } return MakeSignedPayload(new RecoveryMessage() @@ -384,7 +380,8 @@ public ConsensusPayload MakePrepareResponse() { return PreparationPayloads[MyIndex] = MakeSignedPayload(new PrepareResponse { - PreparationHash = PreparationPayloads[Block.ConsensusData.PrimaryIndex].Hash + PreparationHash = PreparationPayloads[Block.ConsensusData.PrimaryIndex].Hash, + StateRootSignature = EnsureStateRoot().Sign(keyPair) }); } @@ -437,7 +434,7 @@ public void Reset(byte viewNumber) keyPair = account.GetKey(); break; } - StateRoot = null; + PreviousBlockStateRoot = null; } else { @@ -458,7 +455,6 @@ public void Reset(byte viewNumber) TransactionHashes = null; PreparationPayloads = new ConsensusPayload[Validators.Length]; if (MyIndex >= 0) LastSeenMessage[MyIndex] = (int)Block.Index; - ProposalStateRoot = Blockchain.Singleton.GetLocalStateRoot(Block.Index - 1); } public void Save() @@ -473,7 +469,6 @@ public void Serialize(BinaryWriter writer) writer.Write(Block.Timestamp); writer.Write(Block.NextConsensus ?? UInt160.Zero); writer.Write(Block.ConsensusData); - writer.Write(ProposalStateRoot); writer.Write(ViewNumber); writer.Write(TransactionHashes ?? new UInt256[0]); writer.Write(Transactions?.Values.ToArray() ?? new Transaction[0]); diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 155cadaa80..2a93ebeef1 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -134,9 +134,6 @@ private void CheckCommits() Block block = context.CreateBlock(); Log($"relay block: height={block.Index} hash={block.Hash} tx={block.Transactions.Length}"); blockchain.Tell(block); - StateRoot root = context.CreateStateRoot(); - Log($"relay state root: height={root.Index} hash={root.Hash} root={root.Root}"); - blockchain.Tell(root); } } @@ -168,6 +165,10 @@ private void CheckPreparations() localNode.Tell(new LocalNode.SendDirectly { Inventory = payload }); // Set timer, so we will resend the commit in case of a networking issue ChangeTimer(TimeSpan.FromMilliseconds(Blockchain.MillisecondsPerBlock)); + + StateRoot stateRoot = context.CreateStateRoot(); + Log($"relay state root, index={stateRoot.Index}, root_hash={stateRoot.RootHash}"); + blockchain.Tell(stateRoot); CheckCommits(); } } @@ -239,14 +240,12 @@ private void OnCommitReceived(ConsensusPayload payload, Commit commit) { Log($"{nameof(OnCommitReceived)}: height={payload.BlockIndex} view={commit.ViewNumber} index={payload.ValidatorIndex} nc={context.CountCommitted} nf={context.CountFailed}"); - byte[] headerHashData = context.EnsureHeader()?.GetHashData(); - byte[] stateRootHashData = context.EnsureStateRoot()?.GetHashData(); - if (headerHashData == null || stateRootHashData == null) + byte[] hashData = context.EnsureHeader()?.GetHashData(); + if (hashData == null) { existingCommitPayload = payload; } - else if (Crypto.VerifySignature(headerHashData, commit.BlockSignature, context.Validators[payload.ValidatorIndex]) - && Crypto.VerifySignature(stateRootHashData, commit.StateRootSignature, context.Validators[payload.ValidatorIndex])) + else if (Crypto.VerifySignature(hashData, commit.Signature, context.Validators[payload.ValidatorIndex])) { existingCommitPayload = payload; CheckCommits(); @@ -429,18 +428,19 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m Log($"Invalid request: transaction already exists", LogLevel.Warning); return; } - - if (message.PreviousBlockStateRoot != Blockchain.Singleton.GetLocalStateRoot(context.Block.Index - 1)) + var stateRootHashData = context.EnsureStateRoot().GetHashData(); + if (!Crypto.VerifySignature(stateRootHashData, message.StateRootSignature, context.Validators[payload.ValidatorIndex])) { - Log($"Invalid request: state root incorrect.", LogLevel.Warning); + Log($"Invalid request: invalid state root signature", LogLevel.Warning); + return; } + // Timeout extension: prepare request has been received with success // around 2*15/M=30.0/5 ~ 40% block time (for M=5) ExtendTimerByFactor(2); context.Block.Timestamp = message.Timestamp; context.Block.ConsensusData.Nonce = message.Nonce; - context.ProposalStateRoot = message.PreviousBlockStateRoot; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); context.SendersFeeMonitor = new SendersFeeMonitor(); @@ -449,12 +449,10 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m if (!context.PreparationPayloads[i].GetDeserializedMessage().PreparationHash.Equals(payload.Hash)) context.PreparationPayloads[i] = null; context.PreparationPayloads[payload.ValidatorIndex] = payload; - byte[] headerHashData = context.EnsureHeader().GetHashData(); - byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); + byte[] hashData = context.EnsureHeader().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(headerHashData, context.CommitPayloads[i].GetDeserializedMessage().BlockSignature, context.Validators[i]) - || !Crypto.VerifySignature(stateRootHashData, context.CommitPayloads[i].GetDeserializedMessage().StateRootSignature, context.Validators[i])) + if (!Crypto.VerifySignature(hashData, context.CommitPayloads[i].GetDeserializedMessage().Signature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) @@ -498,6 +496,12 @@ private void OnPrepareResponseReceived(ConsensusPayload payload, PrepareResponse if (context.PreparationPayloads[payload.ValidatorIndex] != null || context.NotAcceptingPayloadsDueToViewChanging) return; if (context.PreparationPayloads[context.Block.ConsensusData.PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[context.Block.ConsensusData.PrimaryIndex].Hash)) return; + byte[] stateRootHashData = context.EnsureStateRoot()?.GetHashData(); + if (!Crypto.VerifySignature(stateRootHashData, message.StateRootSignature, context.Validators[payload.ValidatorIndex])) + { + Log($"Invalid response: invalid state root signature, height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex}", LogLevel.Warning); + return; + } // Timeout extension: prepare response has been received with success // around 2*15/M=30.0/5 ~ 40% block time (for M=5) diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index 460dc4c125..d9d128b9e7 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -10,13 +10,13 @@ public class PrepareRequest : ConsensusMessage { public ulong Timestamp; public ulong Nonce; - public UInt256 PreviousBlockStateRoot; + public byte[] StateRootSignature; public UInt256[] TransactionHashes; public override int Size => base.Size - + sizeof(ulong) //Timestamp + + sizeof(ulong) //Timestamp + sizeof(ulong) //Nonce - + UInt256.Length //ProposalStateRoot + + StateRootSignature.GetVarSize() //StateRootSignature + TransactionHashes.GetVarSize(); //TransactionHashes public PrepareRequest() @@ -29,7 +29,7 @@ public override void Deserialize(BinaryReader reader) base.Deserialize(reader); Timestamp = reader.ReadUInt64(); Nonce = reader.ReadUInt64(); - PreviousBlockStateRoot = reader.ReadSerializable(); + StateRootSignature = reader.ReadVarBytes(1024); TransactionHashes = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) throw new FormatException(); @@ -40,7 +40,7 @@ public override void Serialize(BinaryWriter writer) base.Serialize(writer); writer.Write(Timestamp); writer.Write(Nonce); - writer.Write(PreviousBlockStateRoot); + writer.WriteVarBytes(StateRootSignature); writer.Write(TransactionHashes); } } diff --git a/src/neo/Consensus/PrepareResponse.cs b/src/neo/Consensus/PrepareResponse.cs index 7c2956ccc2..399e58604f 100644 --- a/src/neo/Consensus/PrepareResponse.cs +++ b/src/neo/Consensus/PrepareResponse.cs @@ -6,8 +6,8 @@ namespace Neo.Consensus public class PrepareResponse : ConsensusMessage { public UInt256 PreparationHash; - - public override int Size => base.Size + PreparationHash.Size; + public byte[] StateRootSignature; + public override int Size => base.Size + PreparationHash.Size + StateRootSignature.GetVarSize(); public PrepareResponse() : base(ConsensusMessageType.PrepareResponse) @@ -18,12 +18,14 @@ public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); PreparationHash = reader.ReadSerializable(); + StateRootSignature = reader.ReadVarBytes(1024); } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); writer.Write(PreparationHash); + writer.WriteVarBytes(StateRootSignature); } } } diff --git a/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs b/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs index 2792c50c9e..5d783c6796 100644 --- a/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs +++ b/src/neo/Consensus/RecoveryMessage.CommitPayloadCompact.cs @@ -10,23 +10,20 @@ public class CommitPayloadCompact : ISerializable { public byte ViewNumber; public ushort ValidatorIndex; - public byte[] BlockSignature; - public byte[] StateRootSignature; + public byte[] Signature; public byte[] InvocationScript; int ISerializable.Size => sizeof(byte) + //ViewNumber sizeof(ushort) + //ValidatorIndex - BlockSignature.Length + //BlockSignature - StateRootSignature.Length + //StateRootSignature + Signature.Length + //Signature InvocationScript.GetVarSize(); //InvocationScript void ISerializable.Deserialize(BinaryReader reader) { ViewNumber = reader.ReadByte(); ValidatorIndex = reader.ReadUInt16(); - BlockSignature = reader.ReadFixedBytes(64); - StateRootSignature = reader.ReadFixedBytes(64); + Signature = reader.ReadFixedBytes(64); InvocationScript = reader.ReadVarBytes(1024); } @@ -37,8 +34,7 @@ public static CommitPayloadCompact FromPayload(ConsensusPayload payload) { ViewNumber = message.ViewNumber, ValidatorIndex = payload.ValidatorIndex, - BlockSignature = message.BlockSignature, - StateRootSignature = message.StateRootSignature, + Signature = message.Signature, InvocationScript = payload.Witness.InvocationScript }; } @@ -47,8 +43,7 @@ void ISerializable.Serialize(BinaryWriter writer) { writer.Write(ViewNumber); writer.Write(ValidatorIndex); - writer.Write(BlockSignature); - writer.Write(StateRootSignature); + writer.Write(Signature); writer.WriteVarBytes(InvocationScript); } } diff --git a/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs b/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs index 962ae69185..5a55da1670 100644 --- a/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs +++ b/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs @@ -1,5 +1,6 @@ using Neo.IO; using Neo.Network.P2P.Payloads; +using System; using System.IO; namespace Neo.Consensus @@ -10,6 +11,7 @@ public class PreparationPayloadCompact : ISerializable { public ushort ValidatorIndex; public byte[] InvocationScript; + public byte[] StateRootSignature; int ISerializable.Size => sizeof(ushort) + //ValidatorIndex @@ -19,14 +21,21 @@ void ISerializable.Deserialize(BinaryReader reader) { ValidatorIndex = reader.ReadUInt16(); InvocationScript = reader.ReadVarBytes(1024); + StateRootSignature = reader.ReadVarBytes(1024); } public static PreparationPayloadCompact FromPayload(ConsensusPayload payload) { + byte[] state_root_sig = Array.Empty(); + if (payload.ConsensusMessage is PrepareResponse req) + state_root_sig = req.StateRootSignature; + else if (payload.ConsensusMessage is PrepareResponse resp) + state_root_sig = resp.StateRootSignature; return new PreparationPayloadCompact { ValidatorIndex = payload.ValidatorIndex, - InvocationScript = payload.Witness.InvocationScript + InvocationScript = payload.Witness.InvocationScript, + StateRootSignature = state_root_sig }; } @@ -34,6 +43,7 @@ void ISerializable.Serialize(BinaryWriter writer) { writer.Write(ValidatorIndex); writer.WriteVarBytes(InvocationScript); + writer.WriteVarBytes(StateRootSignature); } } } diff --git a/src/neo/Consensus/RecoveryMessage.cs b/src/neo/Consensus/RecoveryMessage.cs index 01276874c1..9a0aabf94a 100644 --- a/src/neo/Consensus/RecoveryMessage.cs +++ b/src/neo/Consensus/RecoveryMessage.cs @@ -77,8 +77,7 @@ internal ConsensusPayload[] GetCommitPayloadsFromRecoveryMessage(ConsensusContex ConsensusMessage = new Commit { ViewNumber = p.ViewNumber, - BlockSignature = p.BlockSignature, - StateRootSignature = p.StateRootSignature, + Signature = p.Signature }, Witness = new Witness { @@ -121,7 +120,8 @@ internal ConsensusPayload[] GetPrepareResponsePayloads(ConsensusContext context, ConsensusMessage = new PrepareResponse { ViewNumber = ViewNumber, - PreparationHash = preparationHash + PreparationHash = preparationHash, + StateRootSignature = p.StateRootSignature }, Witness = new Witness { diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 5e7d2f57fa..72f053f6e5 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -14,7 +14,7 @@ public class StateRoot : ICloneable, IInventory { public byte Version; public uint Index; - public UInt256 Root; + public UInt256 RootHash; public Witness Witness; InventoryType IInventory.InventoryType => InventoryType.StateRoot; @@ -47,10 +47,10 @@ Witness[] IVerifiable.Witnesses } public int Size => - sizeof(byte) + //Version - sizeof(uint) + //Index - UInt256.Length + //Root - Witness.Size; //Witness + sizeof(byte) + + sizeof(uint) + + UInt256.Length + + Witness.Size; StateRoot ICloneable.Clone() { @@ -58,7 +58,7 @@ StateRoot ICloneable.Clone() { Version = Version, Index = Index, - Root = Root, + RootHash = RootHash, Witness = Witness, }; } @@ -67,7 +67,7 @@ void ICloneable.FromReplica(StateRoot replica) { Version = replica.Version; Index = replica.Index; - Root = replica.Root; + RootHash = replica.RootHash; Witness = replica.Witness; } @@ -81,7 +81,7 @@ public void DeserializeUnsigned(BinaryReader reader) { Version = reader.ReadByte(); Index = reader.ReadUInt32(); - Root = reader.ReadSerializable(); + RootHash = reader.ReadSerializable(); } public void Serialize(BinaryWriter writer) @@ -94,7 +94,7 @@ public void SerializeUnsigned(BinaryWriter writer) { writer.Write(Version); writer.Write(Index); - writer.Write(Root); + writer.Write(RootHash); } public bool Verify(StoreView snapshot) @@ -109,12 +109,17 @@ public virtual UInt160[] GetScriptHashesForVerifying(StoreView snapshot) return new UInt160[] { script_hash }; } + public byte[] GetMessage() + { + return this.GetHashData(); + } + public JObject ToJson() { var json = new JObject(); json["version"] = Version; json["index"] = Index; - json["stateroot"] = Root.ToString(); + json["stateroot"] = RootHash.ToString(); json["witness"] = Witness.ToJson(); return json; } diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 7ea0152799..cf6b021824 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -10,7 +10,6 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Cryptography; @@ -48,7 +47,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm var mockContext = new Mock(mockWallet.Object, Blockchain.Singleton.Store); mockContext.Object.LastSeenMessage = new int[] { 0, 0, 0, 0, 0, 0, 0 }; - mockContext.Object.ProposalStateRoot = UInt256.Zero; + KeyPair[] kp_array = new KeyPair[7] { UT_Crypto.generateKey(32), // not used, kept for index consistency, didactically @@ -199,9 +198,23 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(6); Console.WriteLine("\nFailed because it is not primary and it created the prereq...Time to adjust"); - prepReq.ValidatorIndex = 1; //simulating primary as prepreq creator (signature is skip, no problem) + var stateRootData = mockContext.Object.EnsureStateRoot().GetHashData(); + prepReq = GetPrepareRequestAndSignStateRoot(prepReq, 1, kp_array[1], stateRootData); + //prepReq.ValidatorIndex = 1; //simulating primary as prepreq creator (signature is skip, no problem) // cleaning old try with Self ValidatorIndex mockContext.Object.PreparationPayloads[mockContext.Object.MyIndex] = null; + for (int i = 0; i < mockContext.Object.Validators.Length; i++) + Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}"); + mockContext.Object.Validators = new ECPoint[7] + { + kp_array[0].PublicKey, + kp_array[1].PublicKey, + kp_array[2].PublicKey, + kp_array[3].PublicKey, + kp_array[4].PublicKey, + kp_array[5].PublicKey, + kp_array[6].PublicKey + }; TellConsensusPayload(actorConsensus, prepReq); var OnPrepResponse = subscriber.ExpectMsg(); @@ -214,7 +227,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(5); // Simulating CN 3 - TellConsensusPayload(actorConsensus, GetPayloadAndModifyValidator(prepResponsePayload, 2)); + TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 2, kp_array[2], stateRootData)); //Waiting for RecoveryRequest for a more deterministic UT backupOnRecoveryDueToFailedNodes = subscriber.ExpectMsg(); recoveryPayload = (ConsensusPayload)backupOnRecoveryDueToFailedNodes.Inventory; @@ -227,7 +240,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(4); // Simulating CN 5 - TellConsensusPayload(actorConsensus, GetPayloadAndModifyValidator(prepResponsePayload, 4)); + TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 4, kp_array[4], stateRootData)); //Waiting for RecoveryRequest for a more deterministic UT backupOnRecoveryDueToFailedNodes = subscriber.ExpectMsg(); recoveryPayload = (ConsensusPayload)backupOnRecoveryDueToFailedNodes.Inventory; @@ -240,7 +253,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(3); // Simulating CN 4 - TellConsensusPayload(actorConsensus, GetPayloadAndModifyValidator(prepResponsePayload, 3)); + TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 3, kp_array[3], stateRootData)); var onCommitPayload = subscriber.ExpectMsg(); var commitPayload = (ConsensusPayload)onCommitPayload.Inventory; Commit cm = (Commit)commitPayload.ConsensusMessage; @@ -254,18 +267,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"ORIGINAL BlockHash: {mockContext.Object.Block.Hash}"); Console.WriteLine($"ORIGINAL Block NextConsensus: {mockContext.Object.Block.NextConsensus}"); - for (int i = 0; i < mockContext.Object.Validators.Length; i++) - Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}"); - mockContext.Object.Validators = new ECPoint[7] - { - kp_array[0].PublicKey, - kp_array[1].PublicKey, - kp_array[2].PublicKey, - kp_array[3].PublicKey, - kp_array[4].PublicKey, - kp_array[5].PublicKey, - kp_array[6].PublicKey - }; Console.WriteLine($"Generated keypairs PKey:"); for (int i = 0; i < mockContext.Object.Validators.Length; i++) Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}"); @@ -284,7 +285,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm var originalBlockHashData = mockContext.Object.Block.GetHashData(); mockContext.Object.Block.NextConsensus = updatedContract.ScriptHash; mockContext.Object.Block.Header.NextConsensus = updatedContract.ScriptHash; - var originalStateRootData = mockContext.Object.EnsureStateRoot().GetHashData(); var originalBlockMerkleRoot = mockContext.Object.Block.MerkleRoot; Console.WriteLine($"\noriginalBlockMerkleRoot: {originalBlockMerkleRoot}"); var updatedBlockHashData = mockContext.Object.Block.GetHashData(); @@ -294,15 +294,16 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("\n\n=========================="); Console.WriteLine("\nBasic commits Signatures verification"); // Basic tests for understanding signatures and ensuring signatures of commits are correct on tests - var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData, originalStateRootData); - Crypto.VerifySignature(originalBlockHashData, cm.BlockSignature, mockContext.Object.Validators[0]).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, cm.BlockSignature, mockContext.Object.Validators[0]).Should().BeFalse(); - Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).BlockSignature, mockContext.Object.Validators[6]).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).BlockSignature, mockContext.Object.Validators[6]).Should().BeTrue(); + var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData); + Crypto.VerifySignature(originalBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeTrue(); Console.WriteLine("\n=========================="); Console.WriteLine("\n=========================="); Console.WriteLine("\nCN7 simulation time"); + TellConsensusPayload(actorConsensus, cmPayloadTemp); var tempPayloadToBlockAndWait = subscriber.ExpectMsg(); var rmPayload = (ConsensusPayload)tempPayloadToBlockAndWait.Inventory; @@ -313,7 +314,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(1); Console.WriteLine("\nCN6 simulation time"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData, originalStateRootData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 5, kp_array[5], updatedBlockHashData)); tempPayloadToBlockAndWait = subscriber.ExpectMsg(); rmPayload = (ConsensusPayload)tempPayloadToBlockAndWait.Inventory; rmm = (RecoveryMessage)rmPayload.ConsensusMessage; @@ -323,7 +324,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.CountFailed.Should().Be(0); Console.WriteLine("\nCN5 simulation time"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData, originalStateRootData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 4, kp_array[4], updatedBlockHashData)); tempPayloadToBlockAndWait = subscriber.ExpectMsg(); Console.WriteLine("\nAsserting CountCommitted is 4..."); mockContext.Object.CountCommitted.Should().Be(4); @@ -352,13 +353,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.Block.PrevHash = UInt256.Zero; //Payload should also be forced, otherwise OnConsensus will not pass commitPayload.PrevHash = UInt256.Zero; - var root = mockContext.Object.EnsureStateRoot(); - var mockRoot = new Mock(); - mockRoot.Object.Version = root.Version; - mockRoot.Object.Index = root.Index; - mockRoot.Object.Root = root.Root; - mockRoot.Setup(p => p.GetScriptHashesForVerifying(It.IsAny())).Returns(p => new UInt160[] { updatedContract.ScriptHash }); - mockContext.Object.StateRoot = mockRoot.Object; Console.WriteLine($"\nNew Hash is {mockContext.Object.Block.GetHashData().ToScriptHash()}"); Console.WriteLine($"\nForcing block VerificationScript to {updatedContract.Script.ToScriptHash()}"); // The default behavior for BlockBase, when PrevHash = UInt256.Zero, is to use its own Witness @@ -368,11 +362,10 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"\nNew Hash is {mockContext.Object.Block.GetHashData().ToScriptHash()}"); Console.WriteLine("\nCN4 simulation time - Final needed signatures"); - TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 3, kp_array[3], mockContext.Object.Block.GetHashData(), originalStateRootData)); + TellConsensusPayload(actorConsensus, GetCommitPayloadModifiedAndSignedCopy(commitPayload, 3, kp_array[3], mockContext.Object.Block.GetHashData())); Console.WriteLine("\nWait for subscriber Block"); var utBlock = subscriber.ExpectMsg(); - var stateroot = subscriber.ExpectMsg(); Console.WriteLine("\nAsserting CountCommitted is 5..."); mockContext.Object.CountCommitted.Should().Be(5); @@ -387,6 +380,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.Block.Transactions = null; // ensuring same hash as snapshot mockContext.Object.Block.PrevHash = oldPrevHash; + Console.WriteLine("\nAsserting CountCommitted is 0..."); mockContext.Object.CountCommitted.Should().Be(0); Console.WriteLine($"\nAsserting CountFailed is 0..."); @@ -436,7 +430,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm /// new ValidatorIndex for the cpToCopy /// KeyPair that will be used for signing the Commit message used for creating blocks /// HashCode of the Block that is being produced and current being signed - public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload cpToCopy, ushort vI, KeyPair kp, byte[] blockHashToSign, byte[] rootHashToSign) + public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload cpToCopy, ushort vI, KeyPair kp, byte[] blockHashToSign) { var cpCommitTemp = cpToCopy.ToArray().AsSerializable(); cpCommitTemp.ValidatorIndex = vI; @@ -444,8 +438,7 @@ public ConsensusPayload GetCommitPayloadModifiedAndSignedCopy(ConsensusPayload c cpCommitTemp.ConsensusMessage = new Commit { ViewNumber = oldViewNumber, - BlockSignature = Crypto.Sign(blockHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false)[1..]), - StateRootSignature = Crypto.Sign(rootHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false)[1..]), + Signature = Crypto.Sign(blockHashToSign, kp.PrivateKey, kp.PublicKey.EncodePoint(false).Skip(1).ToArray()) }; SignPayload(cpCommitTemp, kp); return cpCommitTemp; @@ -463,6 +456,25 @@ public ConsensusPayload GetPayloadAndModifyValidator(ConsensusPayload cpToCopy, return cpTemp; } + public ConsensusPayload GetPrepareRequestAndSignStateRoot(ConsensusPayload req, ushort vI, KeyPair kp, byte[] stateRootData) + { + var tmp = req.ToArray().AsSerializable(); + tmp.ValidatorIndex = vI; + var message = tmp.GetDeserializedMessage(); + message.StateRootSignature = Crypto.Sign(stateRootData, kp.PrivateKey, kp.PublicKey.EncodePoint(false).Skip(1).ToArray()); + tmp.ConsensusMessage = message; + return tmp; + } + public ConsensusPayload GetPrepareResponsePayloadAndSignStateRoot(ConsensusPayload resp, ushort vI, KeyPair kp, byte[] stateRootData) + { + var tmp = resp.ToArray().AsSerializable(); + tmp.ValidatorIndex = vI; + var message = tmp.GetDeserializedMessage(); + message.StateRootSignature = Crypto.Sign(stateRootData, kp.PrivateKey, kp.PublicKey.EncodePoint(false).Skip(1).ToArray()); + tmp.ConsensusMessage = message; + return tmp; + } + private void SignPayload(ConsensusPayload payload, KeyPair kp) { ContractParametersContext sc; @@ -496,7 +508,6 @@ public void TestSerializeAndDeserializeConsensusContext() } }, ViewNumber = 2, - ProposalStateRoot = UInt256.Zero, Validators = new ECPoint[7] { ECPoint.Parse("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", Neo.Cryptography.ECC.ECCurve.Secp256r1), @@ -529,29 +540,21 @@ public void TestSerializeAndDeserializeConsensusContext() { TransactionHashes = consensusContext.TransactionHashes, Timestamp = 23, - PreviousBlockStateRoot = UInt256.Zero + StateRootSignature = new byte[] { 0x01 } }; consensusContext.PreparationPayloads[6] = MakeSignedPayload(consensusContext, prepareRequestMessage, 6, new[] { (byte)'3', (byte)'!' }); - consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 0, new[] { (byte)'t', (byte)'e' }); - consensusContext.PreparationPayloads[1] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 1, new[] { (byte)'s', (byte)'t' }); + consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 0, new[] { (byte)'t', (byte)'e' }); + consensusContext.PreparationPayloads[1] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 1, new[] { (byte)'s', (byte)'t' }); consensusContext.PreparationPayloads[2] = null; - consensusContext.PreparationPayloads[3] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash }, 3, new[] { (byte)'1', (byte)'2' }); + consensusContext.PreparationPayloads[3] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 3, new[] { (byte)'1', (byte)'2' }); consensusContext.PreparationPayloads[4] = null; consensusContext.PreparationPayloads[5] = null; consensusContext.CommitPayloads = new ConsensusPayload[consensusContext.Validators.Length]; using (SHA256 sha256 = SHA256.Create()) { - consensusContext.CommitPayloads[3] = MakeSignedPayload(consensusContext, new Commit - { - BlockSignature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray(), - StateRootSignature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() - }, 3, new[] { (byte)'3', (byte)'4' }); - consensusContext.CommitPayloads[6] = MakeSignedPayload(consensusContext, new Commit - { - BlockSignature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx2.Hash.ToArray())).ToArray(), - StateRootSignature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() - }, 3, new[] { (byte)'6', (byte)'7' }); + consensusContext.CommitPayloads[3] = MakeSignedPayload(consensusContext, new Commit { Signature = sha256.ComputeHash(testTx1.Hash.ToArray()).Concat(sha256.ComputeHash(testTx1.Hash.ToArray())).ToArray() }, 3, new[] { (byte)'3', (byte)'4' }); + consensusContext.CommitPayloads[6] = MakeSignedPayload(consensusContext, new Commit { Signature = sha256.ComputeHash(testTx2.Hash.ToArray()).Concat(sha256.ComputeHash(testTx2.Hash.ToArray())).ToArray() }, 3, new[] { (byte)'6', (byte)'7' }); } consensusContext.Block.Timestamp = TimeProvider.Current.UtcNow.ToTimestampMS(); @@ -641,7 +644,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 0, - InvocationScript = new[] { (byte)'t', (byte)'e' } + InvocationScript = new[] { (byte)'t', (byte)'e' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -649,7 +653,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 3, - InvocationScript = new[] { (byte)'1', (byte)'2' } + InvocationScript = new[] { (byte)'1', (byte)'2' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -657,7 +662,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 6, - InvocationScript = new[] { (byte)'3', (byte)'!' } + InvocationScript = new[] { (byte)'3', (byte)'!' }, + StateRootSignature = new byte[] { 0x01 } } } }, @@ -731,8 +737,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR }, PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray(), - PreviousBlockStateRoot = UInt256.Zero + StateRootSignature = new byte[] { 0x01 }, + TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationHash = new UInt256(Crypto.Hash256(new[] { (byte)'a' })), PreparationMessages = new Dictionary() @@ -742,7 +748,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 0, - InvocationScript = new[] { (byte)'t', (byte)'e' } + InvocationScript = new[] { (byte)'t', (byte)'e' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -750,7 +757,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 1, - InvocationScript = new[] { (byte)'s', (byte)'t' } + InvocationScript = new[] { (byte)'s', (byte)'t' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -758,7 +766,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 3, - InvocationScript = new[] { (byte)'1', (byte)'2' } + InvocationScript = new[] { (byte)'1', (byte)'2' }, + StateRootSignature = new byte[] { 0x01 }, } } }, @@ -785,8 +794,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray(), - PreviousBlockStateRoot = UInt256.Zero + StateRootSignature = new byte[] { 0x01 }, + TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationMessages = new Dictionary() { @@ -795,7 +804,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 0, - InvocationScript = new[] { (byte)'t', (byte)'e' } + InvocationScript = new[] { (byte)'t', (byte)'e' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -803,7 +813,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 1, - InvocationScript = new[] { (byte)'s', (byte)'t' } + InvocationScript = new[] { (byte)'s', (byte)'t' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -811,7 +822,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 3, - InvocationScript = new[] { (byte)'1', (byte)'2' } + InvocationScript = new[] { (byte)'1', (byte)'2' }, + StateRootSignature = new byte[] { 0x01 } } }, { @@ -819,7 +831,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 6, - InvocationScript = new[] { (byte)'3', (byte)'!' } + InvocationScript = new[] { (byte)'3', (byte)'!' }, + StateRootSignature = new byte[] { 0x01 } } } }, @@ -846,8 +859,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - TransactionHashes = txs.Select(p => p.Hash).ToArray(), - PreviousBlockStateRoot = UInt256.Zero + StateRootSignature = new byte[] { 0x01 }, + TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationMessages = new Dictionary() { @@ -856,7 +869,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 0, - InvocationScript = new[] { (byte)'t', (byte)'e' } + InvocationScript = new[] { (byte)'t', (byte)'e' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -864,7 +878,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 1, - InvocationScript = new[] { (byte)'s', (byte)'t' } + InvocationScript = new[] { (byte)'s', (byte)'t' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -872,7 +887,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 3, - InvocationScript = new[] { (byte)'1', (byte)'2' } + InvocationScript = new[] { (byte)'1', (byte)'2' }, + StateRootSignature = new byte[] { 0x01 }, } }, { @@ -880,7 +896,8 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = 6, - InvocationScript = new[] { (byte)'3', (byte)'!' } + InvocationScript = new[] { (byte)'3', (byte)'!' }, + StateRootSignature = new byte[] { 0x01 }, } } }, @@ -891,8 +908,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.CommitPayloadCompact { ValidatorIndex = 1, - BlockSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - StateRootSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + Signature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, InvocationScript = new[] { (byte)'1', (byte)'2' } } }, @@ -901,8 +917,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm new RecoveryMessage.CommitPayloadCompact { ValidatorIndex = 6, - BlockSignature = new byte[64] { (byte)'3', (byte)'D', (byte)'R', (byte)'I', (byte)'N', (byte)'K', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - StateRootSignature = new byte[64] { (byte)'1', (byte)'2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + Signature = new byte[64] { (byte)'3', (byte)'D', (byte)'R', (byte)'I', (byte)'N', (byte)'K', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, InvocationScript = new[] { (byte)'6', (byte)'7' } } } From d24c43c80f9a0b36d5d3a81084d2f7674a586757 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 14:21:22 +0800 Subject: [PATCH 29/40] update consensus ut --- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index cf6b021824..3b4a259b35 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -10,6 +10,7 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Cryptography; @@ -182,6 +183,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm // Forcing hashes to 0 because mempool is currently shared ppToSend.TransactionHashes = new UInt256[0]; ppToSend.TransactionHashes.Length.Should().Be(0); + prepReq.Data = ppToSend.ToArray(); Console.WriteLine($"\nAsserting PreparationPayloads is 1 (After MakePrepareRequest)..."); mockContext.Object.PreparationPayloads.Count(p => p != null).Should().Be(1); mockContext.Object.PreparationPayloads[prepReq.ValidatorIndex] = null; @@ -215,6 +217,10 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm kp_array[5].PublicKey, kp_array[6].PublicKey }; + mockContext.Object.GetPrimaryIndex(mockContext.Object.ViewNumber).Should().Be(1); + mockContext.Object.MyIndex.Should().Be(0); + Console.WriteLine($"\nAsserting tx count is 0..."); + prepReq.GetDeserializedMessage().TransactionHashes.Count().Should().Be(0); TellConsensusPayload(actorConsensus, prepReq); var OnPrepResponse = subscriber.ExpectMsg(); @@ -225,6 +231,10 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.PreparationPayloads.Count(p => p != null).Should().Be(2); Console.WriteLine($"\nAsserting CountFailed is 5..."); mockContext.Object.CountFailed.Should().Be(5); + Console.WriteLine("\nAsserting PrepareResponse ValidatorIndex is 0..."); + prepResponsePayload.ValidatorIndex.Should().Be(0); + // Using correct signed response to replace prepareresponse sent + mockContext.Object.PreparationPayloads[prepResponsePayload.ValidatorIndex] = GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 0, kp_array[0], stateRootData); // Simulating CN 3 TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 2, kp_array[2], stateRootData)); @@ -251,10 +261,20 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm mockContext.Object.PreparationPayloads.Count(p => p != null).Should().Be(4); Console.WriteLine($"\nAsserting CountFailed is 3..."); mockContext.Object.CountFailed.Should().Be(3); + var updatedContract = Contract.CreateMultiSigContract(mockContext.Object.M, mockContext.Object.Validators); + // Mock StateRoot to use mock Validators to sign + var root = mockContext.Object.EnsureStateRoot(); + var mockRoot = new Mock(); + mockRoot.Object.Version = root.Version; + mockRoot.Object.Index = root.Index; + mockRoot.Object.RootHash = root.RootHash; + mockRoot.Setup(p => p.GetScriptHashesForVerifying(It.IsAny())).Returns(p => new UInt160[] { updatedContract.ScriptHash }); + mockContext.Object.PreviousBlockStateRoot = mockRoot.Object; // Simulating CN 4 TellConsensusPayload(actorConsensus, GetPrepareResponsePayloadAndSignStateRoot(prepResponsePayload, 3, kp_array[3], stateRootData)); var onCommitPayload = subscriber.ExpectMsg(); + var onStateRoot = subscriber.ExpectMsg(); var commitPayload = (ConsensusPayload)onCommitPayload.Inventory; Commit cm = (Commit)commitPayload.ConsensusMessage; Console.WriteLine("\nAsserting PreparationPayloads count is 5..."); @@ -270,7 +290,6 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine($"Generated keypairs PKey:"); for (int i = 0; i < mockContext.Object.Validators.Length; i++) Console.WriteLine($"{mockContext.Object.Validators[i]}/{Contract.CreateSignatureContract(mockContext.Object.Validators[i]).ScriptHash}"); - var updatedContract = Contract.CreateMultiSigContract(mockContext.Object.M, mockContext.Object.Validators); Console.WriteLine($"\nContract updated: {updatedContract.ScriptHash}"); // =============================================================== From 56ea966da8fd7d76a74f0d1036b89a785f863f0e Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:02:11 +0800 Subject: [PATCH 30/40] fix some --- src/neo/Consensus/PrepareRequest.cs | 2 +- .../Consensus/RecoveryMessage.PreparationPayloadCompact.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index d9d128b9e7..a133092173 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -10,8 +10,8 @@ public class PrepareRequest : ConsensusMessage { public ulong Timestamp; public ulong Nonce; - public byte[] StateRootSignature; public UInt256[] TransactionHashes; + public byte[] StateRootSignature; public override int Size => base.Size + sizeof(ulong) //Timestamp diff --git a/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs b/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs index 5a55da1670..06c3d1b039 100644 --- a/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs +++ b/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs @@ -14,8 +14,9 @@ public class PreparationPayloadCompact : ISerializable public byte[] StateRootSignature; int ISerializable.Size => - sizeof(ushort) + //ValidatorIndex - InvocationScript.GetVarSize(); //InvocationScript + sizeof(ushort) + //ValidatorIndex + InvocationScript.GetVarSize() + //InvocationScript + StateRootSignature.GetVarSize(); //StateRootSignature void ISerializable.Deserialize(BinaryReader reader) { From 1d30bb045d8c7be102f7394abe8b671a26fb0f10 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:07:06 +0800 Subject: [PATCH 31/40] fix some --- src/neo/Consensus/PrepareRequest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index a133092173..cc0a19b56d 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -29,10 +29,10 @@ public override void Deserialize(BinaryReader reader) base.Deserialize(reader); Timestamp = reader.ReadUInt64(); Nonce = reader.ReadUInt64(); - StateRootSignature = reader.ReadVarBytes(1024); TransactionHashes = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) throw new FormatException(); + StateRootSignature = reader.ReadVarBytes(1024); } public override void Serialize(BinaryWriter writer) @@ -40,8 +40,8 @@ public override void Serialize(BinaryWriter writer) base.Serialize(writer); writer.Write(Timestamp); writer.Write(Nonce); - writer.WriteVarBytes(StateRootSignature); writer.Write(TransactionHashes); + writer.WriteVarBytes(StateRootSignature); } } } From 32fed3c08d429ae2b65b29eae00466a12c9f8ee5 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:08:49 +0800 Subject: [PATCH 32/40] format --- src/neo/Consensus/PrepareRequest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index cc0a19b56d..18ee0ca27d 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -14,10 +14,10 @@ public class PrepareRequest : ConsensusMessage public byte[] StateRootSignature; public override int Size => base.Size - + sizeof(ulong) //Timestamp + + sizeof(ulong) //Timestamp + sizeof(ulong) //Nonce - + StateRootSignature.GetVarSize() //StateRootSignature - + TransactionHashes.GetVarSize(); //TransactionHashes + + TransactionHashes.GetVarSize() //TransactionHashes + + StateRootSignature.GetVarSize(); //StateRootSignature public PrepareRequest() : base(ConsensusMessageType.PrepareRequest) From d33d445281d1192270a1fd6336d16b3dd51c2ed6 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:16:57 +0800 Subject: [PATCH 33/40] comment --- src/neo/Network/P2P/Payloads/StateRoot.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/StateRoot.cs b/src/neo/Network/P2P/Payloads/StateRoot.cs index 72f053f6e5..b55dba8f80 100644 --- a/src/neo/Network/P2P/Payloads/StateRoot.cs +++ b/src/neo/Network/P2P/Payloads/StateRoot.cs @@ -47,10 +47,10 @@ Witness[] IVerifiable.Witnesses } public int Size => - sizeof(byte) + - sizeof(uint) + - UInt256.Length + - Witness.Size; + sizeof(byte) + //Version + sizeof(uint) + //Index + UInt256.Length + //RootHash + Witness.Size; //Witness StateRoot ICloneable.Clone() { From a797876692f6c447fe0b2131123fc0eba73c55d0 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:28:34 +0800 Subject: [PATCH 34/40] fix --- src/neo/Consensus/ConsensusContext.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index ff0fbbadbf..214d85dc71 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -360,7 +360,8 @@ public ConsensusPayload MakeRecoveryMessage() ViewNumber = ViewNumber, Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes + TransactionHashes = TransactionHashes, + StateRootSignature = EnsureStateRoot().Sign(keyPair) }; } return MakeSignedPayload(new RecoveryMessage() From 5567612e7f67cc06af84de846ba60ff94f4a0ef3 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:30:25 +0800 Subject: [PATCH 35/40] requst in recovery --- src/neo/Consensus/ConsensusContext.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 214d85dc71..2fc7cf0b76 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -355,14 +355,7 @@ public ConsensusPayload MakeRecoveryMessage() PrepareRequest prepareRequestMessage = null; if (TransactionHashes != null) { - prepareRequestMessage = new PrepareRequest - { - ViewNumber = ViewNumber, - Timestamp = Block.Timestamp, - Nonce = Block.ConsensusData.Nonce, - TransactionHashes = TransactionHashes, - StateRootSignature = EnsureStateRoot().Sign(keyPair) - }; + prepareRequestMessage = PreparationPayloads[GetPrimaryIndex(ViewNumber)].GetDeserializedMessage(); } return MakeSignedPayload(new RecoveryMessage() { From 7dfb06df491804c92fda28a1b808712ebd991e9a Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:33:14 +0800 Subject: [PATCH 36/40] StateRootSignature fixed size --- src/neo/Consensus/ConsensusContext.cs | 4 +- src/neo/Consensus/PrepareRequest.cs | 6 +-- src/neo/Consensus/PrepareResponse.cs | 6 +-- ...coveryMessage.PreparationPayloadCompact.cs | 6 +-- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 42 +++++++++---------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 2fc7cf0b76..614be96323 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -337,8 +337,8 @@ public ConsensusPayload MakePrepareRequest() { Timestamp = Block.Timestamp, Nonce = Block.ConsensusData.Nonce, - StateRootSignature = EnsureStateRoot().Sign(keyPair), - TransactionHashes = TransactionHashes + TransactionHashes = TransactionHashes, + StateRootSignature = EnsureStateRoot().Sign(keyPair) }); } diff --git a/src/neo/Consensus/PrepareRequest.cs b/src/neo/Consensus/PrepareRequest.cs index 18ee0ca27d..659c5ff795 100644 --- a/src/neo/Consensus/PrepareRequest.cs +++ b/src/neo/Consensus/PrepareRequest.cs @@ -17,7 +17,7 @@ public class PrepareRequest : ConsensusMessage + sizeof(ulong) //Timestamp + sizeof(ulong) //Nonce + TransactionHashes.GetVarSize() //TransactionHashes - + StateRootSignature.GetVarSize(); //StateRootSignature + + StateRootSignature.Length; //StateRootSignature public PrepareRequest() : base(ConsensusMessageType.PrepareRequest) @@ -32,7 +32,7 @@ public override void Deserialize(BinaryReader reader) TransactionHashes = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) throw new FormatException(); - StateRootSignature = reader.ReadVarBytes(1024); + StateRootSignature = reader.ReadFixedBytes(64); } public override void Serialize(BinaryWriter writer) @@ -41,7 +41,7 @@ public override void Serialize(BinaryWriter writer) writer.Write(Timestamp); writer.Write(Nonce); writer.Write(TransactionHashes); - writer.WriteVarBytes(StateRootSignature); + writer.Write(StateRootSignature); } } } diff --git a/src/neo/Consensus/PrepareResponse.cs b/src/neo/Consensus/PrepareResponse.cs index 399e58604f..97b4c4234a 100644 --- a/src/neo/Consensus/PrepareResponse.cs +++ b/src/neo/Consensus/PrepareResponse.cs @@ -7,7 +7,7 @@ public class PrepareResponse : ConsensusMessage { public UInt256 PreparationHash; public byte[] StateRootSignature; - public override int Size => base.Size + PreparationHash.Size + StateRootSignature.GetVarSize(); + public override int Size => base.Size + PreparationHash.Size + StateRootSignature.Length; public PrepareResponse() : base(ConsensusMessageType.PrepareResponse) @@ -18,14 +18,14 @@ public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); PreparationHash = reader.ReadSerializable(); - StateRootSignature = reader.ReadVarBytes(1024); + StateRootSignature = reader.ReadFixedBytes(64); } public override void Serialize(BinaryWriter writer) { base.Serialize(writer); writer.Write(PreparationHash); - writer.WriteVarBytes(StateRootSignature); + writer.Write(StateRootSignature); } } } diff --git a/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs b/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs index 06c3d1b039..ceac4563fc 100644 --- a/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs +++ b/src/neo/Consensus/RecoveryMessage.PreparationPayloadCompact.cs @@ -16,13 +16,13 @@ public class PreparationPayloadCompact : ISerializable int ISerializable.Size => sizeof(ushort) + //ValidatorIndex InvocationScript.GetVarSize() + //InvocationScript - StateRootSignature.GetVarSize(); //StateRootSignature + StateRootSignature.Length; //StateRootSignature void ISerializable.Deserialize(BinaryReader reader) { ValidatorIndex = reader.ReadUInt16(); InvocationScript = reader.ReadVarBytes(1024); - StateRootSignature = reader.ReadVarBytes(1024); + StateRootSignature = reader.ReadFixedBytes(64); } public static PreparationPayloadCompact FromPayload(ConsensusPayload payload) @@ -44,7 +44,7 @@ void ISerializable.Serialize(BinaryWriter writer) { writer.Write(ValidatorIndex); writer.WriteVarBytes(InvocationScript); - writer.WriteVarBytes(StateRootSignature); + writer.Write(StateRootSignature); } } } diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 3b4a259b35..d8d959ac09 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -559,13 +559,13 @@ public void TestSerializeAndDeserializeConsensusContext() { TransactionHashes = consensusContext.TransactionHashes, Timestamp = 23, - StateRootSignature = new byte[] { 0x01 } + StateRootSignature = new byte[64] }; consensusContext.PreparationPayloads[6] = MakeSignedPayload(consensusContext, prepareRequestMessage, 6, new[] { (byte)'3', (byte)'!' }); - consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 0, new[] { (byte)'t', (byte)'e' }); - consensusContext.PreparationPayloads[1] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 1, new[] { (byte)'s', (byte)'t' }); + consensusContext.PreparationPayloads[0] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[64] }, 0, new[] { (byte)'t', (byte)'e' }); + consensusContext.PreparationPayloads[1] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[64] }, 1, new[] { (byte)'s', (byte)'t' }); consensusContext.PreparationPayloads[2] = null; - consensusContext.PreparationPayloads[3] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[] { 0x01 } }, 3, new[] { (byte)'1', (byte)'2' }); + consensusContext.PreparationPayloads[3] = MakeSignedPayload(consensusContext, new PrepareResponse { PreparationHash = consensusContext.PreparationPayloads[6].Hash, StateRootSignature = new byte[64] }, 3, new[] { (byte)'1', (byte)'2' }); consensusContext.PreparationPayloads[4] = null; consensusContext.PreparationPayloads[5] = null; @@ -664,7 +664,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar { ValidatorIndex = 0, InvocationScript = new[] { (byte)'t', (byte)'e' }, - StateRootSignature = new byte[] { 0x01 } + StateRootSignature = new byte[64] } }, { @@ -673,7 +673,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar { ValidatorIndex = 3, InvocationScript = new[] { (byte)'1', (byte)'2' }, - StateRootSignature = new byte[] { 0x01 } + StateRootSignature = new byte[64] } }, { @@ -682,7 +682,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndNoPrepar { ValidatorIndex = 6, InvocationScript = new[] { (byte)'3', (byte)'!' }, - StateRootSignature = new byte[] { 0x01 } + StateRootSignature = new byte[64] } } }, @@ -756,7 +756,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR }, PrepareRequestMessage = new PrepareRequest { - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationHash = new UInt256(Crypto.Hash256(new[] { (byte)'a' })), @@ -768,7 +768,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR { ValidatorIndex = 0, InvocationScript = new[] { (byte)'t', (byte)'e' }, - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], } }, { @@ -777,7 +777,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR { ValidatorIndex = 1, InvocationScript = new[] { (byte)'s', (byte)'t' }, - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], } }, { @@ -786,7 +786,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithChangeViewsAndPrepareR { ValidatorIndex = 3, InvocationScript = new[] { (byte)'1', (byte)'2' }, - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], } } }, @@ -813,7 +813,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationMessages = new Dictionary() @@ -824,7 +824,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC { ValidatorIndex = 0, InvocationScript = new[] { (byte)'t', (byte)'e' }, - StateRootSignature = new byte[] { 0x01 } + StateRootSignature = new byte[64] } }, { @@ -833,7 +833,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC { ValidatorIndex = 1, InvocationScript = new[] { (byte)'s', (byte)'t' }, - StateRootSignature = new byte[] { 0x01 } + StateRootSignature = new byte[64] } }, { @@ -842,7 +842,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC { ValidatorIndex = 3, InvocationScript = new[] { (byte)'1', (byte)'2' }, - StateRootSignature = new byte[] { 0x01 } + StateRootSignature = new byte[64] } }, { @@ -851,7 +851,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithoutC { ValidatorIndex = 6, InvocationScript = new[] { (byte)'3', (byte)'!' }, - StateRootSignature = new byte[] { 0x01 } + StateRootSignature = new byte[64] } } }, @@ -878,7 +878,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm ChangeViewMessages = new Dictionary(), PrepareRequestMessage = new PrepareRequest { - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], TransactionHashes = txs.Select(p => p.Hash).ToArray() }, PreparationMessages = new Dictionary() @@ -889,7 +889,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm { ValidatorIndex = 0, InvocationScript = new[] { (byte)'t', (byte)'e' }, - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], } }, { @@ -898,7 +898,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm { ValidatorIndex = 1, InvocationScript = new[] { (byte)'s', (byte)'t' }, - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], } }, { @@ -907,7 +907,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm { ValidatorIndex = 3, InvocationScript = new[] { (byte)'1', (byte)'2' }, - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], } }, { @@ -916,7 +916,7 @@ public void TestSerializeAndDeserializeRecoveryMessageWithoutChangeViewsWithComm { ValidatorIndex = 6, InvocationScript = new[] { (byte)'3', (byte)'!' }, - StateRootSignature = new byte[] { 0x01 }, + StateRootSignature = new byte[64], } } }, From 2caf3aff3ebfdcbd0faed167bb05bfc587b24378 Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:36:40 +0800 Subject: [PATCH 37/40] =?UTF-8?q?no=20need=20=EF=BC=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/neo/Consensus/ConsensusService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 2a93ebeef1..405dcc429e 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -496,7 +496,7 @@ private void OnPrepareResponseReceived(ConsensusPayload payload, PrepareResponse if (context.PreparationPayloads[payload.ValidatorIndex] != null || context.NotAcceptingPayloadsDueToViewChanging) return; if (context.PreparationPayloads[context.Block.ConsensusData.PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[context.Block.ConsensusData.PrimaryIndex].Hash)) return; - byte[] stateRootHashData = context.EnsureStateRoot()?.GetHashData(); + byte[] stateRootHashData = context.EnsureStateRoot().GetHashData(); if (!Crypto.VerifySignature(stateRootHashData, message.StateRootSignature, context.Validators[payload.ValidatorIndex])) { Log($"Invalid response: invalid state root signature, height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex}", LogLevel.Warning); From 98af51af966dbd414ac6a105b74ebf98b922076b Mon Sep 17 00:00:00 2001 From: KickSeason Date: Thu, 18 Jun 2020 15:39:04 +0800 Subject: [PATCH 38/40] format --- src/neo/Consensus/PrepareResponse.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/neo/Consensus/PrepareResponse.cs b/src/neo/Consensus/PrepareResponse.cs index 97b4c4234a..b1628650f6 100644 --- a/src/neo/Consensus/PrepareResponse.cs +++ b/src/neo/Consensus/PrepareResponse.cs @@ -7,6 +7,7 @@ public class PrepareResponse : ConsensusMessage { public UInt256 PreparationHash; public byte[] StateRootSignature; + public override int Size => base.Size + PreparationHash.Size + StateRootSignature.Length; public PrepareResponse() From d87934d8e819ad8086b299a04a2baf443729aa71 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 8 Jul 2020 10:20:24 +0200 Subject: [PATCH 39/40] Update ConsensusContext.cs --- src/neo/Consensus/ConsensusContext.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 614be96323..c234220a1c 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -92,6 +92,7 @@ public Block CreateBlock() sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().Signature); j++; } + if (!sc.Completed) throw new Exception("There are not enough signatures for sign the Block."); Block.Witness = sc.GetWitnesses()[0]; Block.Transactions = TransactionHashes.Select(p => Transactions[p]).ToArray(); return Block; @@ -111,6 +112,7 @@ public StateRoot CreateStateRoot() sc.AddSignature(contract, Validators[i], PreparationPayloads[i].GetDeserializedMessage().StateRootSignature); j++; } + if (!sc.Completed) throw new Exception("There are not enough signatures for sign the state root."); PreviousBlockStateRoot.Witness = sc.GetWitnesses()[0]; return PreviousBlockStateRoot; } From e1e0fc2e771be4c7b08b61c03a4c931e6262e805 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 8 Jul 2020 10:20:24 +0200 Subject: [PATCH 40/40] Check sc.Complete --- src/neo/Consensus/ConsensusContext.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 614be96323..c234220a1c 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -92,6 +92,7 @@ public Block CreateBlock() sc.AddSignature(contract, Validators[i], CommitPayloads[i].GetDeserializedMessage().Signature); j++; } + if (!sc.Completed) throw new Exception("There are not enough signatures for sign the Block."); Block.Witness = sc.GetWitnesses()[0]; Block.Transactions = TransactionHashes.Select(p => Transactions[p]).ToArray(); return Block; @@ -111,6 +112,7 @@ public StateRoot CreateStateRoot() sc.AddSignature(contract, Validators[i], PreparationPayloads[i].GetDeserializedMessage().StateRootSignature); j++; } + if (!sc.Completed) throw new Exception("There are not enough signatures for sign the state root."); PreviousBlockStateRoot.Witness = sc.GetWitnesses()[0]; return PreviousBlockStateRoot; }