use of com.radixdlt.constraintmachine.exceptions.ProcedureException in project radixdlt by radixdlt.
the class EpochUpdateConstraintScrypt method epochUpdate.
private void epochUpdate(Loader os) {
// Epoch Update
os.procedure(new DownProcedure<>(EndPrevRound.class, EpochData.class, d -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (d, s, r, c) -> {
// TODO: Should move this authorization instead of checking epoch > 0
if (d.epoch() > 0 && s.getClosedRound().view() != maxRounds) {
throw new ProcedureException("Must execute epoch update on end of round " + maxRounds + " but is " + s.getClosedRound().view());
}
return ReducerResult.incomplete(new UpdatingEpoch(d));
}));
os.procedure(new ShutdownAllProcedure<>(ExitingStake.class, UpdatingEpoch.class, () -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, d, c, r) -> {
var exittingStake = new ProcessExittingStake(s);
return ReducerResult.incomplete(exittingStake.process(d));
}));
os.procedure(new UpProcedure<>(ProcessExittingStake.class, TokensInAccount.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.unlock(u))));
os.procedure(new ShutdownAllProcedure<>(ValidatorBFTData.class, RewardingValidators.class, () -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, d, c, r) -> ReducerResult.incomplete(s.process(d, c))));
os.procedure(new ShutdownAllProcedure<>(PreparedUnstakeOwnership.class, PreparingUnstake.class, () -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, d, c, r) -> ReducerResult.incomplete(s.unstakes(d))));
os.procedure(new DownProcedure<>(LoadingStake.class, ValidatorStakeData.class, d -> d.bucket().withdrawAuthorization(), (d, s, r, c) -> ReducerResult.incomplete(s.startUpdate(d))));
os.procedure(new UpProcedure<>(Unstaking.class, ExitingStake.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.exit(u))));
os.procedure(new ShutdownAllProcedure<>(PreparedStake.class, PreparingStake.class, () -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, d, c, r) -> ReducerResult.incomplete(s.prepareStakes(d))));
os.procedure(new ShutdownAllProcedure<>(ValidatorFeeCopy.class, PreparingRakeUpdate.class, () -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, d, c, r) -> ReducerResult.incomplete(s.prepareRakeUpdates(d))));
os.procedure(new UpProcedure<>(ResetRakeUpdate.class, ValidatorFeeCopy.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.reset(u))));
os.procedure(new ShutdownAllProcedure<>(ValidatorOwnerCopy.class, PreparingOwnerUpdate.class, () -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, d, c, r) -> ReducerResult.incomplete(s.prepareValidatorUpdate(d))));
os.procedure(new UpProcedure<>(ResetOwnerUpdate.class, ValidatorOwnerCopy.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.reset(u))));
os.procedure(new ShutdownAllProcedure<>(ValidatorRegisteredCopy.class, PreparingRegisteredUpdate.class, () -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, d, c, r) -> ReducerResult.incomplete(s.prepareRegisterUpdates(d))));
os.procedure(new UpProcedure<>(ResetRegisteredUpdate.class, ValidatorRegisteredCopy.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.reset(u))));
os.procedure(new UpProcedure<>(Staking.class, StakeOwnership.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.stake(u))));
os.procedure(new UpProcedure<>(UpdatingValidatorStakes.class, ValidatorStakeData.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.updateStake(u))));
os.procedure(new ReadIndexProcedure<>(CreatingNextValidatorSet.class, ValidatorStakeData.class, () -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, d, c, r) -> ReducerResult.incomplete(s.readIndex(d, c))));
os.procedure(new UpProcedure<>(BootupValidator.class, ValidatorBFTData.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.bootUp(u))));
os.procedure(new UpProcedure<>(StartingNextEpoch.class, EpochData.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> ReducerResult.incomplete(s.nextEpoch(u))));
os.procedure(new UpProcedure<>(StartingEpochRound.class, RoundData.class, u -> new Authorization(PermissionLevel.SUPER_USER, (r, c) -> {
}), (s, u, c, r) -> {
if (u.view() != 0) {
throw new ProcedureException("Epoch must start with view 0");
}
return ReducerResult.complete();
}));
}
use of com.radixdlt.constraintmachine.exceptions.ProcedureException in project radixdlt by radixdlt.
the class TokensConstraintScryptV3 method defineTokenCreation.
private void defineTokenCreation(Loader os) {
os.procedure(new UpProcedure<>(SystemConstraintScrypt.REAddrClaim.class, TokenResource.class, u -> new Authorization(PermissionLevel.USER, (r, c) -> {
}), (s, u, c, r) -> {
if (!u.addr().equals(s.getAddr())) {
throw new ProcedureException("Addresses don't match");
}
var str = new String(s.getArg());
if (reservedSymbols.contains(str) && c.permissionLevel() != PermissionLevel.SYSTEM) {
throw new ReservedSymbolException(str);
}
if (!tokenSymbolPattern.matcher(str).matches()) {
throw new ProcedureException("invalid token symbol: " + str);
}
if (u.isMutable()) {
return ReducerResult.incomplete(new NeedMetadata(s.getArg(), u));
}
if (!u.granularity().equals(UInt256.ONE)) {
throw new ProcedureException("Granularity must be one.");
}
return ReducerResult.incomplete(new NeedFixedTokenSupply(s.getArg(), u));
}));
os.procedure(new UpProcedure<>(NeedFixedTokenSupply.class, TokensInAccount.class, u -> new Authorization(PermissionLevel.USER, (r, c) -> {
}), (s, u, c, r) -> {
if (!u.resourceAddr().equals(s.tokenResource.addr())) {
throw new ProcedureException("Addresses don't match.");
}
return ReducerResult.incomplete(new NeedMetadata(s.arg, s.tokenResource));
}));
os.procedure(new UpProcedure<>(NeedMetadata.class, TokenResourceMetadata.class, u -> new Authorization(PermissionLevel.USER, (r, c) -> {
}), (s, u, c, r) -> {
s.metadata(u, c);
return ReducerResult.complete();
}));
}
use of com.radixdlt.constraintmachine.exceptions.ProcedureException 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;
}
use of com.radixdlt.constraintmachine.exceptions.ProcedureException in project radixdlt by radixdlt.
the class SystemConstraintScrypt method main.
@Override
public void main(Loader os) {
os.substate(VirtualParent.SUBSTATE_DEFINITION);
// TODO: Down singleton
os.procedure(new UpProcedure<>(VoidReducerState.class, VirtualParent.class, u -> new Authorization(PermissionLevel.SYSTEM, (r, c) -> {
}), (s, u, c, r) -> {
if (u.data().length != 1) {
throw new ProcedureException("Invalid data: " + Bytes.toHexString(u.data()));
}
if (u.data()[0] != SubstateTypeId.UNCLAIMED_READDR.id()) {
throw new ProcedureException("Invalid data: " + Bytes.toHexString(u.data()));
}
return ReducerResult.complete();
}));
os.substate(EpochData.SUBSTATE_DEFINITION);
os.substate(RoundData.SUBSTATE_DEFINITION);
os.procedure(new SystemCallProcedure<>(TokenHoldingBucket.class, REAddr.ofSystem(), () -> new Authorization(PermissionLevel.USER, (r, c) -> {
}), (s, d, c) -> {
var id = d.get(0);
var syscall = Syscall.of(id).orElseThrow(() -> new ProcedureException("Invalid call type " + id));
if (syscall != Syscall.FEE_RESERVE_PUT) {
throw new ProcedureException("Invalid call type: " + syscall);
}
var amt = d.getUInt256(1);
var tokens = s.withdraw(REAddr.ofNativeToken(), amt);
c.depositFeeReserve(tokens);
return ReducerResult.incomplete(s);
}));
os.procedure(new SystemCallProcedure<>(VoidReducerState.class, REAddr.ofSystem(), () -> new Authorization(PermissionLevel.USER, (r, c) -> {
}), (s, d, c) -> {
var id = d.get(0);
var syscall = Syscall.of(id).orElseThrow(() -> new ProcedureException("Invalid call type " + id));
if (syscall == Syscall.FEE_RESERVE_TAKE) {
var amt = d.getUInt256(1);
var tokens = c.withdrawFeeReserve(amt);
return ReducerResult.incomplete(new TokenHoldingBucket(tokens));
} else if (syscall == Syscall.READDR_CLAIM) {
var bytes = d.getRemainingBytes(1);
if (bytes.length > MAX_SYMBOL_LENGTH) {
throw new ProcedureException("Address claim too large.");
}
return ReducerResult.incomplete(new REAddrClaimStart(bytes));
} else {
throw new ProcedureException("Invalid call type: " + syscall);
}
}));
// PUB_KEY type is already claimed by accounts
os.substate(UnclaimedREAddr.SUBSTATE_DEFINITION);
os.procedure(new DownProcedure<>(REAddrClaimStart.class, UnclaimedREAddr.class, d -> {
final PermissionLevel permissionLevel;
if (d.addr().isNativeToken() || d.addr().isSystem()) {
permissionLevel = PermissionLevel.SYSTEM;
} else {
permissionLevel = PermissionLevel.USER;
}
return new Authorization(permissionLevel, (r, ctx) -> {
});
}, (d, s, r, c) -> ReducerResult.incomplete(s.claim(d, c))));
// For Mainnet Genesis
os.procedure(new UpProcedure<>(SystemConstraintScrypt.REAddrClaim.class, EpochData.class, u -> new Authorization(PermissionLevel.SYSTEM, (r, c) -> {
}), (s, u, c, r) -> {
if (u.epoch() != 0) {
throw new ProcedureException("First epoch must be 0.");
}
return ReducerResult.incomplete(new AllocatingSystem());
}));
os.procedure(new UpProcedure<>(AllocatingSystem.class, RoundData.class, u -> new Authorization(PermissionLevel.SYSTEM, (r, c) -> {
}), (s, u, c, r) -> {
if (u.view() != 0) {
throw new ProcedureException("First view must be 0.");
}
return ReducerResult.incomplete(new AllocatingVirtualState());
}));
os.procedure(new UpProcedure<>(AllocatingVirtualState.class, VirtualParent.class, u -> new Authorization(PermissionLevel.SYSTEM, (r, c) -> {
}), (s, u, c, r) -> {
var next = s.createVirtualSubstate(u);
return next == null ? ReducerResult.complete() : ReducerResult.incomplete(next);
}));
}
use of com.radixdlt.constraintmachine.exceptions.ProcedureException in project radixdlt by radixdlt.
the class ConstraintMachine method callProcedure.
/**
* Executes a transition procedure given the next spun particle and a current validation state.
*/
private ReducerState callProcedure(Procedure procedure, Object procedureParam, ReducerState reducerState, Resources immutableAddrs, ExecutionContext context) throws SignedSystemException, InvalidPermissionException, AuthorizationException, MeterException, ProcedureException {
// System permissions don't require additional authorization
var authorization = procedure.authorization(procedureParam);
var requiredLevel = authorization.permissionLevel();
context.verifyPermissionLevel(requiredLevel);
if (context.permissionLevel() != PermissionLevel.SYSTEM) {
try {
if (requiredLevel == PermissionLevel.USER) {
this.meter.onUserProcedure(procedure.key(), procedureParam, context);
} else if (requiredLevel == PermissionLevel.SUPER_USER) {
this.meter.onSuperUserProcedure(procedure.key(), procedureParam, context);
}
} catch (Exception e) {
throw new MeterException(e);
}
if (!context.skipAuthorization()) {
try {
authorization.authorizer().verify(immutableAddrs, context);
} catch (Exception e) {
throw new AuthorizationException(e);
}
}
}
return procedure.call(procedureParam, reducerState, immutableAddrs, context).state();
}
Aggregations