public void Reset(byte viewNumber) { if (viewNumber == 0) { Snapshot?.Dispose(); Snapshot = DBFTPlugin.System.GetSnapshot(); uint height = NativeContract.Ledger.CurrentIndex(Snapshot); Block = new Block { Header = new Header { PrevHash = NativeContract.Ledger.CurrentHash(Snapshot), Index = height + 1, NextConsensus = Contract.GetBFTAddress( NeoToken.ShouldRefreshCommittee(height + 1, DBFTPlugin.System.Settings.CommitteeMembersCount) ? NativeContract.NEO.ComputeNextBlockValidators(Snapshot, DBFTPlugin.System.Settings) : NativeContract.NEO.GetNextBlockValidators(Snapshot, DBFTPlugin.System.Settings.ValidatorsCount)) } }; var pv = Validators; Validators = NativeContract.NEO.GetNextBlockValidators(Snapshot, DBFTPlugin.System.Settings.ValidatorsCount); if (_witnessSize == 0 || (pv != null && pv.Length != Validators.Length)) { // Compute the expected size of the witness using (ScriptBuilder sb = new ScriptBuilder()) { for (int x = 0; x < M; x++) { sb.EmitPush(new byte[64]); } _witnessSize = new Witness { InvocationScript = sb.ToArray(), VerificationScript = Contract.CreateMultiSigRedeemScript(M, Validators) }.Size; } } MyIndex = -1; ChangeViewPayloads = new ExtensiblePayload[Validators.Length]; LastChangeViewPayloads = new ExtensiblePayload[Validators.Length]; CommitPayloads = new ExtensiblePayload[Validators.Length]; if (ValidatorsChanged || LastSeenMessage is null) { var previous_last_seen_message = LastSeenMessage; LastSeenMessage = new Dictionary <ECPoint, uint>(); foreach (var validator in Validators) { if (previous_last_seen_message != null && previous_last_seen_message.TryGetValue(validator, out var value)) { LastSeenMessage[validator] = value; } else { LastSeenMessage[validator] = height; } } } keyPair = null; for (int i = 0; i < Validators.Length; i++) { WalletAccount account = wallet?.GetAccount(Validators[i]); if (account?.HasKey != true) { continue; } MyIndex = i; keyPair = account.GetKey(); break; } cachedMessages = new Dictionary <UInt256, ConsensusMessage>(); } else { for (int i = 0; i < LastChangeViewPayloads.Length; i++) { if (GetMessage <ChangeView>(ChangeViewPayloads[i])?.NewViewNumber >= viewNumber) { LastChangeViewPayloads[i] = ChangeViewPayloads[i]; } else { LastChangeViewPayloads[i] = null; } } } ViewNumber = viewNumber; Block.Header.PrimaryIndex = GetPrimaryIndex(viewNumber); Block.Header.MerkleRoot = null; Block.Header.Timestamp = 0; Block.Transactions = null; TransactionHashes = null; PreparationPayloads = new ExtensiblePayload[Validators.Length]; if (MyIndex >= 0) { LastSeenMessage[Validators[MyIndex]] = Block.Index; } }
Block CreateSignedBlock(Transaction[] transactions) { // The logic in this method is distilled from ConsensusService/ConsensusContext + MemPool tx verification logic var snapshot = neoSystem.StoreView; // Verify the provided transactions. When running, Blockchain class does verification in two steps: VerifyStateIndependent and VerifyStateDependent. // However, Verify does both parts and there's no point in verifying dependent/independent in separate steps here var verificationContext = new TransactionVerificationContext(); for (int i = 0; i < transactions.Length; i++) { var q = transactions[i].Size * NativeContract.Policy.GetFeePerByte(snapshot); if (transactions[i].Verify(ProtocolSettings, snapshot, verificationContext) != VerifyResult.Succeed) { throw new Exception("Verification failed"); } } // create the block instance var prevHash = NativeContract.Ledger.CurrentHash(snapshot); var prevBlock = NativeContract.Ledger.GetHeader(snapshot, prevHash); var blockHeight = prevBlock.Index + 1; var block = new Block { Header = new Header { Version = 0, PrevHash = prevHash, MerkleRoot = MerkleTree.ComputeRoot(transactions.Select(t => t.Hash).ToArray()), Timestamp = Math.Max(Neo.Helper.ToTimestampMS(DateTime.UtcNow), prevBlock.Timestamp + 1), Index = blockHeight, PrimaryIndex = 0, NextConsensus = Contract.GetBFTAddress( NeoToken.ShouldRefreshCommittee(blockHeight, ProtocolSettings.CommitteeMembersCount) ? NativeContract.NEO.ComputeNextBlockValidators(snapshot, ProtocolSettings) : NativeContract.NEO.GetNextBlockValidators(snapshot, ProtocolSettings.ValidatorsCount)), }, Transactions = transactions }; // retrieve the validators for the next block. Logic lifted from ConensusContext.Reset var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, ProtocolSettings.ValidatorsCount); var m = validators.Length - (validators.Length - 1) / 3; // generate the block header witness. Logic lifted from ConsensusContext.CreateBlock var contract = Contract.CreateMultiSigContract(m, validators); var signingContext = new ContractParametersContext(snapshot, block.Header, ProtocolSettings.Network); for (int i = 0, j = 0; i < validators.Length && j < m; i++) { var key = consensusNodesKeys.Value.SingleOrDefault(k => k.PublicKey.Equals(validators[i])); if (key == null) { continue; } var signature = block.Header.Sign(key, ProtocolSettings.Network); signingContext.AddSignature(contract, validators[i], signature); j++; } if (!signingContext.Completed) { throw new Exception("block signing incomplete"); } block.Header.Witness = signingContext.GetWitnesses()[0]; return(block); }