private TransactionReceipt FinishCycleTxReceipt(ulong blockIndex) { var tx = _transactionBuilder.InvokeTransactionWithGasPrice( UInt160Utils.Zero, ContractRegisterer.GovernanceContract, Utility.Money.Zero, GovernanceInterface.MethodFinishCycle, 0, UInt256Utils.ToUInt256(GovernanceContract.GetCycleByBlockNumber(_blockManager.GetHeight())) ); return(HardforkHeights.IsHardfork_9Active(blockIndex) ? new TransactionReceipt { Hash = tx.FullHash(SignatureUtils.ZeroNew, true), Status = TransactionStatus.Pool, Transaction = tx, Signature = SignatureUtils.ZeroNew, } : new TransactionReceipt { Hash = tx.FullHash(SignatureUtils.ZeroOld, false), Status = TransactionStatus.Pool, Transaction = tx, Signature = SignatureUtils.ZeroOld, }); }
public SmartContract FindContract(string contractName) { Throw.IfNullOrEmpty(contractName, nameof(contractName)); if (_contractCache.ContainsKey(contractName)) { return(_contractCache[contractName]); } SmartContract contract; switch (contractName) { case "nexus": contract = new NexusContract(); break; case "consensus": contract = new ConsensusContract(); break; case "governance": contract = new GovernanceContract(); break; case "account": contract = new AccountContract(); break; case "friends": contract = new FriendContract(); break; case "exchange": contract = new ExchangeContract(); break; case "market": contract = new MarketContract(); break; case "energy": contract = new EnergyContract(); break; case "token": contract = new TokenContract(); break; case "swap": contract = new SwapContract(); break; case "gas": contract = new GasContract(); break; case "relay": contract = new RelayContract(); break; case "storage": contract = new StorageContract(); break; case "vault": contract = new VaultContract(); break; case "bank": contract = new BankContract(); break; case "apps": contract = new AppsContract(); break; case "dex": contract = new ExchangeContract(); break; case "nacho": contract = new NachoContract(); break; case "casino": contract = new CasinoContract(); break; default: throw new Exception("Unknown contract: " + contractName); } _contractCache[contractName] = contract; return(contract); }
private bool IsFinishCycleTx(Block block, Transaction tx) { var indexInCycle = block.Header.Index % StakingContract.CycleDuration; var cycle = block.Header.Index / StakingContract.CycleDuration; if (cycle > 0 && indexInCycle == 0 && tx.To.Equals(ContractRegisterer.GovernanceContract)) { var expectedTx = BuildSystemContractTx(ContractRegisterer.GovernanceContract, GovernanceInterface.MethodFinishCycle, UInt256Utils.ToUInt256(GovernanceContract.GetCycleByBlockNumber(block.Header.Index - 1))); return(CheckSystemTxEquality(expectedTx, tx)); } return(false); }
private bool IsDistributeCycleRewardsAndPenaltiesTx(Block block, Transaction tx) { var indexInCycle = block.Header.Index % StakingContract.CycleDuration; var cycle = block.Header.Index / StakingContract.CycleDuration; if (cycle > 0 && indexInCycle == StakingContract.AttendanceDetectionDuration && tx.To.Equals(ContractRegisterer.GovernanceContract)) { var expectedTx = BuildSystemContractTx(ContractRegisterer.GovernanceContract, GovernanceInterface.MethodDistributeCycleRewardsAndPenalties, UInt256Utils.ToUInt256(GovernanceContract.GetCycleByBlockNumber(block.Header.Index - 1))); return(CheckSystemTxEquality(expectedTx, tx)); } return(false); }
private TransactionReceipt BuildSystemContractTxReceipt(UInt160 contractAddress, string mehodSignature) { var transaction = _transactionBuilder.InvokeTransactionWithGasPrice( UInt160Utils.Zero, contractAddress, Money.Zero, mehodSignature, 0, UInt256Utils.ToUInt256(GovernanceContract.GetCycleByBlockNumber(_stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight())) ); return(new TransactionReceipt { Hash = transaction.FullHash(SignatureUtils.ZeroNew, true), Status = TransactionStatus.Pool, Transaction = transaction, Signature = SignatureUtils.ZeroNew, }); }
private TransactionReceipt MakeNextValidatorsTxReceipt() { var sk = Crypto.GeneratePrivateKey(); var pk = Crypto.ComputePublicKey(sk, false); var tx = _transactionBuilder.InvokeTransactionWithGasPrice( _wallet.EcdsaKeyPair.PublicKey.GetAddress(), ContractRegisterer.GovernanceContract, Money.Zero, GovernanceInterface.MethodChangeValidators, 0, UInt256Utils.ToUInt256(GovernanceContract.GetCycleByBlockNumber(_stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight())), (pk) ); var res = Signer.Sign(tx, _wallet.EcdsaKeyPair, true); Assert.False(_eventData.ContainsKey(res.Hash)); _eventData.Add(res.Hash, ByteString.CopyFrom(ContractEncoder.Encode(GovernanceInterface.EventChangeValidators, (pk)))); return(res); }
private TransactionReceipt MakeKeygenSendValuesTxReceipt() { var proposer = new BigInteger(0).ToUInt256(); var value = new Byte[0]; var tx = _transactionBuilder.InvokeTransactionWithGasPrice( _wallet.EcdsaKeyPair.PublicKey.GetAddress(), ContractRegisterer.GovernanceContract, Money.Zero, GovernanceInterface.MethodKeygenSendValue, 0, UInt256Utils.ToUInt256(GovernanceContract.GetCycleByBlockNumber(_stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight())), proposer, (value) ); var res = Signer.Sign(tx, _wallet.EcdsaKeyPair, true); Assert.False(_eventData.ContainsKey(res.Hash)); _eventData.Add(res.Hash, ByteString.CopyFrom(ContractEncoder.Encode(GovernanceInterface.EventKeygenSendValue, proposer, (value)))); return(res); }
private TransactionReceipt MakeCommitTransaction() { var biVarPoly = BiVarSymmetricPolynomial.Random(0); var commitment = biVarPoly.Commit().ToBytes(); var row = new Byte[0]; var tx = _transactionBuilder.InvokeTransactionWithGasPrice( _wallet.EcdsaKeyPair.PublicKey.GetAddress(), ContractRegisterer.GovernanceContract, Money.Zero, GovernanceInterface.MethodKeygenCommit, 0, UInt256Utils.ToUInt256(GovernanceContract.GetCycleByBlockNumber(_stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight())), commitment, new byte[][] { row } ); var res = Signer.Sign(tx, _wallet.EcdsaKeyPair, true); Assert.False(_eventData.ContainsKey(res.Hash)); _eventData.Add(res.Hash, ByteString.CopyFrom(ContractEncoder.Encode(GovernanceInterface.EventKeygenCommit, commitment, new byte[][] { row }))); return(res); }
public void Test_OneNodeCycle() { var stateManager = _container?.Resolve <IStateManager>(); var contractRegisterer = _container?.Resolve <IContractRegisterer>(); var tx = new TransactionReceipt(); var sender = new BigInteger(0).ToUInt160(); var context = new InvocationContext(sender, stateManager !.LastApprovedSnapshot, tx); var contract = new GovernanceContract(context); var keyPair = new EcdsaKeyPair("0xD95D6DB65F3E2223703C5D8E205D98E3E6B470F067B0F94F6C6BF73D4301CE48" .HexToBytes().ToPrivateKey()); byte[] pubKey = CryptoUtils.EncodeCompressed(keyPair.PublicKey); ECDSAPublicKey[] allKeys = { keyPair.PublicKey }; var keygen = new TrustlessKeygen(keyPair, allKeys, 0, 0); var cycle = 0.ToUInt256(); ValueMessage value; // call ChangeValidators method { byte[][] validators = { pubKey }; var input = ContractEncoder.Encode(GovernanceInterface.MethodChangeValidators, cycle, validators); var call = contractRegisterer !.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.ChangeValidators(cycle, validators, frame)); } // check correct validator { var input = ContractEncoder.Encode(GovernanceInterface.MethodIsNextValidator, pubKey); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.IsNextValidator(pubKey, frame)); Assert.AreEqual(frame.ReturnValue, 1.ToUInt256().ToBytes()); } // check incorrect validator { byte[] incorrectPubKey = pubKey.Reverse().ToArray(); var input = ContractEncoder.Encode(GovernanceInterface.MethodIsNextValidator, incorrectPubKey); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.IsNextValidator(incorrectPubKey, frame)); Assert.AreEqual(frame.ReturnValue, 0.ToUInt256().ToBytes()); } // call commit { var commitMessage = keygen.StartKeygen(); byte[] commitment = commitMessage.Commitment.ToBytes(); byte[][] encryptedRows = commitMessage.EncryptedRows; var input = ContractEncoder.Encode(GovernanceInterface.MethodKeygenCommit, cycle, commitment, encryptedRows); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.KeyGenCommit(cycle, commitment, encryptedRows, frame)); // several calls is ok Assert.AreEqual(ExecutionStatus.Ok, contract.KeyGenCommit(cycle, commitment, encryptedRows, frame)); // set keygen state value = keygen.HandleCommit(0, commitMessage); } // send value { var proposer = new BigInteger(0).ToUInt256(); var input = ContractEncoder.Encode(GovernanceInterface.MethodKeygenSendValue, cycle, proposer, value.EncryptedValues); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.KeyGenSendValue(cycle, proposer, value.EncryptedValues, frame)); // set keygen state Assert.IsTrue(keygen.HandleSendValue(0, value)); Assert.IsTrue(keygen.Finished()); } // confirm { ThresholdKeyring?keyring = keygen.TryGetKeys(); Assert.IsNotNull(keyring); var input = ContractEncoder.Encode(GovernanceInterface.MethodKeygenConfirm, cycle, keyring !.Value.TpkePublicKey.ToBytes(), keyring !.Value.ThresholdSignaturePublicKeySet.Keys.Select(key => key.ToBytes()).ToArray()); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.KeyGenConfirm(cycle, keyring !.Value.TpkePublicKey.ToBytes(), keyring !.Value.ThresholdSignaturePublicKeySet.Keys.Select(key => key.ToBytes()).ToArray(), frame)); // set keygen state Assert.IsTrue(keygen.HandleConfirm(keyring !.Value.TpkePublicKey, keyring !.Value.ThresholdSignaturePublicKeySet)); } // check no validators in storage Assert.Throws <ConsensusStateNotPresentException>(() => context.Snapshot.Validators.GetValidatorsPublicKeys()); // finish cycle { var input = ContractEncoder.Encode(GovernanceInterface.MethodFinishCycle, cycle); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); // should fail due to the invalid block Assert.AreEqual(ExecutionStatus.ExecutionHalted, contract.FinishCycle(cycle, frame)); // set next cycle block number in frame: frame.InvocationContext.Receipt.Block = StakingContract.CycleDuration; Assert.AreEqual(ExecutionStatus.Ok, contract.FinishCycle(cycle, frame)); } // check new validators in storage var newValidators = context.Snapshot.Validators.GetValidatorsPublicKeys().ToArray(); Assert.AreEqual(newValidators.Count(), 1); Assert.AreEqual(newValidators[0], keyPair.PublicKey); }
private void ExecuteCycle(int n, int f) { var stateManager = _container?.Resolve <IStateManager>(); var contractRegisterer = _container?.Resolve <IContractRegisterer>(); var tx = new TransactionReceipt(); var sender = new BigInteger(0).ToUInt160(); var context = new InvocationContext(sender, stateManager !.LastApprovedSnapshot, tx); var contract = new GovernanceContract(context); var ecdsaKeys = Enumerable.Range(0, n) .Select(_ => Crypto.GeneratePrivateKey()) .Select(x => x.ToPrivateKey()) .Select(x => new EcdsaKeyPair(x)) .ToArray(); var pubKeys = ecdsaKeys.Select(x => CryptoUtils.EncodeCompressed(x.PublicKey)).ToArray(); var keyGens = Enumerable.Range(0, n) .Select(i => new TrustlessKeygen(ecdsaKeys[i], ecdsaKeys.Select(x => x.PublicKey), f, 0)) .ToArray(); var cycle = 0.ToUInt256(); var messageLedger = new RandomSamplingQueue <QueueItem>(); messageLedger.Enqueue(new QueueItem(-1, null)); // call ChangeValidators method { byte[][] validators = pubKeys; var input = ContractEncoder.Encode(GovernanceInterface.MethodChangeValidators, cycle, validators); var call = contractRegisterer !.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.ChangeValidators(cycle, validators, frame)); } // check correct validator { for (var i = 0; i < n; i++) { var input = ContractEncoder.Encode(GovernanceInterface.MethodIsNextValidator, pubKeys[i]); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.IsNextValidator(pubKeys[i], frame)); Assert.AreEqual(frame.ReturnValue, 1.ToUInt256().ToBytes()); } } // check incorrect validator { byte[] incorrectPubKey = pubKeys[0].Reverse().ToArray(); var input = ContractEncoder.Encode(GovernanceInterface.MethodIsNextValidator, incorrectPubKey); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.IsNextValidator(incorrectPubKey, frame)); Assert.AreEqual(frame.ReturnValue, 0.ToUInt256().ToBytes()); } while (messageLedger.Count > 0) { QueueItem?msg; var success = messageLedger.TryDequeue(out msg); Assert.IsTrue(success); switch (msg.payload) { case null: for (var i = 0; i < n; ++i) { messageLedger.Enqueue(new QueueItem(i, keyGens[i].StartKeygen())); } break; case CommitMessage commitMessage: for (var i = 0; i < n; ++i) { if (i == 0) { byte[] commitment = commitMessage.Commitment.ToBytes(); byte[][] encryptedRows = commitMessage.EncryptedRows; var input = ContractEncoder.Encode(GovernanceInterface.MethodKeygenCommit, cycle, commitment, encryptedRows); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.KeyGenCommit(cycle, commitment, encryptedRows, frame)); // several calls is ok Assert.AreEqual(ExecutionStatus.Ok, contract.KeyGenCommit(cycle, commitment, encryptedRows, frame)); } messageLedger.Enqueue(new QueueItem(i, keyGens[i].HandleCommit(msg.sender, commitMessage))); } break; case ValueMessage valueMessage: for (var i = 0; i < n; ++i) { if (i == 0) { var proposer = new BigInteger(msg.sender).ToUInt256(); var input = ContractEncoder.Encode(GovernanceInterface.MethodKeygenSendValue, cycle, proposer, valueMessage.EncryptedValues); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.KeyGenSendValue(cycle, proposer, valueMessage.EncryptedValues, frame)); } keyGens[i].HandleSendValue(msg.sender, valueMessage); } break; default: Assert.Fail($"Message of type {msg.GetType()} occurred"); break; } } Assert.IsTrue(keyGens.All((x) => x.Finished())); // finish cycle { var input = ContractEncoder.Encode(GovernanceInterface.MethodFinishCycle, cycle); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); // set next cycle block number in frame: frame.InvocationContext.Receipt.Block = StakingContract.CycleDuration; Assert.AreEqual(ExecutionStatus.Ok, contract.FinishCycle(cycle, frame)); } }
public void Test_InvalidValidatorKey() { var stateManager = _container?.Resolve <IStateManager>(); var contractRegisterer = _container?.Resolve <IContractRegisterer>(); var tx = new TransactionReceipt(); var sender = new BigInteger(0).ToUInt160(); var context = new InvocationContext(sender, stateManager !.LastApprovedSnapshot, tx); var contract = new GovernanceContract(context); var keyPair = new EcdsaKeyPair(Crypto.GeneratePrivateKey().ToPrivateKey()); ECDSAPublicKey[] allKeys = { keyPair.PublicKey }; var keygen = new TrustlessKeygen(keyPair, allKeys, 0, 0); var cycle = 0.ToUInt256(); ValueMessage value; // call ChangeValidators method with invalid key { byte[][] validators = { new byte[] { 0 } }; var input = ContractEncoder.Encode(GovernanceInterface.MethodChangeValidators, cycle, validators); var call = contractRegisterer !.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.ExecutionHalted, contract.ChangeValidators(cycle, validators, frame)); } // call commit { var commitMessage = keygen.StartKeygen(); byte[] commitment = commitMessage.Commitment.ToBytes(); byte[][] encryptedRows = commitMessage.EncryptedRows; var input = ContractEncoder.Encode(GovernanceInterface.MethodKeygenCommit, cycle, commitment, encryptedRows); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.ExecutionHalted, contract.KeyGenCommit(cycle, commitment, encryptedRows, frame)); // set keygen state value = keygen.HandleCommit(0, commitMessage); } // send value { var proposer = new BigInteger(0).ToUInt256(); var input = ContractEncoder.Encode(GovernanceInterface.MethodKeygenSendValue, cycle, proposer, value.EncryptedValues); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.ExecutionHalted, contract.KeyGenSendValue(cycle, proposer, value.EncryptedValues, frame)); // set keygen state Assert.IsTrue(keygen.HandleSendValue(0, value)); Assert.IsTrue(keygen.Finished()); } // confirm { ThresholdKeyring?keyring = keygen.TryGetKeys(); Assert.IsNotNull(keyring); var input = ContractEncoder.Encode(GovernanceInterface.MethodKeygenConfirm, cycle, keyring !.Value.TpkePublicKey.ToBytes(), keyring !.Value.ThresholdSignaturePublicKeySet.Keys.Select(key => key.ToBytes()).ToArray()); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); Assert.AreEqual(ExecutionStatus.Ok, contract.KeyGenConfirm(cycle, keyring !.Value.TpkePublicKey.ToBytes(), keyring !.Value.ThresholdSignaturePublicKeySet.Keys.Select(key => key.ToBytes()).ToArray(), frame)); // set keygen state Assert.IsTrue(keygen.HandleConfirm(keyring !.Value.TpkePublicKey, keyring !.Value.ThresholdSignaturePublicKeySet)); } // check no validators in storage Assert.Throws <ConsensusStateNotPresentException>(() => context.Snapshot.Validators.GetValidatorsPublicKeys()); // finish cycle { var input = ContractEncoder.Encode(GovernanceInterface.MethodFinishCycle, cycle); var call = contractRegisterer.DecodeContract(context, ContractRegisterer.GovernanceContract, input); Assert.IsNotNull(call); var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000); // set next cycle block number in frame: frame.InvocationContext.Receipt.Block = StakingContract.CycleDuration; Assert.AreEqual(ExecutionStatus.Ok, contract.FinishCycle(cycle, frame)); } // check no validators in storage again Assert.IsEmpty(context.Snapshot.Validators.GetValidatorsPublicKeys()); }
// For every cycle, a new set of keys are required for the validators. This key generation process // is done on-chain. That means, every communication between participating nodes happen via transactions // in the block. For example, if node A wants to send a msg to node B, then node A encrypts the // msg with node B's public key and broadcast this as a transaction to the governance contract. // After this transaction is added to the chain, node B can decrypt the msg and read it. // During block execution, after every system transaction is executed, the following method // is invoked. It evaluates the transaction and if it's keygen related, it produces // appropriate response in form of a transaction and adds it to the pool for the addition // in the block. private void BlockManagerOnSystemContractInvoked(object _, InvocationContext context) { if (context.Receipt is null) { return; } var highestBlock = _blockSynchronizer.GetHighestBlock(); var willParticipate = !highestBlock.HasValue || GovernanceContract.IsKeygenBlock(context.Receipt.Block) && GovernanceContract.SameCycle(highestBlock.Value, context.Receipt.Block); if (!willParticipate) { Logger.LogInformation( highestBlock != null ? $"Will not participate in keygen: highest block is {highestBlock.Value}, call block is {context.Receipt.Block}" : $"Will not participate in keygen: highest block is null, call block is {context.Receipt.Block}" ); } var tx = context.Receipt.Transaction; if ( !tx.To.Equals(ContractRegisterer.GovernanceContract) && !tx.To.Equals(ContractRegisterer.StakingContract) ) { return; } if (context.Receipt.Block < _blockManager.GetHeight() && !GovernanceContract.SameCycle(context.Receipt.Block, _blockManager.GetHeight())) { Logger.LogWarning( $"System contract invoked from outdated tx: {context.Receipt.Hash}, tx block {context.Receipt.Block}, our height is {_blockManager.GetHeight()}"); return; } if (tx.Invocation.Length < 4) { return; } var signature = ContractEncoder.MethodSignatureAsInt(tx.Invocation); var decoder = new ContractDecoder(tx.Invocation.ToArray()); var contractAddress = tx.To; if (contractAddress.Equals(ContractRegisterer.GovernanceContract) && signature == ContractEncoder.MethodSignatureAsInt(GovernanceInterface.MethodFinishCycle)) { Logger.LogDebug("Aborting ongoing keygen because cycle was finished"); _keyGenRepository.SaveKeyGenState(Array.Empty <byte>()); } else if (signature == ContractEncoder.MethodSignatureAsInt(StakingInterface.MethodFinishVrfLottery)) { Logger.LogDebug($"Detected call of StakingInterface.{StakingInterface.MethodFinishVrfLottery}"); var cycle = GovernanceContract.GetCycleByBlockNumber(context.Receipt.Block); var data = new GovernanceContract(context).GetNextValidators(); var publicKeys = (data ?? throw new ArgumentException("Cannot parse method args")) .Select(x => x.ToPublicKey()) .ToArray(); Logger.LogDebug( $"Keygen is started in cycle={cycle}, block={context.Receipt.Block} for validator set: {string.Join(",", publicKeys.Select(x => x.ToHex()))}" ); if (!publicKeys.Contains(_privateWallet.EcdsaKeyPair.PublicKey)) { Logger.LogWarning("Skipping validator change event since we are not new validator"); return; } var keygen = GetCurrentKeyGen(); if (keygen != null && keygen.Cycle == cycle) { throw new ArgumentException("Cannot start keygen, since one is already running"); } if (keygen != null) { Logger.LogWarning($"Aborted keygen for cycle {keygen.Cycle} to start keygen for cycle {cycle}"); } _keyGenRepository.SaveKeyGenState(Array.Empty <byte>()); var faulty = (publicKeys.Length - 1) / 3; keygen = new TrustlessKeygen(_privateWallet.EcdsaKeyPair, publicKeys, faulty, cycle); var commitTx = MakeCommitTransaction(keygen.StartKeygen(), cycle); Logger.LogTrace($"Produced commit tx with hash: {commitTx.Hash.ToHex()}"); if (willParticipate) { Logger.LogInformation($"Try to send KeyGen Commit transaction"); if (_transactionPool.Add(commitTx) is var error && error != OperatingError.Ok) { Logger.LogError($"Error creating commit transaction ({commitTx.Hash.ToHex()}): {error}"); } else { Logger.LogInformation($"KeyGen Commit transaction sent"); } } Logger.LogDebug($"Saving keygen {keygen.ToBytes().ToHex()}"); _keyGenRepository.SaveKeyGenState(keygen.ToBytes()); }