StatusMessage.java
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth.messages;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractMessageData;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
public final class StatusMessage extends AbstractMessageData {
private EthStatus status;
public StatusMessage(final Bytes data) {
super(data);
}
public static StatusMessage create(
final int protocolVersion,
final BigInteger networkId,
final Difficulty totalDifficulty,
final Hash bestHash,
final Hash genesisHash) {
final EthStatus status =
new EthStatus(protocolVersion, networkId, totalDifficulty, bestHash, genesisHash);
final BytesValueRLPOutput out = new BytesValueRLPOutput();
status.writeTo(out);
return new StatusMessage(out.encoded());
}
public static StatusMessage create(
final int protocolVersion,
final BigInteger networkId,
final Difficulty totalDifficulty,
final Hash bestHash,
final Hash genesisHash,
final ForkId forkId) {
final EthStatus status =
new EthStatus(protocolVersion, networkId, totalDifficulty, bestHash, genesisHash, forkId);
final BytesValueRLPOutput out = new BytesValueRLPOutput();
status.writeTo(out);
return new StatusMessage(out.encoded());
}
public static StatusMessage readFrom(final MessageData message) {
if (message instanceof StatusMessage) {
return (StatusMessage) message;
}
final int code = message.getCode();
if (code != EthPV62.STATUS) {
throw new IllegalArgumentException(
String.format("Message has code %d and thus is not a StatusMessage.", code));
}
return new StatusMessage(message.getData());
}
@Override
public int getCode() {
return EthPV62.STATUS;
}
/**
* Return The eth protocol version the associated node is running.
*
* @return The eth protocol version the associated node is running.
*/
public int protocolVersion() {
return status().protocolVersion;
}
/**
* Return The id of the network the associated node is participating in.
*
* @return The id of the network the associated node is participating in.
*/
public BigInteger networkId() {
return status().networkId;
}
/**
* Return The total difficulty of the head of the associated node's local blockchain.
*
* @return The total difficulty of the head of the associated node's local blockchain.
*/
public Difficulty totalDifficulty() {
return status().totalDifficulty;
}
/**
* Return The hash of the head of the associated node's local blockchain.
*
* @return The hash of the head of the associated node's local blockchain.
*/
public Hash bestHash() {
return status().bestHash;
}
/**
* Return The hash of the genesis block of the network the associated node is participating in.
*
* @return The hash of the genesis block of the network the associated node is participating in.
*/
public Bytes32 genesisHash() {
return status().genesisHash;
}
/**
* Return The fork id of the network the associated node is participating in.
*
* @return The fork id of the network the associated node is participating in.
*/
public ForkId forkId() {
return status().forkId;
}
private EthStatus status() {
if (status == null) {
final RLPInput input = RLP.input(data);
status = EthStatus.readFrom(input);
}
return status;
}
private static class EthStatus {
private final int protocolVersion;
private final BigInteger networkId;
private final Difficulty totalDifficulty;
private final Hash bestHash;
private final Hash genesisHash;
private final ForkId forkId;
EthStatus(
final int protocolVersion,
final BigInteger networkId,
final Difficulty totalDifficulty,
final Hash bestHash,
final Hash genesisHash) {
this.protocolVersion = protocolVersion;
this.networkId = networkId;
this.totalDifficulty = totalDifficulty;
this.bestHash = bestHash;
this.genesisHash = genesisHash;
this.forkId = null;
}
EthStatus(
final int protocolVersion,
final BigInteger networkId,
final Difficulty totalDifficulty,
final Hash bestHash,
final Hash genesisHash,
final ForkId forkHash) {
this.protocolVersion = protocolVersion;
this.networkId = networkId;
this.totalDifficulty = totalDifficulty;
this.bestHash = bestHash;
this.genesisHash = genesisHash;
this.forkId = forkHash;
}
public void writeTo(final RLPOutput out) {
out.startList();
out.writeIntScalar(protocolVersion);
out.writeBigIntegerScalar(networkId);
out.writeUInt256Scalar(totalDifficulty);
out.writeBytes(bestHash);
out.writeBytes(genesisHash);
if (forkId != null) {
forkId.writeTo(out);
}
out.endList();
}
public static EthStatus readFrom(final RLPInput in) {
in.enterList();
final int protocolVersion = in.readIntScalar();
final BigInteger networkId = in.readBigIntegerScalar();
final Difficulty totalDifficulty = Difficulty.of(in.readUInt256Scalar());
final Hash bestHash = Hash.wrap(in.readBytes32());
final Hash genesisHash = Hash.wrap(in.readBytes32());
final ForkId forkId;
if (in.nextIsList()) {
forkId = ForkId.readFrom(in);
} else {
forkId = null;
}
in.leaveList();
return new EthStatus(
protocolVersion, networkId, totalDifficulty, bestHash, genesisHash, forkId);
}
@Override
public String toString() {
return "{"
+ "protocolVersion="
+ protocolVersion
+ ", networkId="
+ networkId
+ ", totalDifficulty="
+ totalDifficulty
+ ", bestHash="
+ bestHash
+ ", genesisHash="
+ genesisHash
+ ", forkId="
+ forkId
+ '}';
}
}
@Override
public String toStringDecoded() {
return status().toString();
}
}