module ValidatorSet { import 0x0.Event; import 0x0.LibraAccount; import 0x0.Vector; struct ValidatorInfo { addr: address, consensus_pubkey: bytearray, consensus_voting_power: u64, network_signing_pubkey: bytearray, network_identity_pubkey: bytearray, } // A current or prospective validator should publish one of these under their address resource ValidatorConfig { network_signing_pubkey: bytearray, network_identity_pubkey: bytearray, consensus_pubkey: bytearray, } struct ChangeEvent { new_validator_set: Vector.T, } resource T { validators: Vector.T, change_events: Event.Handle, } // This can only be invoked by the special validator set address, and only a single time. // Currently, it is invoked in the genesis transaction. public initialize() { // Only callable by the validator set address assert(get_txn_sender() == 0x1D8, 1); move_to_sender(T { validators: Vector.empty(), change_events: Event.new_event_handle(), }); return; } // Return the size of the current validator set public size(): u64 acquires T { let validator_set_ref: &Self.T; validator_set_ref = borrow_global(0x1D8); return Vector.length(&move(validator_set_ref).validators); } // Return true if addr is a current validator public is_validator(addr: address): bool acquires T { let size: u64; let i: u64; let vector_ref: &Vector.T; let info_ref: &Self.ValidatorInfo; vector_ref = &borrow_global(0x1D8).validators; size = Vector.length(copy(vector_ref)); if (copy(size) == 0) { return false; } i = 0; info_ref = Vector.borrow(copy(vector_ref), copy(i)); while (copy(i) < copy(size)) { if (*©(info_ref).addr == copy(addr)) { // TODO: below doesn't work, looks like a compiler bug //if (*(&Vector.borrow(copy(vector_ref), copy(i)).addr) == copy(addr)) { return true; } info_ref = Vector.borrow(copy(vector_ref), copy(i)); i = copy(i) + 1; } return false; } // Register the transaction sender as a candidate validator by creating a ValidatorConfig // resource under their account public register_candidate_validator( network_signing_pubkey: bytearray, network_identity_pubkey: bytearray, consensus_pubkey: bytearray) { move_to_sender( ValidatorConfig { network_signing_pubkey: move(network_signing_pubkey), network_identity_pubkey: move(network_identity_pubkey), consensus_pubkey: move(consensus_pubkey), }); return; } // Get the consensus public key for the validator candidate at the given address public get_consensus_pubkey(addr: address): bytearray acquires ValidatorConfig { let config_ref: &Self.ValidatorConfig; config_ref = borrow_global(move(addr)); return *&move(config_ref).consensus_pubkey; } // Rotate a validator candidate's consensus public key. The change will not take effect until // the next reconfiguration. public rotate_consensus_pubkey(consensus_pubkey: bytearray) acquires ValidatorConfig { let config_ref: &mut Self.ValidatorConfig; config_ref = borrow_global_mut(get_txn_sender()); *(&mut move(config_ref).consensus_pubkey) = move(consensus_pubkey); return; } // TODO: Decide on access control policy. For now, we ensure that this is only callable from the // genesis txn. Obviously, we'll need a different policy once we support reconfiguration. add_validator(account_address: address) acquires T, ValidatorConfig { let config_ref: &Self.ValidatorConfig; let validator_set_ref: &mut Self.T; let vector_ref: &mut Vector.T; // A prospective validator must have an account assert(LibraAccount.exists(copy(account_address)), 17); config_ref = borrow_global(copy(account_address)); validator_set_ref = borrow_global_mut(0x1D8); Vector.push_back( &mut move(validator_set_ref).validators, ValidatorInfo { addr: move(account_address), consensus_pubkey: *©(config_ref).consensus_pubkey, // TODO: check for LIT, compute voting power based on LIT + stake consensus_voting_power: 1, network_signing_pubkey: *©(config_ref).network_signing_pubkey, network_identity_pubkey: *&move(config_ref).network_identity_pubkey, } ); return; } // Trigger a reconfiguation the Libra system by: // (1) Computing a new validator set and storing it on chain // (2) Emitting an event containing new validator set, which will be passed to the executor reconfigure() acquires T { let validator_set_ref: &mut Self.T; let vector_ref: &Vector.T; // TODO: for now, we just emit the current validator set. Eventually, we'll compute the new // validator set from a larger list of candidate validators sorted by stake. validator_set_ref = borrow_global_mut(0x1D8); Event.emit_event( &mut copy(validator_set_ref).change_events, ChangeEvent { new_validator_set: *&move(validator_set_ref).validators, }, ); return; } }