use of com.radixdlt.ledger.AccumulatorState in project radixdlt by radixdlt.
the class LocalSyncServiceTest method createHeaderAtStateVersion.
private LedgerProof createHeaderAtStateVersion(long version) {
final LedgerProof header = mock(LedgerProof.class);
final AccumulatorState accumulatorState = mock(AccumulatorState.class);
when(header.getAccumulatorState()).thenReturn(accumulatorState);
when(accumulatorState.getStateVersion()).thenReturn(version);
return header;
}
use of com.radixdlt.ledger.AccumulatorState in project radixdlt by radixdlt.
the class TransactionsHandler method handleRequest.
@Override
public CommittedTransactionsResponse handleRequest(CommittedTransactionsRequest request) throws CoreApiException {
coreModelMapper.verifyNetwork(request.getNetworkIdentifier());
var stateIdentifier = coreModelMapper.partialStateIdentifier(request.getStateIdentifier());
long stateVersion = stateIdentifier.getFirst();
var accumulator = stateIdentifier.getSecond();
var currentAccumulator = txnStore.getAccumulator(stateVersion).orElseThrow(() -> CoreApiException.notFound(coreModelMapper.notFoundErrorDetails(request.getStateIdentifier())));
if (accumulator != null) {
var matchesInput = accumulator.equals(currentAccumulator);
if (!matchesInput) {
throw CoreApiException.notFound(coreModelMapper.notFoundErrorDetails(request.getStateIdentifier()));
}
}
var limit = coreModelMapper.limit(request.getLimit());
var recoverable = txnStore.get(stateVersion, limit);
var accumulatorState = new AccumulatorState(stateVersion, currentAccumulator);
var response = new CommittedTransactionsResponse();
var txns = ledgerEntryStore.getCommittedTxns(stateVersion, recoverable.size());
for (int i = 0; i < txns.size(); i++) {
var txn = txns.get(i);
var recoveryInfo = recoverable.get(i);
var nextAccumulatorState = ledgerAccumulator.accumulate(accumulatorState, txn.getId().asHashCode());
accumulatorState = nextAccumulatorState;
response.addTransactionsItem(construct(txn, recoveryInfo, nextAccumulatorState));
}
return response.stateIdentifier(new StateIdentifier().stateVersion(stateVersion).transactionAccumulator(Bytes.toHexString(currentAccumulator.asBytes())));
}
use of com.radixdlt.ledger.AccumulatorState in project radixdlt by radixdlt.
the class TransactionsHandler method construct.
private CommittedTransaction construct(Txn txn, RecoverableProcessedTxn recoveryInfo, AccumulatorState accumulatorState) {
var parser = radixEngineProvider.get().getParser();
ParsedTxn parsedTxn;
try {
parsedTxn = parser.parse(txn);
} catch (TxnParseException e) {
throw new IllegalStateException("Could not parse already committed transaction", e);
}
var committedTransaction = new CommittedTransaction();
recoveryInfo.recoverStateUpdates(parsedTxn).stream().map(stateUpdateGroup -> {
var operationGroup = new OperationGroup();
stateUpdateGroup.stream().map(stateUpdate -> {
var substateOperation = stateUpdate.recover(radixEngineProvider);
return coreModelMapper.operation(substateOperation.getSubstate(), substateOperation.getSubstateId(), substateOperation.isBootUp(), this::symbol);
}).forEach(operationGroup::addOperationsItem);
return operationGroup;
}).forEach(committedTransaction::addOperationGroupsItem);
var signedBy = parsedTxn.getPayloadHashAndSig().map(hashAndSig -> {
var hash = hashAndSig.getFirst();
var sig = hashAndSig.getSecond();
return ECPublicKey.recoverFrom(hash, sig).orElseThrow(() -> new IllegalStateException("Invalid signature on already committed transaction"));
});
var transactionIdentifier = coreModelMapper.transactionIdentifier(txn.getId());
return committedTransaction.committedStateIdentifier(coreModelMapper.stateIdentifier(accumulatorState)).metadata(new CommittedTransactionMetadata().fee(coreModelMapper.nativeTokenAmount(parsedTxn.getFeePaid())).message(parsedTxn.getMsg().map(Bytes::toHexString).orElse(null)).size(txn.getPayload().length).hex(Bytes.toHexString(txn.getPayload())).signedBy(signedBy.map(coreModelMapper::publicKey).orElse(null))).transactionIdentifier(transactionIdentifier);
}
use of com.radixdlt.ledger.AccumulatorState in project radixdlt by radixdlt.
the class LargeEpochChangeTest method large_epoch.
@Test
public void large_epoch() throws Exception {
var rt = Runtime.getRuntime();
logger.info("max mem: {}MB", rt.maxMemory() / 1024 / 1024);
int privKeyStart = 2;
int numTxnsPerRound = 10;
createInjector().injectMembers(this);
// Arrange
var request = TxnConstructionRequest.create();
IntStream.range(privKeyStart, NUM_ROUNDS * numTxnsPerRound + privKeyStart).forEach(i -> {
var k = PrivateKeys.ofNumeric(i);
var addr = REAddr.ofPubKeyAccount(k.getPublicKey());
request.action(new MintToken(REAddr.ofNativeToken(), addr, Amount.ofTokens(NUM_ROUNDS * 1000).toSubunits()));
request.action(new RegisterValidator(k.getPublicKey()));
});
var mint = sut.construct(request).buildWithoutSignature();
logger.info("mint_txn_size={}", mint.getPayload().length);
var accumulator = new AccumulatorState(2, HashUtils.zero256());
var proof = new LedgerProof(HashUtils.zero256(), LedgerHeader.create(1, View.of(1), accumulator, 0), new TimestampedECDSASignatures());
sut.execute(List.of(mint), LedgerAndBFTProof.create(proof), PermissionLevel.SYSTEM);
var systemConstruction = Stopwatch.createUnstarted();
var construction = Stopwatch.createUnstarted();
var signatures = Stopwatch.createUnstarted();
var execution = Stopwatch.createUnstarted();
var feesPaid = UInt256.ZERO;
for (int round = 1; round <= NUM_ROUNDS; round++) {
if (round % NUM_ROUNDS == 0) {
logger.info("Staking txn {}/{} sys_construct_time: {}s user_construct_time: {}s sig_time: {}s" + " execute_time: {}s", round * (numTxnsPerRound + 1), NUM_ROUNDS * (numTxnsPerRound + 1), systemConstruction.elapsed(TimeUnit.SECONDS), construction.elapsed(TimeUnit.SECONDS), signatures.elapsed(TimeUnit.SECONDS), execution.elapsed(TimeUnit.SECONDS));
}
var txns = new ArrayList<Txn>();
systemConstruction.start();
var sysTxn = sut.construct(new NextRound(round, false, 1, v -> TEST_KEY.getPublicKey())).buildWithoutSignature();
systemConstruction.stop();
txns.add(sysTxn);
for (int i = 0; i < numTxnsPerRound; i++) {
var privateKey = PrivateKeys.ofNumeric((round - 1) * numTxnsPerRound + i + privKeyStart);
var pubKey = privateKey.getPublicKey();
var addr = REAddr.ofPubKeyAccount(privateKey.getPublicKey());
construction.start();
var builder = sut.construct(TxnConstructionRequest.create().feePayer(addr).action(new StakeTokens(addr, pubKey, Amount.ofTokens(100 + i).toSubunits())));
construction.stop();
signatures.start();
var txn = builder.signAndBuild(privateKey::sign);
signatures.stop();
txns.add(txn);
}
var acc = new AccumulatorState(2 + round * (numTxnsPerRound + 1), HashUtils.zero256());
var proof2 = new LedgerProof(HashUtils.zero256(), LedgerHeader.create(1, View.of(1), acc, 0), new TimestampedECDSASignatures());
execution.start();
var result = sut.execute(txns, LedgerAndBFTProof.create(proof2), PermissionLevel.SUPER_USER);
execution.stop();
for (var p : result.getProcessedTxns()) {
feesPaid = feesPaid.add(p.getFeePaid());
}
}
logger.info("total_fees_paid: {}", Amount.ofSubunits(feesPaid));
// Act
construction.reset();
construction.start();
logger.info("constructing epoch...");
var txn = sut.construct(new NextEpoch(1)).buildWithoutSignature();
construction.stop();
logger.info("epoch_construction: size={}MB time={}s", txn.getPayload().length / 1024 / 1024, construction.elapsed(TimeUnit.SECONDS));
construction.reset();
construction.start();
logger.info("preparing epoch...");
var result = sut.transientBranch().execute(List.of(txn), PermissionLevel.SUPER_USER);
sut.deleteBranches();
var nextValidatorSet = result.getProcessedTxn().getEvents().stream().filter(REEvent.NextValidatorSetEvent.class::isInstance).map(REEvent.NextValidatorSetEvent.class::cast).findFirst().map(e -> BFTValidatorSet.from(e.nextValidators().stream().map(v -> BFTValidator.from(BFTNode.create(v.validatorKey()), v.amount()))));
var stateUpdates = result.getProcessedTxn().stateUpdates().count();
construction.stop();
logger.info("epoch_preparation: state_updates={} verification_time={}s store_time={}s total_time={}s", stateUpdates, result.getVerificationTime() / 1000, result.getStoreTime() / 1000, construction.elapsed(TimeUnit.SECONDS));
construction.reset();
construction.start();
logger.info("executing epoch...");
var acc = new AccumulatorState(2 + 1 + NUM_ROUNDS * (1 + numTxnsPerRound), HashUtils.zero256());
var header = LedgerHeader.create(1, View.of(10), acc, 0, nextValidatorSet.orElseThrow());
var proof2 = new LedgerProof(HashUtils.zero256(), header, new TimestampedECDSASignatures());
var executionResult = this.sut.execute(List.of(txn), LedgerAndBFTProof.create(proof2), PermissionLevel.SUPER_USER);
construction.stop();
logger.info("epoch_execution: verification_time={}s store_time={}s total_time={}s", executionResult.getVerificationTime() / 1000, executionResult.getStoreTime() / 1000, construction.elapsed(TimeUnit.SECONDS));
for (var v : nextValidatorSet.orElseThrow().getValidators()) {
logger.info("validator {} {}", v.getNode(), v.getPower());
}
}
use of com.radixdlt.ledger.AccumulatorState in project radixdlt by radixdlt.
the class ConsensusModuleTest method createNextVertex.
private Pair<QuorumCertificate, VerifiedVertex> createNextVertex(QuorumCertificate parent, BFTNode bftNode, Txn txn) {
var unverifiedVertex = UnverifiedVertex.create(parent, View.of(1), List.of(txn), bftNode);
var hash = hasher.hash(unverifiedVertex);
var verifiedVertex = new VerifiedVertex(unverifiedVertex, hash);
var next = new BFTHeader(View.of(1), verifiedVertex.getId(), LedgerHeader.create(1, View.of(1), new AccumulatorState(1, HashUtils.zero256()), 1));
var voteData = new VoteData(next, parent.getProposed(), parent.getParent());
var unsyncedQC = new QuorumCertificate(voteData, new TimestampedECDSASignatures(Map.of(bftNode, TimestampedECDSASignature.from(1, zeroSignature()))));
return Pair.of(unsyncedQC, verifiedVertex);
}
Aggregations