use of com.radixdlt.engine.parser.exceptions.TxnParseException 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.engine.parser.exceptions.TxnParseException in project radixdlt by radixdlt.
the class KeySignHandler method handleRequest.
@Override
public KeySignResponse handleRequest(KeySignRequest request) throws CoreApiException {
coreModelMapper.verifyNetwork(request.getNetworkIdentifier());
var pubKey = coreModelMapper.ecPublicKey(request.getPublicKey());
if (!self.equals(pubKey)) {
throw CoreApiException.notSupported(new PublicKeyNotSupportedError().unsupportedPublicKey(request.getPublicKey()).type(PublicKeyNotSupportedError.class.getSimpleName()));
}
// Verify this is a valid transaction and not anything more malicious
var bytes = coreModelMapper.bytes(request.getUnsignedTransaction());
var txn = Txn.create(bytes);
try {
radixEngineProvider.get().getParser().parse(txn);
} catch (TxnParseException e) {
throw coreModelMapper.parseException(e);
}
var builder = TxLowLevelBuilder.newBuilder(bytes);
var hash = builder.hashToSign();
var signature = this.hashSigner.sign(hash);
var signedTransaction = builder.sig(signature).blob();
return new KeySignResponse().signedTransaction(Bytes.toHexString(signedTransaction));
}
use of com.radixdlt.engine.parser.exceptions.TxnParseException 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.engine.parser.exceptions.TxnParseException in project radixdlt by radixdlt.
the class REParser method parse.
public ParsedTxn parse(Txn txn) throws TxnParseException {
UInt256 feePaid = null;
ECDSASignature sig = null;
int sigPosition = 0;
var parserState = new ParserState(txn);
var buf = ByteBuffer.wrap(txn.getPayload());
while (buf.hasRemaining()) {
if (sig != null) {
throw new TxnParseException(parserState, "Signature must be last");
}
var curPos = buf.position();
parserState.pos(curPos);
final var inst = readInstruction(parserState, buf);
parserState.nextInstruction(inst);
if (inst.isStateUpdate()) {
parserState.substateUpdate(inst.getMicroOp().getOp());
} else if (inst.getMicroOp().getOp() == REOp.READ || inst.getMicroOp().getOp() == REOp.READINDEX) {
parserState.read();
} else if (inst.getMicroOp() == REInstruction.REMicroOp.HEADER) {
parserState.header(inst.getData());
} else if (inst.getMicroOp() == REInstruction.REMicroOp.SYSCALL) {
try {
var callData = inst.<CallData>getData();
byte id = callData.get(0);
var syscall = Syscall.of(id).orElseThrow(() -> new TxnParseException(parserState, "Invalid call data type: " + id));
switch(syscall) {
case FEE_RESERVE_PUT:
if (feePaid != null) {
throw new TxnParseException(parserState, "Should only pay fees once.");
}
feePaid = callData.getUInt256(1);
break;
case FEE_RESERVE_TAKE:
if (feePaid == null) {
throw new TxnParseException(parserState, "No fees paid");
}
var takeAmount = callData.getUInt256(1);
if (takeAmount.compareTo(feePaid) > 0) {
throw new TxnParseException(parserState, "Trying to take more fees than paid");
}
feePaid = feePaid.subtract(takeAmount);
break;
case READDR_CLAIM:
break;
// TODO: Along with FeeConstraintScrypt.java
default:
throw new TxnParseException(parserState, "Invalid call data type: " + id);
}
} catch (CallDataAccessException | TrailingBytesException e) {
throw new TxnParseException(parserState, e);
}
} else if (inst.getMicroOp() == REInstruction.REMicroOp.MSG) {
parserState.msg(inst.getData());
} else if (inst.getMicroOp() == REInstruction.REMicroOp.END) {
parserState.end();
} else if (inst.getMicroOp() == REInstruction.REMicroOp.SIG) {
sigPosition = curPos;
sig = inst.getData();
} else {
throw new TxnParseException(parserState, "Unknown CM Op " + inst.getMicroOp());
}
}
parserState.finish();
return new ParsedTxn(txn, feePaid, parserState.instructions, parserState.msg, sig == null ? null : Pair.of(calculatePayloadHash(txn, sigPosition), sig), parserState.disableResourceAllocAndDestroy);
}
use of com.radixdlt.engine.parser.exceptions.TxnParseException 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);
}
Aggregations