예제 #1
0
        public ExecutionStatus KeyGenConfirm(UInt256 cycle, byte[] tpkePublicKey, byte[][] thresholdSignaturePublicKeys,
                                             SystemContractExecutionFrame frame)
        {
            Logger.LogDebug(
                $"KeyGenConfirm({tpkePublicKey.ToHex()}, [{string.Join(", ", thresholdSignaturePublicKeys.Select(s => s.ToHex()))}])");
            if (cycle.ToBigInteger() != GetConsensusGeneration(frame))
            {
                Logger.LogWarning($"Invalid cycle: {cycle}, now is {GetConsensusGeneration(frame)}");
                return(ExecutionStatus.Ok);
            }

            frame.ReturnValue = new byte[] { };
            frame.UseGas(GasMetering.KeygenConfirmCost);
            var players = thresholdSignaturePublicKeys.Length;
            var faulty  = (players - 1) / 3;

            UInt256      keyringHash;
            PublicKeySet tsKeys;

            try
            {
                tsKeys = new PublicKeySet(
                    thresholdSignaturePublicKeys.Select(x => Lachain.Crypto.ThresholdSignature.PublicKey.FromBytes(x)),
                    faulty
                    );
                var tpkeKey = PublicKey.FromBytes(tpkePublicKey);
                keyringHash = tpkeKey.ToBytes().Concat(tsKeys.ToBytes()).Keccak();
            }
            catch
            {
                Logger.LogError("GovernanceContract is halted in KeyGenConfirm");
                return(ExecutionStatus.ExecutionHalted);
            }

            var gen   = GetConsensusGeneration(frame);
            var votes = GetConfirmations(keyringHash.ToBytes(), gen);

            SetConfirmations(keyringHash.ToBytes(), gen, votes + 1);

            Logger.LogDebug($"KeygenConfirm: {votes + 1} collected for this keyset");
            if (votes + 1 != players - faulty)
            {
                return(ExecutionStatus.Ok);
            }
            Logger.LogDebug($"KeygenConfirm: succeeded since collected {votes + 1} votes");
            _lastSuccessfulKeygenBlock.Set(new BigInteger(frame.InvocationContext.Receipt.Block).ToUInt256().ToBytes());
            SetPlayersCount(players);
            SetTSKeys(tsKeys);
            SetTpkeKey(tpkePublicKey);

            Emit(GovernanceInterface.EventKeygenConfirm, tpkePublicKey, thresholdSignaturePublicKeys);
            return(ExecutionStatus.Ok);
        }
예제 #2
0
        public ExecutionStatus ChangeValidators(UInt256 cycle, byte[][] newValidators,
                                                SystemContractExecutionFrame frame)
        {
            Logger.LogDebug($"ChangeValidators([{string.Join(", ", newValidators.Select(x => x.ToHex()))})]");
            if (cycle.ToBigInteger() != GetConsensusGeneration(frame))
            {
                Logger.LogWarning($"Invalid cycle: {cycle}, now is {GetConsensusGeneration(frame)}");
                return(ExecutionStatus.Ok);
            }

            if (!MsgSender().Equals(ContractRegisterer.StakingContract) && !MsgSender().IsZero())
            {
                Logger.LogError("GovernanceContract is halted in ChangeValidators: Invalid sender");
                return(ExecutionStatus.ExecutionHalted);
            }

            frame.ReturnValue = new byte[] { };
            frame.UseGas(GasMetering.ChangeValidatorsCost);
            foreach (var publicKey in newValidators)
            {
                if (publicKey.Length != CryptoUtils.PublicKeyLength)
                {
                    Logger.LogError("GovernanceContract is halted in ChangeValidators: Invalid public key length");
                    return(ExecutionStatus.ExecutionHalted);
                }

                if (!Crypto.TryDecodePublicKey(publicKey, false, out _))
                {
                    Logger.LogError("GovernanceContract is halted in ChangeValidators: failed to decode public key");
                    return(ExecutionStatus.ExecutionHalted);
                }
            }

            _nextValidators.Set(newValidators
                                .Select(x => x.ToPublicKey().EncodeCompressed())
                                .Flatten()
                                .ToArray()
                                );

            Emit(GovernanceInterface.EventChangeValidators, newValidators);
            return(ExecutionStatus.Ok);
        }
예제 #3
0
 private void SetTpkeKey(byte[] tpkePublicKey)
 {
     _tpkeKey.Set(tpkePublicKey);
 }
예제 #4
0
 private void SetCollectedFees(Money fees)
 {
     _collectedFees.Set(fees.ToUInt256().ToBytes());
 }
예제 #5
0
 private void SetTSKeys(PublicKeySet tsKeys)
 {
     _tsKeys.Set(tsKeys.ToBytes().ToArray());
 }
예제 #6
0
 private void SetPlayersCount(int count)
 {
     _playersCount.Set(count.ToBytes().ToArray());
 }
