コード例 #1
0
ファイル: BlockProducer.cs プロジェクト: LAToken/lachain
        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,
            });
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        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,
            });
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        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);
        }
コード例 #8
0
        // 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());
            }