Skip to content
This repository has been archived by the owner on Feb 19, 2024. It is now read-only.

Validator api #226

Merged
merged 8 commits into from
Apr 25, 2021
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ public void start(SimulationNodes.RunningNetwork network) {
List<BFTNode> nodes = network.getNodes();
this.disposable = Observable.interval(1, 1, TimeUnit.SECONDS)
.map(i -> nodes.get(random.nextInt(nodes.size())))
.map(node -> network.getDispatcher(NodeApplicationRequest.class, node))
.subscribe(d -> {
.subscribe(node -> {
var d = network.getDispatcher(NodeApplicationRequest.class, node);
var builder = TxActionListBuilder.create();
if (random.nextBoolean()) {
builder.registerAsValidator();
builder.registerAsValidator(node.getKey());
} else {
builder.unregisterAsValidator();
builder.unregisterAsValidator(node.getKey());
}

var request = NodeApplicationRequest.create(builder.build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ public void start(SimulationNodes.RunningNetwork network) {
this.disposable = Observable.fromIterable(nodes)
.concatMap(i -> Observable.timer(3, TimeUnit.SECONDS).map(l -> i))
.doOnNext(validationRegistrations::onNext)
.map(node -> network.getDispatcher(NodeApplicationRequest.class, node))
.subscribe(d -> d.dispatch(NodeApplicationRequest.create(new RegisterValidator())));
.subscribe(node -> {
var d = network.getDispatcher(NodeApplicationRequest.class, node);
d.dispatch(NodeApplicationRequest.create(new RegisterValidator(node.getKey())));
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ public NodeEventProcessor<?> updateChecker() {
ViewQuorumReached.class,
(node, viewQuorumReached) -> {
if (viewQuorumReached.votingResult() instanceof FormedQC
&& ((FormedQC) viewQuorumReached.votingResult())
.getQC().getCommittedAndLedgerStateProof().isPresent()) {
&& ((FormedQC) viewQuorumReached.votingResult()).getQC().getCommitted().isPresent()) {
lastNodeToCommit = network.lookup(node);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,14 @@ private BFTSync bftSync(
@LastProof LedgerProof ledgerLastProof, // Use this instead of configuration.getRoot()
Random random,
@BFTSyncPatienceMillis int bftSyncPatienceMillis,
Hasher hasher,
SystemCounters counters
) {
return new BFTSync(
self,
syncRequestRateLimiter,
vertexStore,
hasher,
pacemakerReducer,
Comparator.comparingLong((LedgerHeader h) -> h.getAccumulatorState().getStateVersion()),
requestSender,
Expand All @@ -277,11 +279,13 @@ private VertexStore vertexStore(
EventDispatcher<BFTHighQCUpdate> highQCUpdateEventDispatcher,
EventDispatcher<BFTCommittedUpdate> committedSender,
BFTConfiguration bftConfiguration,
Ledger ledger
Ledger ledger,
Hasher hasher
) {
return VertexStore.create(
bftConfiguration.getVertexStoreState(),
ledger,
hasher,
updateSender,
rebuildUpdateDispatcher,
highQCUpdateEventDispatcher,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,14 @@ private BFTSyncFactory bftSyncFactory(
ScheduledEventDispatcher<VertexRequestTimeout> timeoutDispatcher,
Random random,
@BFTSyncPatienceMillis int bftSyncPatienceMillis,
SystemCounters counters
SystemCounters counters,
Hasher hasher
) {
return (vertexStore, pacemakerState, configuration) -> new BFTSync(
self,
syncRequestRateLimiter,
vertexStore,
hasher,
pacemakerState,
Comparator.comparingLong((LedgerHeader h) -> h.getAccumulatorState().getStateVersion()),
requestSender,
Expand All @@ -267,11 +269,13 @@ private VertexStoreFactory vertexStoreFactory(
EventDispatcher<BFTRebuildUpdate> rebuildUpdateDispatcher,
EventDispatcher<BFTHighQCUpdate> highQCUpdateEventDispatcher,
EventDispatcher<BFTCommittedUpdate> committedDispatcher,
Ledger ledger
Ledger ledger,
Hasher hasher
) {
return vertexStoreState -> VertexStore.create(
vertexStoreState,
ledger,
hasher,
updateSender,
rebuildUpdateDispatcher,
highQCUpdateEventDispatcher,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ private static VerifiedVertexStoreState serializedToVerifiedVertexStore(
serializedVertexStoreState.getHighQC(),
verifiedRoot,
vertices,
serializedVertexStoreState.getHighestTC()
serializedVertexStoreState.getHighestTC(),
hasher
);
}

Expand All @@ -133,7 +134,7 @@ private static VerifiedVertexStoreState epochProofToGenesisVertexStore(
lastEpochProof.timestamp()
);
var genesisQC = QuorumCertificate.ofGenesis(verifiedGenesisVertex, nextLedgerHeader);
return VerifiedVertexStoreState.create(HighQC.from(genesisQC), verifiedGenesisVertex, Optional.empty());
return VerifiedVertexStoreState.create(HighQC.from(genesisQC), verifiedGenesisVertex, Optional.empty(), hasher);
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import com.radixdlt.environment.EventDispatcher;
import com.radixdlt.environment.RemoteEventProcessorOnRunner;
import com.radixdlt.environment.ScheduledEventProducerOnRunner;
import com.radixdlt.ledger.DtoTxnsAndProof;
import com.radixdlt.ledger.LedgerUpdate;
import com.radixdlt.ledger.VerifiedTxnsAndProof;
import com.radixdlt.store.LastProof;
Expand Down Expand Up @@ -109,14 +108,11 @@ private VerifiedSyncResponseSender verifiedSyncResponseSender(
EventDispatcher<VerifiedTxnsAndProof> syncCommandsDispatcher
) {
return resp -> {
DtoTxnsAndProof txnsAndProof = resp.getTxnsAndProof();
var txnsAndProof = resp.getTxnsAndProof();
// TODO: Stateful ledger header verification:
// TODO: -verify rootHash matches
LedgerProof nextHeader = new LedgerProof(
txnsAndProof.getTail().getOpaque0(),
txnsAndProof.getTail().getOpaque1(),
txnsAndProof.getTail().getOpaque2(),
txnsAndProof.getTail().getOpaque3(),
var nextHeader = new LedgerProof(
txnsAndProof.getTail().getOpaque(),
txnsAndProof.getTail().getLedgerHeader(),
txnsAndProof.getTail().getSignatures()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,65 +32,79 @@
import com.radixdlt.consensus.bft.PacemakerTimeout;
import com.radixdlt.consensus.epoch.EpochViewUpdate;
import com.radixdlt.counters.SystemCountersImpl;
import com.radixdlt.environment.EventProcessor;
import com.radixdlt.environment.EventProcessorOnRunner;
import com.radixdlt.environment.LocalEvents;
import com.radixdlt.environment.ProcessWithSystemInfoRunner;
import com.radixdlt.environment.Runners;
import com.radixdlt.epochs.EpochsLedgerUpdate;
import com.radixdlt.systeminfo.InMemorySystemInfo;
import com.radixdlt.systeminfo.SystemInfoRunner;
import com.radixdlt.consensus.liveness.EpochLocalTimeoutOccurrence;
import com.radixdlt.consensus.QuorumCertificate;
import com.radixdlt.consensus.epoch.EpochView;
import com.radixdlt.middleware2.InfoSupplier;
import com.radixdlt.counters.SystemCounters;
import com.radixdlt.properties.RuntimeProperties;

import org.radix.Radix;

/**
* Module which manages system info
*/
public class SystemInfoModule extends AbstractModule {
private static final int DEFAULT_VERTEX_BUFFER_SIZE = 16;

@Override
protected void configure() {
bind(SystemCounters.class).to(SystemCountersImpl.class).in(Scopes.SINGLETON);
bind(SystemInfoRunner.class).in(Scopes.SINGLETON);

bind(InMemorySystemInfo.class).in(Scopes.SINGLETON);
var eventBinder = Multibinder.newSetBinder(binder(), new TypeLiteral<Class<?>>() { }, LocalEvents.class)
.permitDuplicates();
eventBinder.addBinding().toInstance(EpochViewUpdate.class);
eventBinder.addBinding().toInstance(EpochLocalTimeoutOccurrence.class);
eventBinder.addBinding().toInstance(BFTCommittedUpdate.class);
eventBinder.addBinding().toInstance(BFTHighQCUpdate.class);
eventBinder.addBinding().toInstance(EpochsLedgerUpdate.class);
}

@ProvidesIntoSet
private EventProcessor<EpochViewUpdate> epochViewEventProcessor(InMemorySystemInfo inMemorySystemInfo) {
return v -> inMemorySystemInfo.processView(v.getEpochView());
private EventProcessorOnRunner<?> epochsLedgerUpdateProcessor(InMemorySystemInfo inMemorySystemInfo) {
return new EventProcessorOnRunner<>(
Runners.SYSTEM_INFO,
EpochsLedgerUpdate.class,
inMemorySystemInfo.ledgerUpdateEventProcessor()
);
}

@ProvidesIntoSet
private EventProcessor<EpochLocalTimeoutOccurrence> timeoutEventProcessor(InMemorySystemInfo inMemorySystemInfo) {
return inMemorySystemInfo::processTimeout;
private EventProcessorOnRunner<?> epochViewEventProcessor(InMemorySystemInfo inMemorySystemInfo) {
return new EventProcessorOnRunner<>(
Runners.SYSTEM_INFO,
EpochViewUpdate.class,
v -> inMemorySystemInfo.processView(v.getEpochView())
);
}

@ProvidesIntoSet
private EventProcessor<BFTCommittedUpdate> committedUpdateEventProcessor(InMemorySystemInfo inMemorySystemInfo) {
return inMemorySystemInfo.bftCommittedUpdateEventProcessor();
private EventProcessorOnRunner<?> timeoutEventProcessor(InMemorySystemInfo inMemorySystemInfo) {
return new EventProcessorOnRunner<>(
Runners.SYSTEM_INFO,
EpochLocalTimeoutOccurrence.class,
inMemorySystemInfo::processTimeout
);
}

@ProvidesIntoSet
@ProcessWithSystemInfoRunner
private EventProcessor<BFTHighQCUpdate> highQCProcessor(InMemorySystemInfo inMemorySystemInfo) {
return inMemorySystemInfo.bftHighQCEventProcessor();
private EventProcessorOnRunner<?> committedUpdateEventProcessor(InMemorySystemInfo inMemorySystemInfo) {
return new EventProcessorOnRunner<>(
Runners.SYSTEM_INFO,
BFTCommittedUpdate.class,
inMemorySystemInfo.bftCommittedUpdateEventProcessor()
);
}

@Provides
@Singleton
private InMemorySystemInfo inMemorySystemInfo(RuntimeProperties runtimeProperties) {
final int vertexBufferSize = runtimeProperties.get("api.debug.vertex_buffer_size", DEFAULT_VERTEX_BUFFER_SIZE);
return new InMemorySystemInfo(vertexBufferSize);
@ProvidesIntoSet
private EventProcessorOnRunner<?> highQCProcessor(InMemorySystemInfo inMemorySystemInfo) {
return new EventProcessorOnRunner<>(
Runners.SYSTEM_INFO,
BFTHighQCUpdate.class,
inMemorySystemInfo.bftHighQCEventProcessor()
);
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* (C) Copyright 2020 Radix DLT Ltd
*
* Radix DLT Ltd licenses this file to you 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.
*/

package com.radixdlt.consensus;

import com.google.common.hash.HashCode;
import com.radixdlt.crypto.Hasher;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public final class ConsensusHasher {
private ConsensusHasher() {
throw new IllegalStateException();
}

public static HashCode toHash(HashCode opaque, LedgerHeader header, long nodeTimestamp, Hasher hasher) {
var raw = new ByteArrayOutputStream();
var outputStream = new DataOutputStream(raw);
try {
outputStream.writeInt(header != null ? 0 : 1); // 4 bytes (Version)
outputStream.write(opaque.asBytes()); // 32 bytes
if (header != null) {
outputStream.write(header.getAccumulatorState().getAccumulatorHash().asBytes()); // 32 bytes
outputStream.writeLong(header.getAccumulatorState().getStateVersion()); // 8 bytes
outputStream.writeLong(header.getEpoch()); // 8 bytes
outputStream.writeLong(header.getView().number()); // 8 bytes
outputStream.writeLong(header.timestamp()); // 8 bytes
if (header.getNextValidatorSet().isPresent()) {
var vset = header.getNextValidatorSet().get();
outputStream.writeInt(vset.getValidators().size()); // 4 bytes
for (var v : vset.getValidators().asList()) {
var key = v.getNode().getKey().getCompressedBytes();
outputStream.write(key);
var power = v.getPower();
outputStream.write(power.toByteArray());
}
} else {
outputStream.writeInt(0); // 4 bytes
}
}
outputStream.writeLong(nodeTimestamp); // 8 bytes
} catch (IOException e) {
throw new IllegalStateException();
}
var toHash = raw.toByteArray();
return hasher.hashBytes(toHash);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,6 @@ public QuorumCertificate highestCommittedQC() {
return this.highestCommittedQC == null ? this.highestQC : this.highestCommittedQC;
}

public LedgerProof proof() {
return this.highestCommittedQC().getCommittedAndLedgerStateProof().orElseThrow().getSecond();
}

@Override
public int hashCode() {
return Objects.hash(this.highestQC, this.highestCommittedQC, this.highestTC);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableSet;
import com.radixdlt.client.ValidatorAddress;
import com.radixdlt.consensus.bft.BFTValidator;
import com.radixdlt.consensus.bft.BFTValidatorSet;
import com.radixdlt.consensus.bft.View;
Expand All @@ -30,6 +31,10 @@
import com.radixdlt.serialization.SerializerConstants;
import com.radixdlt.serialization.SerializerDummy;
import com.radixdlt.serialization.SerializerId2;
import com.radixdlt.utils.Bytes;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.Objects;
import java.util.Optional;
import javax.annotation.concurrent.Immutable;
Expand Down Expand Up @@ -88,6 +93,29 @@ private LedgerHeader(
this.timestamp = timestamp;
}

public JSONObject asJSONObject() {
var json = new JSONObject()
.put("epoch", epoch)
.put("view", view.number())
.put("version", accumulatorState.getStateVersion())
.put("accumulator", Bytes.toHexString(accumulatorState.getAccumulatorHash().asBytes()))
.put("timestamp", timestamp);

if (nextValidators != null) {
var validators = new JSONArray();
for (var v : nextValidators) {
var validatorAddress = ValidatorAddress.of(v.getNode().getKey());
validators.put(new JSONObject()
.put("address", validatorAddress)
.put("stake", v.getPower())
);
}
json.put("nextValidators", validators);
}

return json;
}


public static LedgerHeader mocked() {
return new LedgerHeader(0, View.genesis(), new AccumulatorState(0, HashUtils.zero256()), 0, null);
Expand Down
Loading