private bool AddTransaction(Transaction tx, bool verify) { if (verify && !tx.Verify(context.Snapshot, context.Transactions.Values)) { Log($"Invalid transaction: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); RequestChangeView(); return(false); } if (!Plugin.CheckPolicy(tx)) { Log($"reject tx: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); RequestChangeView(); return(false); } context.Transactions[tx.Hash] = tx; if (context.TransactionHashes.Length == context.Transactions.Count) { if (VerifyRequest()) { // 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); } // Timeout extension due to prepare response sent // around 2*15/M=30.0/5 ~ 40% block time (for M=5) ExtendTimerByFactor(2); Log($"send prepare response"); localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakePrepareResponse() }); CheckPreparations(); } else { RequestChangeView(); return(false); } } return(true); }
private void InitializeConsensus(byte viewNumber) { context.Reset(viewNumber); if (context.MyIndex < 0) { return; } if (viewNumber > 0) { Log($"changeview: view={viewNumber} primary={context.Validators[context.GetPrimaryIndex((byte)(viewNumber - 1u))]}", LogLevel.Warning); } Log($"initialize: height={context.BlockIndex} view={viewNumber} index={context.MyIndex} role={(context.IsPrimary() ? "Primary" : "Backup")}"); if (context.IsPrimary()) { if (isRecovering) { ChangeTimer(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (viewNumber + 1))); } else { TimeSpan span = TimeProvider.Current.UtcNow - block_received_time; if (span >= Blockchain.TimePerBlock) { ChangeTimer(TimeSpan.Zero); } else { ChangeTimer(Blockchain.TimePerBlock - span); } } } else { ChangeTimer(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (viewNumber + 1))); } }