2019-07-15 21:59:19 -04:00
|
|
|
// @flow
|
|
|
|
|
2021-02-02 10:53:24 +08:00
|
|
|
import {Buffer} from 'buffer';
|
2021-02-26 15:06:12 +08:00
|
|
|
import {
|
|
|
|
assert as assertType,
|
|
|
|
optional,
|
|
|
|
string,
|
|
|
|
type as pick,
|
|
|
|
} from 'superstruct';
|
2019-07-15 21:59:19 -04:00
|
|
|
|
|
|
|
import * as Layout from './layout';
|
|
|
|
import * as shortvec from './util/shortvec-encoding';
|
|
|
|
import {PublicKey} from './publickey';
|
|
|
|
|
2019-07-24 16:01:07 -07:00
|
|
|
export const VALIDATOR_INFO_KEY = new PublicKey(
|
2019-07-15 21:59:19 -04:00
|
|
|
'Va1idator1nfo111111111111111111111111111111',
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
type ConfigKey = {|
|
|
|
|
publicKey: PublicKey,
|
|
|
|
isSigner: boolean,
|
|
|
|
|};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Info used to identity validators.
|
|
|
|
*
|
|
|
|
* @typedef {Object} Info
|
|
|
|
* @property {string} name validator name
|
|
|
|
* @property {?string} website optional, validator website
|
|
|
|
* @property {?string} details optional, extra information the validator chose to share
|
2019-07-18 09:40:34 -06:00
|
|
|
* @property {?string} keybaseUsername optional, used to identify validators on keybase.io
|
2019-07-15 21:59:19 -04:00
|
|
|
*/
|
|
|
|
export type Info = {|
|
|
|
|
name: string,
|
|
|
|
website?: string,
|
|
|
|
details?: string,
|
2019-07-18 09:40:34 -06:00
|
|
|
keybaseUsername?: string,
|
2019-07-15 21:59:19 -04:00
|
|
|
|};
|
|
|
|
|
2021-02-26 15:06:12 +08:00
|
|
|
const InfoString = pick({
|
|
|
|
name: string(),
|
|
|
|
website: optional(string()),
|
|
|
|
details: optional(string()),
|
|
|
|
keybaseUsername: optional(string()),
|
2019-07-15 21:59:19 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ValidatorInfo class
|
|
|
|
*/
|
|
|
|
export class ValidatorInfo {
|
|
|
|
/**
|
|
|
|
* validator public key
|
|
|
|
*/
|
|
|
|
key: PublicKey;
|
|
|
|
/**
|
|
|
|
* validator information
|
|
|
|
*/
|
|
|
|
info: Info;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct a valid ValidatorInfo
|
|
|
|
*
|
|
|
|
* @param key validator public key
|
|
|
|
* @param info validator information
|
|
|
|
*/
|
|
|
|
constructor(key: PublicKey, info: Info) {
|
|
|
|
this.key = key;
|
|
|
|
this.info = info;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deserialize ValidatorInfo from the config account data. Exactly two config
|
|
|
|
* keys are required in the data.
|
|
|
|
*
|
|
|
|
* @param buffer config account data
|
|
|
|
* @return null if info was not found
|
|
|
|
*/
|
2020-02-14 22:33:11 +08:00
|
|
|
static fromConfigData(
|
|
|
|
buffer: Buffer | Uint8Array | Array<number>,
|
|
|
|
): ValidatorInfo | null {
|
2019-07-15 21:59:19 -04:00
|
|
|
const PUBKEY_LENGTH = 32;
|
|
|
|
|
|
|
|
let byteArray = [...buffer];
|
|
|
|
const configKeyCount = shortvec.decodeLength(byteArray);
|
|
|
|
if (configKeyCount !== 2) return null;
|
|
|
|
|
|
|
|
const configKeys: Array<ConfigKey> = [];
|
|
|
|
for (let i = 0; i < 2; i++) {
|
|
|
|
const publicKey = new PublicKey(byteArray.slice(0, PUBKEY_LENGTH));
|
|
|
|
byteArray = byteArray.slice(PUBKEY_LENGTH);
|
|
|
|
const isSigner = byteArray.slice(0, 1)[0] === 1;
|
|
|
|
byteArray = byteArray.slice(1);
|
|
|
|
configKeys.push({publicKey, isSigner});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (configKeys[0].publicKey.equals(VALIDATOR_INFO_KEY)) {
|
|
|
|
if (configKeys[1].isSigner) {
|
|
|
|
const rawInfo = Layout.rustString().decode(Buffer.from(byteArray));
|
2021-02-26 15:06:12 +08:00
|
|
|
const info = JSON.parse(rawInfo);
|
|
|
|
assertType(info, InfoString);
|
2019-07-15 21:59:19 -04:00
|
|
|
return new ValidatorInfo(configKeys[1].publicKey, info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|