Skip to content

Commit

Permalink
Implemented functionality for reading grandpa consensus message
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleksandr committed Dec 19, 2024
1 parent be7cbd0 commit 2722477
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.limechain.network.protocol.grandpa.messages.consensus;

import com.limechain.chain.lightsyncstate.Authority;
import lombok.Data;

import java.math.BigInteger;
import java.util.List;

@Data
public class GrandpaConsensusMessage {
private long bestFinalizedBlock;
private List<Authority> authorities;
private BigInteger disabledAuthority;
private long delay;
private GrandpaConsensusMessageFormat format;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.limechain.network.protocol.grandpa.messages.consensus;

import lombok.Getter;

@Getter
public enum GrandpaConsensusMessageFormat {
GRANDPA_SCHEDULED_CHANGE(1), GRANDPA_FORCED_CHANGE(2), GRANDPA_ON_DISABLED(3), GRANDPA_PAUSE(4), GRANDPA_RESUME(5);

private final int format;

GrandpaConsensusMessageFormat(int format) {
this.format = format;
}

public static GrandpaConsensusMessageFormat fromFormat(byte format) {
for (GrandpaConsensusMessageFormat messageFormat : values()) {
if (messageFormat.getFormat() == format) {
return messageFormat;
}
}
throw new IllegalArgumentException("Unknown grandpa consensus message format: " + format);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.limechain.network.protocol.grandpa.messages.consensus;

import com.limechain.chain.lightsyncstate.Authority;
import com.limechain.chain.lightsyncstate.scale.AuthorityReader;
import io.emeraldpay.polkaj.scale.ScaleCodecReader;
import io.emeraldpay.polkaj.scale.ScaleReader;
import io.emeraldpay.polkaj.scale.reader.ListReader;
import io.emeraldpay.polkaj.scale.reader.UInt64Reader;

import java.util.List;

public class GrandpaConsensusMessageReader implements ScaleReader<GrandpaConsensusMessage> {

@Override
public GrandpaConsensusMessage read(ScaleCodecReader reader) {
GrandpaConsensusMessage grandpaConsensusMessage = new GrandpaConsensusMessage();
GrandpaConsensusMessageFormat format = GrandpaConsensusMessageFormat.fromFormat(reader.readByte());
grandpaConsensusMessage.setFormat(format);
switch (format) {
case GRANDPA_SCHEDULED_CHANGE -> {
List<Authority> authorities = reader.read(new ListReader<>(new AuthorityReader()));
long delay = reader.readUint32();
grandpaConsensusMessage.setAuthorities(authorities);
grandpaConsensusMessage.setDelay(delay);
}
case GRANDPA_FORCED_CHANGE -> {
long bestFinalizedBlock = reader.readUint32();
List<Authority> authorities = reader.read(new ListReader<>(new AuthorityReader()));
long delay = reader.readUint32();
grandpaConsensusMessage.setBestFinalizedBlock(bestFinalizedBlock);
grandpaConsensusMessage.setAuthorities(authorities);
grandpaConsensusMessage.setDelay(delay);
}
case GRANDPA_ON_DISABLED -> grandpaConsensusMessage.setDisabledAuthority(new UInt64Reader().read(reader));
case GRANDPA_PAUSE, GRANDPA_RESUME -> grandpaConsensusMessage.setDelay(reader.readUint32());
}
return grandpaConsensusMessage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.limechain.babe.consensus.scale.BabeConsensusMessageReader;
import com.limechain.babe.predigest.BabePreDigest;
import com.limechain.babe.predigest.scale.PreDigestReader;
import com.limechain.network.protocol.grandpa.messages.consensus.GrandpaConsensusMessage;
import com.limechain.network.protocol.grandpa.messages.consensus.GrandpaConsensusMessageReader;
import com.limechain.network.protocol.warp.dto.BlockHeader;
import com.limechain.network.protocol.warp.dto.ConsensusEngine;
import com.limechain.network.protocol.warp.dto.DigestType;
Expand Down Expand Up @@ -32,6 +34,15 @@ public static Optional<BabeConsensusMessage> getBabeConsensusMessage(HeaderDiges
.map(message -> ScaleUtils.Decode.decode(message, new BabeConsensusMessageReader()));
}

public static Optional<GrandpaConsensusMessage> getGrandpaConsensusMessage(HeaderDigest[] headerDigests) {
return Arrays.stream(headerDigests)
.filter(headerDigest -> DigestType.CONSENSUS_MESSAGE.equals(headerDigest.getType()) &&
ConsensusEngine.GRANDPA.equals(headerDigest.getId()))
.findFirst()
.map(HeaderDigest::getMessage)
.map(message -> ScaleUtils.Decode.decode(message, new GrandpaConsensusMessageReader()));
}

public static Optional<BabePreDigest> getBabePreRuntimeDigest(HeaderDigest[] headerDigests) {
return Arrays.stream(headerDigests)
.filter(headerDigest -> DigestType.PRE_RUNTIME.equals(headerDigest.getType()) &&
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.limechain.network.protocol.grandpa.messages.consensus;

import com.limechain.utils.StringUtils;
import io.emeraldpay.polkaj.scale.ScaleCodecReader;
import org.junit.jupiter.api.Test;

import java.math.BigInteger;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class GrandpaConsensusMessageReaderTest {

private final GrandpaConsensusMessageReader reader = new GrandpaConsensusMessageReader();

@Test
public void testScheduledChangeInput() {
String hexWithPrefix = "0x0104010101010101010101010101010101010101010101010101010101010101010101020000000000000003000000";
byte[] input = StringUtils.hexToBytes(hexWithPrefix);
GrandpaConsensusMessage message = reader.read(new ScaleCodecReader(input));
assertNotNull(message);
assertEquals(GrandpaConsensusMessageFormat.GRANDPA_SCHEDULED_CHANGE, message.getFormat());
assertNotNull(message.getAuthorities());
assertEquals(1, message.getAuthorities().size());
assertEquals(768L, message.getDelay());
}

@Test
public void testForcedChangeInput() {
String hexWithPrefix = "0x020300000004010101010101010101010101010101010101010101010101010101010101010101020000000000000003000000";
byte[] input = StringUtils.hexToBytes(hexWithPrefix);
GrandpaConsensusMessage message = reader.read(new ScaleCodecReader(input));
assertNotNull(message);
assertEquals(GrandpaConsensusMessageFormat.GRANDPA_FORCED_CHANGE, message.getFormat());
assertEquals(3, message.getBestFinalizedBlock());
assertNotNull(message.getAuthorities());

assertEquals(1, message.getAuthorities().size());
assertEquals(768L, message.getDelay());
}

@Test
public void testOnDisabledInput() {
String hexWithPrefix = "0x0315cd5b0700000000";
byte[] input = StringUtils.hexToBytes(hexWithPrefix);
GrandpaConsensusMessage message = reader.read(new ScaleCodecReader(input));
assertNotNull(message);
assertEquals(GrandpaConsensusMessageFormat.GRANDPA_ON_DISABLED, message.getFormat());
assertEquals(BigInteger.valueOf(123456789L), message.getDisabledAuthority());
}

@Test
public void testPauseInput() {
String hexWithPrefix = "0x0414000000";
byte[] input = StringUtils.hexToBytes(hexWithPrefix);
GrandpaConsensusMessage message = reader.read(new ScaleCodecReader(input));
assertNotNull(message);
assertEquals(GrandpaConsensusMessageFormat.GRANDPA_PAUSE, message.getFormat());
assertEquals(20L, message.getDelay());
}

@Test
public void testResumeInput() {
String hexWithPrefix = "0x0519000000";
byte[] input = StringUtils.hexToBytes(hexWithPrefix);
GrandpaConsensusMessage message = reader.read(new ScaleCodecReader(input));
assertNotNull(message);
assertEquals(GrandpaConsensusMessageFormat.GRANDPA_RESUME, message.getFormat());
assertEquals(25L, message.getDelay());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.limechain.babe.consensus.BabeConsensusMessageFormat;
import com.limechain.babe.predigest.PreDigestType;
import com.limechain.network.protocol.grandpa.messages.consensus.GrandpaConsensusMessageFormat;
import com.limechain.network.protocol.warp.dto.BlockHeader;
import com.limechain.network.protocol.warp.dto.ConsensusEngine;
import com.limechain.network.protocol.warp.dto.DigestType;
Expand Down Expand Up @@ -52,6 +53,34 @@ void getBabeConsensusMessageWithoutSuchDigestInHeadersTest() {
assertTrue(optResult.isEmpty());
}

@Test
void getGrandpaConsensusMessageTest() {
HeaderDigest consensusDigest = new HeaderDigest();
consensusDigest.setId(ConsensusEngine.GRANDPA);
consensusDigest.setType(DigestType.CONSENSUS_MESSAGE);

// Create a consensus message with type GRANDPA_ON_DISABLED(3) and value equal to 0
var message = new byte[33];
message[0] = 3;
consensusDigest.setMessage(message);

HeaderDigest[] headerDigests = new HeaderDigest[] {consensusDigest};
var optResult = DigestHelper.getGrandpaConsensusMessage(headerDigests);

assertTrue(optResult.isPresent());

var result = optResult.get();
assertEquals(GrandpaConsensusMessageFormat.GRANDPA_ON_DISABLED, result.getFormat());
assertEquals(BigInteger.ZERO, result.getDisabledAuthority());
assertNull(result.getAuthorities());
}

@Test
void getGrandpaConsensusMessageWithoutSuchDigestInHeadersTest() {
var optResult = DigestHelper.getGrandpaConsensusMessage(new HeaderDigest[0]);
assertTrue(optResult.isEmpty());
}

@Test
void getBabePreRuntimeDigestForPrimarySlotTest() {
HeaderDigest consensusDigest = new HeaderDigest();
Expand Down

0 comments on commit 2722477

Please sign in to comment.