简述
witness 即在tron链中就是产块节点的代名词,一般称为SR
。
一般节点不产块,要配置成witness,需要启动时指定私钥,并使用--witness
或-w
指定成为产块节点。
witness 加载过程
有两种加载方式:
- 参数或配置文件
- 指定
localwitness
启动
参数或配置文件
通过参数指定为witness节点,但是私钥建议写在配置文件中,否则ps
查看一下进程就能看到启动参数,就全暴露了,但是如果有人能上机器,也能查看配置文件。
java -jar FullNode.jar --witness -p xxxxxxxxxxxxxxxxxx
输入上面的命令后,节点就会以SR
类型启动,具体是如何加载的,调用栈如下:
FullNode.main()
--Args.setParam(args, Constant.TESTNET_CONF); //381
--PARAMETER.privateKey //优先加载 参数
--Constant.LOCAL_WITNESS //或加载 配置文件
--LocalWitnesses.setPrivateKeys //或从 keystore 中加载
FullNode.startup()
--ConsensusService.start() // 加载localwitness
Args.setParam 加载过程
代码语言:javascript复制@Slf4j(topic = "app")
@NoArgsConstructor
@Component
public class Args extends CommonParameter {
@Getter
@Setter
private static LocalWitnesses localWitnesses = new LocalWitnesses();
public static void setParam(final String[] args, final String confFileName) {
// 省略部分代码
...
// PARAMETER.privateKey 即 -p 或 --private-key 参数
if (StringUtils.isNoneBlank(PARAMETER.privateKey)) {
localWitnesses = (new LocalWitnesses(PARAMETER.privateKey));
if (StringUtils.isNoneBlank(PARAMETER.witnessAddress)) {
byte[] bytes = Commons.decodeFromBase58Check(PARAMETER.witnessAddress);
if (bytes != null) {
localWitnesses.setWitnessAccountAddress(bytes);
logger.debug("Got localWitnessAccountAddress from cmd");
} else {
PARAMETER.witnessAddress = "";
logger.warn(IGNORE_WRONG_WITNESS_ADDRESS_FORMAT);
}
}
// 初始化 witness
localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine());
logger.debug("Got privateKey from cmd");
} else if (config.hasPath(Constant.LOCAL_WITNESS)) {
// Constant.LOCAL_WITNESS 即,配置文件中的 localwitness 这个配置项,可以配置多个
// 作用就是一个 java-tron 服务,配置多个witness产块,这样做的话,要约成本,一台机器就可以配置多个
localWitnesses = new LocalWitnesses();
List<String> localwitness = config.getStringList(Constant.LOCAL_WITNESS);
localWitnesses.setPrivateKeys(localwitness);
witnessAddressCheck(config);
localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine());
logger.debug("Got privateKey from config.conf");
} else if (config.hasPath(Constant.LOCAL_WITNESS_KEYSTORE)) {
// 通过 keystore 加载
localWitnesses = new LocalWitnesses();
List<String> privateKeys = new ArrayList<String>();
if (PARAMETER.isWitness()) {
List<String> localwitness = config.getStringList(Constant.LOCAL_WITNESS_KEYSTORE);
if (localwitness.size() > 0) {
String fileName = System.getProperty("user.dir") "/" localwitness.get(0);
String password;
if (StringUtils.isEmpty(PARAMETER.password)) {
System.out.println("Please input your password.");
password = WalletUtils.inputPassword();
} else {
password = PARAMETER.password;
PARAMETER.password = null;
}
try {
Credentials credentials = WalletUtils
.loadCredentials(password, new File(fileName));
SignInterface sign = credentials.getSignInterface();
String prikey = ByteArray.toHexString(sign.getPrivateKey());
privateKeys.add(prikey);
} catch (IOException | CipherException e) {
logger.error(e.getMessage());
logger.error("Witness node start failed!");
exit(-1);
}
}
}
localWitnesses.setPrivateKeys(privateKeys);
witnessAddressCheck(config);
localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine());
logger.debug("Got privateKey from keystore");
}
// 省略部分代码
...
}
}
共识阶段加载
ConsensusService
主要控制共识相关,在启动时。
ConsensusService.start
--Consensus.start
--DposService.start // 对共抽的抽象,设计上方便切换共识
几个关注的点:
- 设置成
witness
节点 - 加载前面的私钥
- 启动共识
- 更新updateWitness
public void start() {
Param param = Param.getInstance();
// 设置成 witness 节点
param.setEnable(parameter.isWitness());
param.setGenesisBlock(parameter.getGenesisBlock());
param.setMinParticipationRate(parameter.getMinParticipationRate());
param.setBlockProduceTimeoutPercent(Args.getInstance().getBlockProducedTimeOut());
param.setNeedSyncCheck(parameter.isNeedSyncCheck());
param.setAgreeNodeCount(parameter.getAgreeNodeCount());
List<Miner> miners = new ArrayList<>();
// 拿到私钥列表
List<String> privateKeys = Args.getLocalWitnesses().getPrivateKeys();
if (privateKeys.size() > 1) {
// 前面说了,可以配置多个 私钥,所以这里遍历
for (String key : privateKeys) {
byte[] privateKey = fromHexString(key);
byte[] privateKeyAddress = SignUtils
.fromPrivate(privateKey, Args.getInstance().isECKeyCryptoEngine()).getAddress();
WitnessCapsule witnessCapsule = witnessStore.get(privateKeyAddress);
if (null == witnessCapsule) {
logger.warn("Witness {} is not in witnessStore.", Hex.toHexString(privateKeyAddress));
}
// 封装到 Miner 中,在产块时私钥相关校验
Miner miner = param.new Miner(privateKey, ByteString.copyFrom(privateKeyAddress),
ByteString.copyFrom(privateKeyAddress));
miners.add(miner);
logger.info("Add witness: {}, size: {}",
Hex.toHexString(privateKeyAddress), miners.size());
}
} else {
byte[] privateKey =
fromHexString(Args.getLocalWitnesses().getPrivateKey());
byte[] privateKeyAddress = SignUtils.fromPrivate(privateKey,
Args.getInstance().isECKeyCryptoEngine()).getAddress();
byte[] witnessAddress = Args.getLocalWitnesses().getWitnessAccountAddress(
Args.getInstance().isECKeyCryptoEngine());
WitnessCapsule witnessCapsule = witnessStore.get(witnessAddress);
if (null == witnessCapsule) {
logger.warn("Witness {} is not in witnessStore.", Hex.toHexString(witnessAddress));
}
Miner miner = param.new Miner(privateKey, ByteString.copyFrom(privateKeyAddress),
ByteString.copyFrom(witnessAddress));
miners.add(miner);
}
param.setMiners(miners);
param.setBlockHandle(blockHandle);
param.setPbftInterface(pbftBaseImpl);
// 启动共识
consensus.start(param);
logger.info("consensus service start success");
}
Dpos 中加载
//TODO