private void OnPrepareResponseReceived(ExtensiblePayload payload, PrepareResponse message) { if (message.ViewNumber != context.ViewNumber) { return; } if (context.PreparationPayloads[message.ValidatorIndex] != null || context.NotAcceptingPayloadsDueToViewChanging) { return; } if (context.PreparationPayloads[context.Block.PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[context.Block.PrimaryIndex].Hash)) { return; } // Timeout extension: prepare response has been received with success // around 2*15/M=30.0/5 ~ 40% block time (for M=5) ExtendTimerByFactor(2); Log($"{nameof(OnPrepareResponseReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex}"); context.PreparationPayloads[message.ValidatorIndex] = payload; if (context.WatchOnly || context.CommitSent) { return; } if (context.RequestSentOrReceived) { CheckPreparations(); } }
private PreparationPayloadCompact GetPreparationPayloadCompact(ExtensiblePayload payload) { return(new PreparationPayloadCompact { ValidatorIndex = GetMessage(payload).ValidatorIndex, InvocationScript = payload.Witness.InvocationScript }); }
private ExtensiblePayload MakeSignedPayload(ConsensusMessage message) { message.BlockIndex = Block.Index; message.ValidatorIndex = (byte)MyIndex; message.ViewNumber = ViewNumber; ExtensiblePayload payload = CreatePayload(message, null); SignPayload(payload); return(payload); }
private ChangeViewPayloadCompact GetChangeViewPayloadCompact(ExtensiblePayload payload) { ChangeView message = GetMessage <ChangeView>(payload); return(new ChangeViewPayloadCompact { ValidatorIndex = message.ValidatorIndex, OriginalViewNumber = message.ViewNumber, Timestamp = message.Timestamp, InvocationScript = payload.Witness.InvocationScript }); }
private VerifyResult OnNewExtensiblePayload(ExtensiblePayload payload) { DataCache snapshot = system.StoreView; extensibleWitnessWhiteList ??= UpdateExtensibleWitnessWhiteList(snapshot); if (!payload.Verify(snapshot, extensibleWitnessWhiteList)) { return(VerifyResult.Invalid); } system.RelayCache.Add(payload); return(VerifyResult.Succeed); }
private CommitPayloadCompact GetCommitPayloadCompact(ExtensiblePayload payload) { Commit message = GetMessage <Commit>(payload); return(new CommitPayloadCompact { ViewNumber = message.ViewNumber, ValidatorIndex = message.ValidatorIndex, Signature = message.Signature, InvocationScript = payload.Witness.InvocationScript }); }
public ConsensusMessage GetMessage(ExtensiblePayload payload) { if (payload is null) { return(null); } if (!cachedMessages.TryGetValue(payload.Hash, out ConsensusMessage message)) { cachedMessages.Add(payload.Hash, message = ConsensusMessage.DeserializeFrom(payload.Data)); } return(message); }
private bool ReverifyAndProcessPayload(ExtensiblePayload payload) { RelayResult relayResult = blockchain.Ask <RelayResult>(new Blockchain.Reverify { Inventories = new IInventory[] { payload } }).Result; if (relayResult.Result != VerifyResult.Succeed) { return(false); } OnConsensusPayload(payload); return(true); }
private void CheckPreparations() { if (context.PreparationPayloads.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p))) { ExtensiblePayload payload = context.MakeCommit(); Log($"Sending {nameof(Commit)}"); context.Save(); 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)); CheckCommits(); } }
private void SignPayload(ExtensiblePayload payload) { ContractParametersContext sc; try { sc = new ContractParametersContext(neoSystem.StoreView, payload, dbftSettings.Network); wallet.Sign(sc); } catch (InvalidOperationException) { return; } payload.Witness = sc.GetWitnesses()[0]; }
public void Size_Get() { var test = new ExtensiblePayload() { Sender = Array.Empty <byte>().ToScriptHash(), Category = "123", Data = new byte[] { 1, 2, 3 }, Witness = new Witness() { InvocationScript = new byte[] { 3, 5, 6 }, VerificationScript = Array.Empty <byte>() } }; test.Size.Should().Be(42); }
private void OnStatePayload(ExtensiblePayload payload) { if (payload.Data.Length == 0) { return; } if ((MessageType)payload.Data.Span[0] != MessageType.StateRoot) { return; } StateRoot message; try { message = payload.Data[1..].AsSerializable <StateRoot>();
private void OnVoteMessage(ExtensiblePayload payload) { if (payload.Data.Length == 0) { return; } if ((MessageType)payload.Data.Span[0] != MessageType.Vote) { return; } Vote message; try { message = payload.Data[1..].AsSerializable <Vote>();
private void SignPayload(ExtensiblePayload payload) { ContractParametersContext sc; try { sc = new ContractParametersContext(payload); wallet.Sign(sc); } catch (InvalidOperationException) { return; } payload.Witness = sc.GetWitnesses()[0]; }
private void SignPayload(ExtensiblePayload payload) { ContractParametersContext sc; try { sc = new ContractParametersContext(neoSystem.StoreView, payload, dbftSettings.Network); wallet.Sign(sc); } catch (InvalidOperationException exception) { Utility.Log(nameof(ConsensusContext), LogLevel.Debug, exception.ToString()); return; } payload.Witness = sc.GetWitnesses()[0]; }
private IVerifiable deserializeContainer(dynamic args) { byte[] serializedContainer = (byte[])args.buffer; string typeIn = (string)args.type; IVerifiable container; ContainerType type; if (Enum.TryParse <ContainerType>(typeIn, out type)) { switch (type) { case ContainerType.Block: container = new Block(); break; case ContainerType.Header: container = new Header(); break; case ContainerType.Transaction: container = new Transaction(); break; case ContainerType.Signers: container = new Signers(); break; case ContainerType.ExtensiblePayload: container = new ExtensiblePayload(); break; default: throw new ArgumentException($"{typeIn} is not a valid container type"); } using (MemoryStream ms = new MemoryStream(serializedContainer)) using (BinaryReader reader = new BinaryReader(ms)) { container.Deserialize(reader); } return(container); } throw new ArgumentException($"{typeIn} is not a valid container type"); }
private void OnStatePayload(ExtensiblePayload payload) { StateRoot state_root = null; try { state_root = payload.Data?.AsSerializable <StateRoot>(); } catch (Exception ex) { Utility.Log(nameof(StateStore), LogLevel.Warning, " invalid state root " + ex.Message); return; } if (state_root != null) { OnNewStateRoot(state_root); } }
private void OnInventory(IInventory inventory, bool relay = true) { VerifyResult result = inventory switch { Block block => OnNewBlock(block), Transaction transaction => OnNewTransaction(transaction), ExtensiblePayload payload => OnNewExtensiblePayload(payload), _ => throw new NotSupportedException() }; if (result == VerifyResult.Succeed && relay) { system.LocalNode.Tell(new LocalNode.RelayDirectly { Inventory = inventory }); } SendRelayResult(inventory, result); }
private void OnStatePayload(ExtensiblePayload payload) { if (payload.Data.Length == 0) { return; } if ((MessageType)payload.Data[0] != MessageType.StateRoot) { return; } StateRoot message; try { message = payload.Data.AsSerializable <StateRoot>(1); } catch (FormatException) { return; } OnNewStateRoot(message); }
public void DeserializeAndSerialize() { var test = new ExtensiblePayload() { Category = "123", ValidBlockStart = 456, ValidBlockEnd = 789, Sender = Array.Empty <byte>().ToScriptHash(), Data = new byte[] { 1, 2, 3 }, Witness = new Witness() { InvocationScript = new byte[] { (byte)OpCode.PUSH1, (byte)OpCode.PUSH2, (byte)OpCode.PUSH3 }, VerificationScript = Array.Empty <byte>() } }; var clone = test.ToArray().AsSerializable <ExtensiblePayload>(); Assert.AreEqual(test.Sender, clone.Witness.ScriptHash); Assert.AreEqual(test.Hash, clone.Hash); Assert.AreEqual(test.ValidBlockStart, clone.ValidBlockStart); Assert.AreEqual(test.ValidBlockEnd, clone.ValidBlockEnd); Assert.AreEqual(test.Category, clone.Category); }
private void OnVoteMessage(ExtensiblePayload payload) { if (payload.Data.Length == 0) { return; } if ((MessageType)payload.Data[0] != MessageType.Vote) { return; } Vote message; try { message = payload.Data.AsSerializable <Vote>(1); } catch (FormatException) { return; } OnStateRootVote(message); }
private void OnChangeViewReceived(ExtensiblePayload payload, ChangeView message) { if (message.NewViewNumber <= context.ViewNumber) { OnRecoveryRequestReceived(payload, message); } if (context.CommitSent) { return; } var expectedView = context.GetMessage <ChangeView>(context.ChangeViewPayloads[message.ValidatorIndex])?.NewViewNumber ?? 0; if (message.NewViewNumber <= expectedView) { return; } Log($"{nameof(OnChangeViewReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex} nv={message.NewViewNumber} reason={message.Reason}"); context.ChangeViewPayloads[message.ValidatorIndex] = payload; CheckExpectedView(message.NewViewNumber); }
// TODO: remove if https://github.com/neo-project/neo/issues/2061 is fixed // this logic is lifted from ConsensusService.OnPrepareRequestReceived // Log, Timer, Task and CheckPrepare logic has been commented out for offline consensus private static void OnPrepareRequestReceived(ConsensusContext context, ExtensiblePayload payload, PrepareRequest message) { if (context.RequestSentOrReceived || context.NotAcceptingPayloadsDueToViewChanging) { return; } if (message.ValidatorIndex != context.Block.ConsensusData.PrimaryIndex || message.ViewNumber != context.ViewNumber) { return; } if (message.Version != context.Block.Version || message.PrevHash != context.Block.PrevHash) { return; } // Log($"{nameof(OnPrepareRequestReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (message.Timestamp <= context.PrevHeader.Timestamp || message.Timestamp > TimeProvider.Current.UtcNow.AddMilliseconds(8 * Blockchain.MillisecondsPerBlock).ToTimestampMS()) { // Log($"Timestamp incorrect: {message.Timestamp}", LogLevel.Warning); return; } if (message.TransactionHashes.Any(p => NativeContract.Ledger.ContainsTransaction(context.Snapshot, p))) { // Log($"Invalid request: transaction already exists", 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.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary <UInt256, Transaction>(); context.VerificationContext = new TransactionVerificationContext(); for (int i = 0; i < context.PreparationPayloads.Length; i++) { if (context.PreparationPayloads[i] != null) { if (!context.GetMessage <PrepareResponse>(context.PreparationPayloads[i]).PreparationHash.Equals(payload.Hash)) { context.PreparationPayloads[i] = null; } } } context.PreparationPayloads[message.ValidatorIndex] = payload; byte[] hashData = context.EnsureHeader().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) { if (context.GetMessage(context.CommitPayloads[i])?.ViewNumber == context.ViewNumber) { if (!Crypto.VerifySignature(hashData, context.GetMessage <Commit>(context.CommitPayloads[i]).Signature, context.Validators[i])) { context.CommitPayloads[i] = null; } } } if (context.TransactionHashes.Length == 0) { // There are no tx so we should act like if all the transactions were filled // CheckPrepareResponse(); return; } Dictionary <UInt256, Transaction> mempoolVerified = Blockchain.Singleton.MemPool.GetVerifiedTransactions().ToDictionary(p => p.Hash); List <Transaction> unverified = new List <Transaction>(); foreach (UInt256 hash in context.TransactionHashes) { if (mempoolVerified.TryGetValue(hash, out var tx)) { if (!AddTransaction(tx, false)) { return; } } else { if (Blockchain.Singleton.MemPool.TryGetValue(hash, out tx)) { unverified.Add(tx); } } } foreach (Transaction tx in unverified) { if (!AddTransaction(tx, true)) { return; } } if (context.Transactions.Count < context.TransactionHashes.Length) { UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); // taskManager.Tell(new TaskManager.RestartTasks // { // Payload = InvPayload.Create(InventoryType.TX, hashes) // }); } bool AddTransaction(Transaction tx, bool verify) { if (verify) { VerifyResult result = tx.Verify(context.Snapshot, context.VerificationContext); if (result != VerifyResult.Succeed) { // Log($"Rejected tx: {tx.Hash}, {result}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); // RequestChangeView(result == VerifyResult.PolicyFail ? ChangeViewReason.TxRejectedByPolicy : ChangeViewReason.TxInvalid); return(false); } } context.Transactions[tx.Hash] = tx; context.VerificationContext.AddTransaction(tx); return(CheckPrepareResponse()); } bool CheckPrepareResponse() { if (context.TransactionHashes.Length == context.Transactions.Count) { // if we are the primary for this view, but acting as a backup because we recovered our own // previously sent prepare request, then we don't want to send a prepare response. if (context.IsPrimary || context.WatchOnly) { return(true); } // TODO: Replace reflection after https://github.com/neo-project/neo-modules/pull/503 is merged // Check maximum block size via Native Contract policy var expectedBlockSize = (int)(getExpectedBlockSizeMethodInfo.Value.Invoke(context, Array.Empty <object>())) !; if (expectedBlockSize > NativeContract.Policy.GetMaxBlockSize(context.Snapshot)) { // Log($"Rejected block: {context.Block.Index} The size exceed the policy", LogLevel.Warning); // RequestChangeView(ChangeViewReason.BlockRejectedByPolicy); return(false); } // TODO: Replace duplicate code for calculating blockSystemFee after https://github.com/neo-project/neo-modules/pull/503 is merged // Check maximum block system fee via Native Contract policy var blockSystemFee = context.Transactions.Values.Sum(u => u.SystemFee); if (blockSystemFee > NativeContract.Policy.GetMaxBlockSystemFee(context.Snapshot)) { // Log($"Rejected block: {context.Block.Index} The system fee exceed the policy", LogLevel.Warning); // RequestChangeView(ChangeViewReason.BlockRejectedByPolicy); return(false); } // Timeout extension due to prepare response sent // around 2*15/M=30.0/5 ~ 40% block time (for M=5) // ExtendTimerByFactor(2); // Log($"Sending {nameof(PrepareResponse)}"); // localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakePrepareResponse() }); // CheckPreparations(); } return(true); } }
public T GetMessage <T>(ExtensiblePayload payload) where T : ConsensusMessage { return((T)GetMessage(payload)); }
private void OnPrepareRequestReceived(ExtensiblePayload payload, PrepareRequest message) { if (context.RequestSentOrReceived || context.NotAcceptingPayloadsDueToViewChanging) { return; } if (message.ValidatorIndex != context.Block.PrimaryIndex || message.ViewNumber != context.ViewNumber) { return; } if (message.Version != context.Block.Version || message.PrevHash != context.Block.PrevHash) { return; } if (message.TransactionHashes.Length > neoSystem.Settings.MaxTransactionsPerBlock) { return; } Log($"{nameof(OnPrepareRequestReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (message.Timestamp <= context.PrevHeader.Timestamp || message.Timestamp > TimeProvider.Current.UtcNow.AddMilliseconds(8 * neoSystem.Settings.MillisecondsPerBlock).ToTimestampMS()) { Log($"Timestamp incorrect: {message.Timestamp}", LogLevel.Warning); return; } if (message.TransactionHashes.Any(p => NativeContract.Ledger.ContainsTransaction(context.Snapshot, p))) { Log($"Invalid request: transaction already exists", 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.Header.Timestamp = message.Timestamp; context.Block.Header.Nonce = message.Nonce; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary <UInt256, Transaction>(); context.VerificationContext = new TransactionVerificationContext(); for (int i = 0; i < context.PreparationPayloads.Length; i++) { if (context.PreparationPayloads[i] != null) { if (!context.GetMessage <PrepareResponse>(context.PreparationPayloads[i]).PreparationHash.Equals(payload.Hash)) { context.PreparationPayloads[i] = null; } } } context.PreparationPayloads[message.ValidatorIndex] = payload; byte[] hashData = context.EnsureHeader().GetSignData(neoSystem.Settings.Network); for (int i = 0; i < context.CommitPayloads.Length; i++) { if (context.GetMessage(context.CommitPayloads[i])?.ViewNumber == context.ViewNumber) { if (!Crypto.VerifySignature(hashData, context.GetMessage <Commit>(context.CommitPayloads[i]).Signature.Span, context.Validators[i])) { context.CommitPayloads[i] = null; } } } if (context.TransactionHashes.Length == 0) { // There are no tx so we should act like if all the transactions were filled CheckPrepareResponse(); return; } Dictionary <UInt256, Transaction> mempoolVerified = neoSystem.MemPool.GetVerifiedTransactions().ToDictionary(p => p.Hash); List <Transaction> unverified = new List <Transaction>(); foreach (UInt256 hash in context.TransactionHashes) { if (mempoolVerified.TryGetValue(hash, out Transaction tx)) { if (!AddTransaction(tx, false)) { return; } } else { if (neoSystem.MemPool.TryGetValue(hash, out tx)) { unverified.Add(tx); } } } foreach (Transaction tx in unverified) { if (!AddTransaction(tx, true)) { return; } } if (context.Transactions.Count < context.TransactionHashes.Length) { UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); taskManager.Tell(new TaskManager.RestartTasks { Payload = InvPayload.Create(InventoryType.TX, hashes) }); } }
private void OnConsensusPayload(ExtensiblePayload payload) { if (context.BlockSent) { return; } ConsensusMessage message; try { message = context.GetMessage(payload); } catch (Exception ex) { Utility.Log(nameof(ConsensusService), LogLevel.Debug, ex.ToString()); return; } if (!message.Verify(neoSystem.Settings)) { return; } if (message.BlockIndex != context.Block.Index) { if (context.Block.Index < message.BlockIndex) { Log($"Chain is behind: expected={message.BlockIndex} current={context.Block.Index - 1}", LogLevel.Warning); } return; } if (message.ValidatorIndex >= context.Validators.Length) { return; } if (payload.Sender != Contract.CreateSignatureRedeemScript(context.Validators[message.ValidatorIndex]).ToScriptHash()) { return; } context.LastSeenMessage[context.Validators[message.ValidatorIndex]] = message.BlockIndex; switch (message) { case PrepareRequest request: OnPrepareRequestReceived(payload, request); break; case PrepareResponse response: OnPrepareResponseReceived(payload, response); break; case ChangeView view: OnChangeViewReceived(payload, view); break; case Commit commit: OnCommitReceived(payload, commit); break; case RecoveryRequest request: OnRecoveryRequestReceived(payload, request); break; case RecoveryMessage recovery: OnRecoveryMessageReceived(recovery); break; } }
private void OnCommitReceived(ExtensiblePayload payload, Commit commit) { ref ExtensiblePayload existingCommitPayload = ref context.CommitPayloads[commit.ValidatorIndex];