예제 #7
0
        // Every time a node starts, it first tries to build the genesis block
        public bool TryBuildGenesisBlock()
        {
            // genesis block is built from the config.json file
            // genesis block mints tokens to the validators for the first cycle
            var genesisBlock = _genesisBuilder.Build();

            // if genesis block can already be found, we return immediately
            if (_stateManager.LastApprovedSnapshot.Blocks.GetBlockByHeight(0) != null)
            {
                return(false);
            }
            var snapshot      = _stateManager.NewSnapshot();
            var genesisConfig = _configManager.GetConfig <GenesisConfig>("genesis");

            if (genesisConfig is null)
            {
                return(false);
            }
            genesisConfig.ValidateOrThrow();
            var initialConsensusState = new ConsensusState(
                genesisConfig.ThresholdEncryptionPublicKey.HexToBytes(),
                genesisConfig.Validators.Select(v => new ValidatorCredentials
                                                (
                                                    v.EcdsaPublicKey.HexToBytes().ToPublicKey(),
                                                    v.ThresholdSignaturePublicKey.HexToBytes()
                                                )).ToArray()
                );

            snapshot.Validators.SetConsensusState(initialConsensusState);

            // stake delegation happens even before genesis block
            // stake delegation means - some other address stakes for the validators
            // config.json keeps the stakerAddress and the stakeAmount for each of the validators

            // init system contracts storage
            var dummyStakerPub = new string('f', CryptoUtils.PublicKeyLength * 2).HexToBytes();

            snapshot.Storage.SetRawValue(
                ContractRegisterer.StakingContract,
                new BigInteger(6).ToUInt256().Buffer,
                dummyStakerPub
                );

            // TODO: get rid of explicit numbering of fields
            var initialVrfSeed = Encoding.ASCII.GetBytes("test");

            snapshot.Storage.SetRawValue(
                ContractRegisterer.StakingContract,
                new BigInteger(7).ToUInt256().Buffer,
                initialVrfSeed
                );

            var initialBlockReward = Money.Parse(genesisConfig.BlockReward).ToUInt256().ToBytes();

            snapshot.Storage.SetRawValue(
                ContractRegisterer.GovernanceContract,
                new BigInteger(3).ToUInt256().Buffer,
                initialBlockReward
                );

            var initialBasicGasPrice = Money.Parse(genesisConfig.BasicGasPrice).ToUInt256().ToBytes();

            snapshot.Storage.SetRawValue(
                ContractRegisterer.GovernanceContract,
                new BigInteger(8).ToUInt256().Buffer,
                initialBasicGasPrice
                );

            // The followings are the variables used in stakingContract
            // This variables are stored in the storage snapshot and is a part of the chain
            // To understand the what each variables represent, refer to StakingContract.cs

            // We do the stake delegation even before the execution of genesis block

            var _userToStake = new StorageMapping(
                ContractRegisterer.StakingContract,
                snapshot.Storage,
                new BigInteger(3).ToUInt256()
                );
            var _stakers = new StorageVariable(
                ContractRegisterer.StakingContract,
                snapshot.Storage,
                new BigInteger(6).ToUInt256()
                );
            var _userToPubKey = new StorageMapping(
                ContractRegisterer.StakingContract,
                snapshot.Storage,
                new BigInteger(2).ToUInt256()
                );
            var _pubKeyToStaker = new StorageMapping(
                ContractRegisterer.StakingContract,
                snapshot.Storage,
                new BigInteger(12).ToUInt256()
                );
            var _userToStartCycle = new StorageMapping(
                ContractRegisterer.StakingContract,
                snapshot.Storage,
                new BigInteger(4).ToUInt256()
                );

            foreach (var validator in genesisConfig.Validators)
            {
                if (validator.StakeAmount == null || validator.StakerAddress == null)
                {
                    continue;
                }
                var validatorPublicKey = validator.EcdsaPublicKey.HexToBytes();
                var validatorAddress   = Hepler.PublicKeyToAddress(validatorPublicKey).ToBytes();
                var stakerAddress      = validator.StakerAddress.HexToBytes();

                // add balance to staking contract
                var stakeAmount = Money.Parse(validator.StakeAmount);
                snapshot.Balances.AddBalance(ContractRegisterer.StakingContract, stakeAmount, true);
                // set stake value
                _userToStake.SetValue(validatorAddress, stakeAmount.ToUInt256().ToBytes());
                // update stakers list
                var stakers = _stakers.Get();
                _stakers.Set(stakers.Concat(validatorPublicKey).ToArray());
                // user to public key and public key to staker
                _userToPubKey.SetValue(validatorAddress, validatorPublicKey);
                _pubKeyToStaker.SetValue(validatorPublicKey, stakerAddress);
                // set start cycle
                _userToStartCycle.SetValue(validatorAddress, BitConverter.GetBytes(0));
            }

            _stateManager.Approve();

            // emulate and execute the genesis block
            var(error, removeTransactions, stateHash, relayTransactions) =
                Emulate(genesisBlock.Block, genesisBlock.Transactions);
            if (error != OperatingError.Ok)
            {
                throw new InvalidBlockException(error);
            }
            if (removeTransactions.Count != 0)
            {
                throw new InvalidBlockException(OperatingError.InvalidTransaction);
            }
            if (relayTransactions.Count != 0)
            {
                throw new InvalidBlockException(OperatingError.InvalidTransaction);
            }
            genesisBlock.Block.Header.StateHash = stateHash;
            genesisBlock.Block.Hash             = genesisBlock.Block.Header.Keccak();

            error = Execute(genesisBlock.Block, genesisBlock.Transactions, commit: true, checkStateHash: true);
            if (error != OperatingError.Ok)
            {
                throw new InvalidBlockException(error);
            }
            _stateManager.Commit();
            BlockPersisted(genesisBlock.Block);
            return(true);
        }