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); }
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); }
private void SetTpkeKey(byte[] tpkePublicKey) { _tpkeKey.Set(tpkePublicKey); }
private void SetCollectedFees(Money fees) { _collectedFees.Set(fees.ToUInt256().ToBytes()); }
private void SetTSKeys(PublicKeySet tsKeys) { _tsKeys.Set(tsKeys.ToBytes().ToArray()); }
private void SetPlayersCount(int count) { _playersCount.Set(count.ToBytes().ToArray()); }
// 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); }