use of com.radixdlt.constraintmachine.exceptions.ConstraintMachineException in project radixdlt by radixdlt.
the class RadixEngine method executeInternal.
private RadixEngineResult executeInternal(EngineStore.EngineStoreInTransaction<M> engineStoreInTransaction, List<Txn> txns, M meta, PermissionLevel permissionLevel, boolean skipAuthorization) throws RadixEngineException {
var processedTxns = new ArrayList<REProcessedTxn>();
// FIXME: This is quite the hack to increase sigsLeft for execution on noncommits (e.g. mempool)
// FIXME: Should probably just change metering
// Start with 0
var sigsLeft = meta != null ? 0 : 1000;
var storageStopwatch = Stopwatch.createUnstarted();
var verificationStopwatch = Stopwatch.createUnstarted();
for (int i = 0; i < txns.size(); i++) {
var txn = txns.get(i);
verificationStopwatch.start();
var context = new ExecutionContext(txn, permissionLevel, skipAuthorization, sigsLeft);
final REProcessedTxn processedTxn;
try {
processedTxn = this.verify(engineStoreInTransaction, txn, context);
} catch (TxnParseException | AuthorizationException | ConstraintMachineException e) {
throw new RadixEngineException(i, txns.size(), txn, e);
}
verificationStopwatch.stop();
// Carry sigs left to the next transaction
sigsLeft = context.sigsLeft();
storageStopwatch.start();
try {
engineStoreInTransaction.storeTxn(processedTxn);
} catch (Exception e) {
logger.error("Store of atom failed: " + processedTxn, e);
throw e;
}
storageStopwatch.stop();
processedTxns.add(processedTxn);
}
try {
batchVerifier.testMetadata(meta, processedTxns);
} catch (MetadataException e) {
logger.error("Invalid metadata: " + processedTxns);
throw e;
}
if (meta != null) {
engineStoreInTransaction.storeMetadata(meta);
}
return RadixEngineResult.create(processedTxns, verificationStopwatch.elapsed(TimeUnit.MILLISECONDS), storageStopwatch.elapsed(TimeUnit.MILLISECONDS));
}
use of com.radixdlt.constraintmachine.exceptions.ConstraintMachineException in project radixdlt by radixdlt.
the class RadixEngineStateComputerTest method preparing_system_update_from_vertex_should_fail.
@Test
public void preparing_system_update_from_vertex_should_fail() throws TxBuilderException {
// Arrange
var txn = radixEngine.construct(new NextRound(1, false, 0, i -> proposerElection.getProposer(View.of(i)).getKey())).buildWithoutSignature();
var illegalTxn = TxLowLevelBuilder.newBuilder(currentForkView.currentForkConfig().engineRules().serialization()).down(SubstateId.ofSubstate(txn.getId(), 1)).up(new RoundData(2, 0)).end().build();
var v = UnverifiedVertex.create(mock(QuorumCertificate.class), View.of(1), List.of(illegalTxn), proposerElection.getProposer(View.of(1)));
var vertex = new VerifiedVertex(v, mock(HashCode.class));
// Act
var result = sut.prepare(ImmutableList.of(), vertex, 0);
// Assert
assertThat(result.getSuccessfulCommands()).hasSize(1);
assertThat(result.getFailedCommands()).hasValueSatisfying(new Condition<>(e -> {
var ex = (RadixEngineException) e;
var cmException = (ConstraintMachineException) ex.getCause();
return cmException.getCause() instanceof InvalidPermissionException;
}, "Is invalid_execution_permission error"));
}
use of com.radixdlt.constraintmachine.exceptions.ConstraintMachineException in project radixdlt by radixdlt.
the class RadixEngine method executeInternal.
private RadixEngineResult<M> executeInternal(EngineStore.EngineStoreInTransaction<M> engineStoreInTransaction, List<Txn> txns, Optional<M> metaOpt, PermissionLevel permissionLevel, boolean skipAuthorization) throws RadixEngineException {
var processedTxns = new ArrayList<REProcessedTxn>();
// FIXME: This is quite the hack to increase sigsLeft for execution on noncommits (e.g. mempool)
// FIXME: Should probably just change metering
// Start with 0
var sigsLeft = metaOpt.isPresent() ? 0 : 1000;
var storageStopwatch = Stopwatch.createUnstarted();
var verificationStopwatch = Stopwatch.createUnstarted();
for (int i = 0; i < txns.size(); i++) {
var txn = txns.get(i);
verificationStopwatch.start();
var context = new ExecutionContext(txn, permissionLevel, skipAuthorization, sigsLeft);
final REProcessedTxn processedTxn;
try {
processedTxn = this.verify(engineStoreInTransaction, txn, context);
} catch (TxnParseException | AuthorizationException | ConstraintMachineException e) {
throw new RadixEngineException(i, txns.size(), txn, e);
}
verificationStopwatch.stop();
// Carry sigs left to the next transaction
sigsLeft = context.sigsLeft();
storageStopwatch.start();
try {
engineStoreInTransaction.storeTxn(processedTxn);
} catch (Exception e) {
logger.error("Store of atom failed: " + processedTxn, e);
throw e;
}
storageStopwatch.stop();
processedTxns.add(processedTxn);
}
try {
final var resultMetadata = metaOpt.map(meta -> {
final var postProcessedMetadata = postProcessor.process(meta, engineStoreInTransaction, processedTxns);
engineStoreInTransaction.storeMetadata(postProcessedMetadata);
return postProcessedMetadata;
}).orElse(null);
return RadixEngineResult.create(processedTxns, resultMetadata, verificationStopwatch.elapsed(TimeUnit.MILLISECONDS), storageStopwatch.elapsed(TimeUnit.MILLISECONDS));
} catch (PostProcessorException e) {
logger.error("Invalid metadata: " + processedTxns);
throw e;
}
}
use of com.radixdlt.constraintmachine.exceptions.ConstraintMachineException in project radixdlt by radixdlt.
the class ConstraintMachine method statefulVerify.
/**
* Executes transition procedures and witness validators in a particle group and validates that
* the particle group is well formed.
*/
List<List<REStateUpdate>> statefulVerify(ExecutionContext context, CMValidationState validationState, List<REInstruction> instructions) throws ConstraintMachineException {
int instIndex = 0;
var expectEnd = false;
ReducerState reducerState = null;
var readableAddrs = validationState.resources();
var groupedStateUpdates = new ArrayList<List<REStateUpdate>>();
var stateUpdates = new ArrayList<REStateUpdate>();
meter.onStart(context);
for (REInstruction inst : instructions) {
try {
if (expectEnd && inst.getMicroOp() != REInstruction.REMicroOp.END) {
throw new MissingExpectedEndException();
}
if (inst.getMicroOp() == REInstruction.REMicroOp.SYSCALL) {
CallData callData = inst.getData();
var opSignature = OpSignature.ofMethod(inst.getMicroOp().getOp(), REAddr.ofSystem());
var methodProcedure = loadProcedure(reducerState, opSignature);
reducerState = callProcedure(methodProcedure, callData, reducerState, readableAddrs, context);
} else if (inst.getMicroOp().getOp() == REOp.READ) {
final Particle nextParticle;
if (inst.getMicroOp() == REInstruction.REMicroOp.VREAD) {
SubstateId substateId = inst.getData();
nextParticle = validationState.virtualRead(substateId);
} else if (inst.getMicroOp() == REInstruction.REMicroOp.READ) {
SubstateId substateId = inst.getData();
nextParticle = validationState.read(substateId);
} else if (inst.getMicroOp() == REInstruction.REMicroOp.LREAD) {
SubstateId substateId = inst.getData();
nextParticle = validationState.localRead(substateId.getIndex().orElseThrow());
} else if (inst.getMicroOp() == REInstruction.REMicroOp.LVREAD) {
SubstateId substateId = inst.getData();
nextParticle = validationState.localVirtualRead(substateId);
} else {
throw new IllegalStateException("Unknown read op " + inst.getMicroOp());
}
var eventId = OpSignature.ofSubstateUpdate(inst.getMicroOp().getOp(), nextParticle.getClass());
var methodProcedure = loadProcedure(reducerState, eventId);
reducerState = callProcedure(methodProcedure, nextParticle, reducerState, readableAddrs, context);
expectEnd = reducerState == null;
} else if (inst.getMicroOp().getOp() == REOp.DOWNINDEX || inst.getMicroOp().getOp() == REOp.READINDEX) {
byte[] raw = inst.getData();
var index = SubstateIndex.create(raw, validationState.deserialization.byteToClass(raw[0]));
var substateCursor = validationState.getIndexedCursor(index);
var tmp = stateUpdates;
final int tmpInstIndex = instIndex;
var iterator = new Iterator<Particle>() {
@Override
public boolean hasNext() {
return substateCursor.hasNext();
}
@Override
public Particle next() {
// FIXME: this is a hack
// FIXME: do this via shutdownAll state update rather than individually
var substate = substateCursor.next();
if (inst.getMicroOp().getOp() == REOp.DOWNINDEX) {
var typeByte = deserialization.classToByte(substate.getParticle().getClass());
tmp.add(REStateUpdate.of(REOp.DOWN, tmpInstIndex, substate.getId(), typeByte, substate.getParticle(), null));
}
return substate.getParticle();
}
};
var substateIterator = new IndexedSubstateIterator<>(index, iterator);
try {
var eventId = OpSignature.ofSubstateUpdate(inst.getMicroOp().getOp(), index.getSubstateClass());
var methodProcedure = loadProcedure(reducerState, eventId);
reducerState = callProcedure(methodProcedure, substateIterator, reducerState, readableAddrs, context);
} finally {
substateCursor.close();
}
} else if (inst.isStateUpdate()) {
final SubstateId substateId;
final Particle nextParticle;
final Supplier<ByteBuffer> substateBuffer;
if (inst.getMicroOp() == REInstruction.REMicroOp.UP) {
// TODO: Cleanup indexing of substate class
UpSubstate upSubstate = inst.getData();
var buf = upSubstate.getSubstateBuffer();
nextParticle = validationState.deserialization.deserialize(buf);
if (buf.hasRemaining()) {
throw new TrailingBytesException("Substate has trailing bytes.");
}
substateId = upSubstate.getSubstateId();
substateBuffer = upSubstate::getSubstateBuffer;
validationState.bootUp(Substate.create(nextParticle, substateId), upSubstate::getSubstateBuffer);
} else if (inst.getMicroOp() == REInstruction.REMicroOp.VDOWN) {
substateId = inst.getData();
substateBuffer = null;
nextParticle = validationState.virtualShutdown(substateId);
} else if (inst.getMicroOp() == REInstruction.REMicroOp.DOWN) {
substateId = inst.getData();
substateBuffer = null;
nextParticle = validationState.shutdown(substateId);
} else if (inst.getMicroOp() == REInstruction.REMicroOp.LDOWN) {
substateId = inst.getData();
substateBuffer = null;
nextParticle = validationState.localShutdown(substateId.getIndex().orElseThrow());
} else if (inst.getMicroOp() == REInstruction.REMicroOp.LVDOWN) {
substateId = inst.getData();
substateBuffer = null;
nextParticle = validationState.localVirtualShutdown(substateId);
} else {
throw new IllegalStateException("Unhandled op: " + inst.getMicroOp());
}
var op = inst.getMicroOp().getOp();
var typeByte = deserialization.classToByte(nextParticle.getClass());
stateUpdates.add(REStateUpdate.of(op, instIndex, substateId, typeByte, nextParticle, substateBuffer));
var eventId = OpSignature.ofSubstateUpdate(op, nextParticle.getClass());
var methodProcedure = loadProcedure(reducerState, eventId);
reducerState = callProcedure(methodProcedure, nextParticle, reducerState, readableAddrs, context);
expectEnd = reducerState == null;
} else if (inst.getMicroOp() == REInstruction.REMicroOp.END) {
groupedStateUpdates.add(stateUpdates);
stateUpdates = new ArrayList<>();
if (reducerState != null) {
var eventId = OpSignature.ofSubstateUpdate(inst.getMicroOp().getOp(), null);
var methodProcedure = loadProcedure(reducerState, eventId);
reducerState = callProcedure(methodProcedure, reducerState, reducerState, readableAddrs, context);
}
expectEnd = false;
} else if (inst.getMicroOp() == REInstruction.REMicroOp.SIG) {
if (context.permissionLevel() != PermissionLevel.SYSTEM) {
meter.onSigInstruction(context);
}
} else {
// Collect no-ops here
if (inst.getMicroOp() != REInstruction.REMicroOp.MSG && inst.getMicroOp() != REInstruction.REMicroOp.HEADER) {
throw new ProcedureException("Unknown op " + inst.getMicroOp());
}
}
} catch (Exception e) {
throw new ConstraintMachineException(instIndex, instructions, reducerState, e);
}
instIndex++;
}
try {
context.destroy();
} catch (Exception e) {
throw new ConstraintMachineException(instIndex, instructions, reducerState, e);
}
return groupedStateUpdates;
}
Aggregations