src/signTx.c
static inline void advanceStage()
{
	TRACE("Advancing sign tx stage from: %d", ctx->stage);

	switch (ctx->stage) {

	case SIGN_STAGE_INIT:
		ctx->stage = SIGN_STAGE_AUX_DATA;
		initTxAuxDataCtx();

		if (ctx->includeAuxData) {
			// wait for aux data APDU(s)
			AUX_DATA_CTX->auxDataReceived = false;
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_AUX_DATA:
		if (ctx->includeAuxData) {
			ASSERT(AUX_DATA_CTX->auxDataReceived);
		}

		ctx->stage = SIGN_STAGE_BODY_INPUTS;
		initTxBodyCtx();

		{
			// Note: make sure that everything in ctx is initialized properly
			txHashBuilder_init(
			        &BODY_CTX->txHashBuilder,
			        ctx->numInputs,
			        ctx->numOutputs,
			        ctx->includeTtl,
			        ctx->numCertificates,
			        ctx->numWithdrawals,
			        ctx->includeAuxData,
			        ctx->includeValidityIntervalStart,
			        ctx->includeMint,
			        ctx->includeScriptDataHash,
			        ctx->numCollaterals,
			        ctx->numRequiredSigners,
			        ctx->includeNetworkId
			);
			txHashBuilder_enterInputs(&BODY_CTX->txHashBuilder);
		}
		break;

	case SIGN_STAGE_BODY_INPUTS:
		// we should have received all inputs
		ASSERT(BODY_CTX->currentInput == ctx->numInputs);
		txHashBuilder_enterOutputs(&BODY_CTX->txHashBuilder);
		signTxOutput_init();
		ctx->stage = SIGN_STAGE_BODY_OUTPUTS;

		if (ctx->numOutputs > 0) {
			// wait for output APDUs
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_OUTPUTS:
		// we should have received all outputs
		ASSERT(BODY_CTX->currentOutput == ctx->numOutputs);
		ctx->stage = SIGN_STAGE_BODY_FEE;
		break;

	case SIGN_STAGE_BODY_FEE:
		ASSERT(BODY_CTX->feeReceived);

		ctx->stage = SIGN_STAGE_BODY_TTL;

		if (ctx->includeTtl) {
			// wait for TTL APDU
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_TTL:
		if (ctx->includeTtl) {
			ASSERT(BODY_CTX->ttlReceived);
		}

		ctx->stage = SIGN_STAGE_BODY_CERTIFICATES;

		if (ctx->numCertificates > 0) {
			txHashBuilder_enterCertificates(&BODY_CTX->txHashBuilder);
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_CERTIFICATES:
		// we should have received all certificates
		ASSERT(BODY_CTX->currentCertificate == ctx->numCertificates);

		ctx->stage = SIGN_STAGE_BODY_WITHDRAWALS;

		if (ctx->numWithdrawals > 0) {
			txHashBuilder_enterWithdrawals(&BODY_CTX->txHashBuilder);
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_WITHDRAWALS:
		// we should have received all withdrawals
		ASSERT(BODY_CTX->currentWithdrawal == ctx->numWithdrawals);

		if (ctx->includeAuxData) {
			// add auxiliary data to tx
			TRACE("Adding auxiliary data hash to tx hash");
			txHashBuilder_addAuxData(
			        &BODY_CTX->txHashBuilder,
			        ctx->auxDataHash, SIZEOF(ctx->auxDataHash)
			);
		}

		ctx->stage = SIGN_STAGE_BODY_VALIDITY_INTERVAL;
		if (ctx->includeValidityIntervalStart) {
			// wait for Validity interval start APDU
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_VALIDITY_INTERVAL:
		if (ctx->includeValidityIntervalStart) {
			ASSERT(BODY_CTX->validityIntervalStartReceived);
		}
		ctx->stage = SIGN_STAGE_BODY_MINT;
		if (ctx->includeMint) {
			txHashBuilder_enterMint(&BODY_CTX->txHashBuilder);
			signTxMint_init();
			// wait for mint APDU
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_MINT:
		if (ctx->includeMint) {
			ASSERT(BODY_CTX->mintReceived);
		}
		ctx->stage = SIGN_STAGE_BODY_SCRIPT_DATA_HASH;
		if (ctx->includeScriptDataHash) {
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_SCRIPT_DATA_HASH:
		if (ctx->includeScriptDataHash) {
			ASSERT(BODY_CTX->scriptDataHashReceived);
		}
		ctx->stage = SIGN_STAGE_BODY_COLLATERALS;
		if (ctx->numCollaterals > 0) {
			txHashBuilder_enterCollaterals(&BODY_CTX->txHashBuilder);
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_COLLATERALS:
		ASSERT(BODY_CTX->currentCollateral == ctx->numCollaterals);
		ctx->stage = SIGN_STAGE_BODY_REQUIRED_SIGNERS;
		if (ctx->numRequiredSigners > 0) {
			txHashBuilder_enterRequiredSigners(&BODY_CTX->txHashBuilder);
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_BODY_REQUIRED_SIGNERS:
		ASSERT(BODY_CTX->currentRequiredSigner == ctx->numRequiredSigners);
		if (ctx->includeNetworkId) {
			// we are not waiting for any APDU here, network id is already known from the init APDU
			txHashBuilder_addNetworkId(&BODY_CTX->txHashBuilder, ctx->commonTxData.networkId);
		}
		ctx->stage = SIGN_STAGE_CONFIRM;
		break;

	case SIGN_STAGE_CONFIRM:
		ctx->stage = SIGN_STAGE_WITNESSES;
		initTxWitnessCtx();

		if (ctx->numWitnesses > 0) {
			break;
		}

	// intentional fallthrough

	case SIGN_STAGE_WITNESSES:
		ctx->stage = SIGN_STAGE_NONE;
		ui_idle(); // we are done with this tx
		break;

	case SIGN_STAGE_NONE:
		// advanceStage() not supposed to be called after tx processing is finished
		ASSERT(false);

	default:
		ASSERT(false);
	}

	TRACE("Advancing sign tx stage to: %d", ctx->stage);
}
// advances the stage of the main state machine
advances the stage of the main state machine
advances the stage of the main state machine
static inline void advanceStage()
{
	TRACE("Advancing sign tx stage from: %d", ctx->stage);
	switch (ctx->stage) {
	case SIGN_STAGE_INIT:
		ctx->stage = SIGN_STAGE_AUX_DATA;
		initTxAuxDataCtx();
		if (ctx->includeAuxData) {
			AUX_DATA_CTX->auxDataReceived = false;
			break;
		}
	case SIGN_STAGE_AUX_DATA:
		if (ctx->includeAuxData) {
			ASSERT(AUX_DATA_CTX->auxDataReceived);
		}
		ctx->stage = SIGN_STAGE_BODY_INPUTS;
		initTxBodyCtx();
		{
			txHashBuilder_init(
			        &BODY_CTX->txHashBuilder,
			        ctx->numInputs,
			        ctx->numOutputs,
			        ctx->includeTtl,
			        ctx->numCertificates,
			        ctx->numWithdrawals,
			        ctx->includeAuxData,
			        ctx->includeValidityIntervalStart,
			        ctx->includeMint,
			        ctx->includeScriptDataHash,
			        ctx->numCollaterals,
			        ctx->numRequiredSigners,
			        ctx->includeNetworkId
			);
			txHashBuilder_enterInputs(&BODY_CTX->txHashBuilder);
		}
		break;
	case SIGN_STAGE_BODY_INPUTS:
		ASSERT(BODY_CTX->currentInput == ctx->numInputs);
		txHashBuilder_enterOutputs(&BODY_CTX->txHashBuilder);
		signTxOutput_init();
		ctx->stage = SIGN_STAGE_BODY_OUTPUTS;
		if (ctx->numOutputs > 0) {
			break;
		}
	case SIGN_STAGE_BODY_OUTPUTS:
		ASSERT(BODY_CTX->currentOutput == ctx->numOutputs);
		ctx->stage = SIGN_STAGE_BODY_FEE;
		break;
	case SIGN_STAGE_BODY_FEE:
		ASSERT(BODY_CTX->feeReceived);
		ctx->stage = SIGN_STAGE_BODY_TTL;
		if (ctx->includeTtl) {
			break;
		}
	case SIGN_STAGE_BODY_TTL:
		if (ctx->includeTtl) {
			ASSERT(BODY_CTX->ttlReceived);
		}
		ctx->stage = SIGN_STAGE_BODY_CERTIFICATES;
		if (ctx->numCertificates > 0) {
			txHashBuilder_enterCertificates(&BODY_CTX->txHashBuilder);
			break;
		}
	case SIGN_STAGE_BODY_CERTIFICATES:
		ASSERT(BODY_CTX->currentCertificate == ctx->numCertificates);
		ctx->stage = SIGN_STAGE_BODY_WITHDRAWALS;
		if (ctx->numWithdrawals > 0) {
			txHashBuilder_enterWithdrawals(&BODY_CTX->txHashBuilder);
			break;
		}
	case SIGN_STAGE_BODY_WITHDRAWALS:
		ASSERT(BODY_CTX->currentWithdrawal == ctx->numWithdrawals);
		if (ctx->includeAuxData) {
			TRACE("Adding auxiliary data hash to tx hash");
			txHashBuilder_addAuxData(
			        &BODY_CTX->txHashBuilder,
			        ctx->auxDataHash, SIZEOF(ctx->auxDataHash)
			);
		}
		ctx->stage = SIGN_STAGE_BODY_VALIDITY_INTERVAL;
		if (ctx->includeValidityIntervalStart) {
			break;
		}
	case SIGN_STAGE_BODY_VALIDITY_INTERVAL:
		if (ctx->includeValidityIntervalStart) {
			ASSERT(BODY_CTX->validityIntervalStartReceived);
		}
		ctx->stage = SIGN_STAGE_BODY_MINT;
		if (ctx->includeMint) {
			txHashBuilder_enterMint(&BODY_CTX->txHashBuilder);
			signTxMint_init();
			break;
		}
	case SIGN_STAGE_BODY_MINT:
		if (ctx->includeMint) {
			ASSERT(BODY_CTX->mintReceived);
		}
		ctx->stage = SIGN_STAGE_BODY_SCRIPT_DATA_HASH;
		if (ctx->includeScriptDataHash) {
			break;
		}
	case SIGN_STAGE_BODY_SCRIPT_DATA_HASH:
		if (ctx->includeScriptDataHash) {
			ASSERT(BODY_CTX->scriptDataHashReceived);
		}
		ctx->stage = SIGN_STAGE_BODY_COLLATERALS;
		if (ctx->numCollaterals > 0) {
			txHashBuilder_enterCollaterals(&BODY_CTX->txHashBuilder);
			break;
		}
	case SIGN_STAGE_BODY_COLLATERALS:
		ASSERT(BODY_CTX->currentCollateral == ctx->numCollaterals);
		ctx->stage = SIGN_STAGE_BODY_REQUIRED_SIGNERS;
		if (ctx->numRequiredSigners > 0) {
			txHashBuilder_enterRequiredSigners(&BODY_CTX->txHashBuilder);
			break;
		}
	case SIGN_STAGE_BODY_REQUIRED_SIGNERS:
		ASSERT(BODY_CTX->currentRequiredSigner == ctx->numRequiredSigners);
		if (ctx->includeNetworkId) {
			txHashBuilder_addNetworkId(&BODY_CTX->txHashBuilder, ctx->commonTxData.networkId);
		}
		ctx->stage = SIGN_STAGE_CONFIRM;
		break;
	case SIGN_STAGE_CONFIRM:
		ctx->stage = SIGN_STAGE_WITNESSES;
		initTxWitnessCtx();
		if (ctx->numWitnesses > 0) {
			break;
		}
	case SIGN_STAGE_WITNESSES:
		ctx->stage = SIGN_STAGE_NONE;
		ui_idle(); 
		break;
	case SIGN_STAGE_NONE:
		ASSERT(false);
	default:
		ASSERT(false);
	}
	TRACE("Advancing sign tx stage to: %d", ctx->stage);
}
static inline void advanceStage ( ) { TRACE ( " " , ctx -> stage ) ; switch ( ctx -> stage ) { case SIGN_STAGE_INIT : ctx -> stage = SIGN_STAGE_AUX_DATA ; initTxAuxDataCtx ( ) ; if ( ctx -> includeAuxData ) { AUX_DATA_CTX -> auxDataReceived = false ; break ; } case SIGN_STAGE_AUX_DATA : if ( ctx -> includeAuxData ) { ASSERT ( AUX_DATA_CTX -> auxDataReceived ) ; } ctx -> stage = SIGN_STAGE_BODY_INPUTS ; initTxBodyCtx ( ) ; { txHashBuilder_init ( & BODY_CTX -> txHashBuilder , ctx -> numInputs , ctx -> numOutputs , ctx -> includeTtl , ctx -> numCertificates , ctx -> numWithdrawals , ctx -> includeAuxData , ctx -> includeValidityIntervalStart , ctx -> includeMint , ctx -> includeScriptDataHash , ctx -> numCollaterals , ctx -> numRequiredSigners , ctx -> includeNetworkId ) ; txHashBuilder_enterInputs ( & BODY_CTX -> txHashBuilder ) ; } break ; case SIGN_STAGE_BODY_INPUTS : ASSERT ( BODY_CTX -> currentInput == ctx -> numInputs ) ; txHashBuilder_enterOutputs ( & BODY_CTX -> txHashBuilder ) ; signTxOutput_init ( ) ; ctx -> stage = SIGN_STAGE_BODY_OUTPUTS ; if ( ctx -> numOutputs > 0 ) { break ; } case SIGN_STAGE_BODY_OUTPUTS : ASSERT ( BODY_CTX -> currentOutput == ctx -> numOutputs ) ; ctx -> stage = SIGN_STAGE_BODY_FEE ; break ; case SIGN_STAGE_BODY_FEE : ASSERT ( BODY_CTX -> feeReceived ) ; ctx -> stage = SIGN_STAGE_BODY_TTL ; if ( ctx -> includeTtl ) { break ; } case SIGN_STAGE_BODY_TTL : if ( ctx -> includeTtl ) { ASSERT ( BODY_CTX -> ttlReceived ) ; } ctx -> stage = SIGN_STAGE_BODY_CERTIFICATES ; if ( ctx -> numCertificates > 0 ) { txHashBuilder_enterCertificates ( & BODY_CTX -> txHashBuilder ) ; break ; } case SIGN_STAGE_BODY_CERTIFICATES : ASSERT ( BODY_CTX -> currentCertificate == ctx -> numCertificates ) ; ctx -> stage = SIGN_STAGE_BODY_WITHDRAWALS ; if ( ctx -> numWithdrawals > 0 ) { txHashBuilder_enterWithdrawals ( & BODY_CTX -> txHashBuilder ) ; break ; } case SIGN_STAGE_BODY_WITHDRAWALS : ASSERT ( BODY_CTX -> currentWithdrawal == ctx -> numWithdrawals ) ; if ( ctx -> includeAuxData ) { TRACE ( " " ) ; txHashBuilder_addAuxData ( & BODY_CTX -> txHashBuilder , ctx -> auxDataHash , SIZEOF ( ctx -> auxDataHash ) ) ; } ctx -> stage = SIGN_STAGE_BODY_VALIDITY_INTERVAL ; if ( ctx -> includeValidityIntervalStart ) { break ; } case SIGN_STAGE_BODY_VALIDITY_INTERVAL : if ( ctx -> includeValidityIntervalStart ) { ASSERT ( BODY_CTX -> validityIntervalStartReceived ) ; } ctx -> stage = SIGN_STAGE_BODY_MINT ; if ( ctx -> includeMint ) { txHashBuilder_enterMint ( & BODY_CTX -> txHashBuilder ) ; signTxMint_init ( ) ; break ; } case SIGN_STAGE_BODY_MINT : if ( ctx -> includeMint ) { ASSERT ( BODY_CTX -> mintReceived ) ; } ctx -> stage = SIGN_STAGE_BODY_SCRIPT_DATA_HASH ; if ( ctx -> includeScriptDataHash ) { break ; } case SIGN_STAGE_BODY_SCRIPT_DATA_HASH : if ( ctx -> includeScriptDataHash ) { ASSERT ( BODY_CTX -> scriptDataHashReceived ) ; } ctx -> stage = SIGN_STAGE_BODY_COLLATERALS ; if ( ctx -> numCollaterals > 0 ) { txHashBuilder_enterCollaterals ( & BODY_CTX -> txHashBuilder ) ; break ; } case SIGN_STAGE_BODY_COLLATERALS : ASSERT ( BODY_CTX -> currentCollateral == ctx -> numCollaterals ) ; ctx -> stage = SIGN_STAGE_BODY_REQUIRED_SIGNERS ; if ( ctx -> numRequiredSigners > 0 ) { txHashBuilder_enterRequiredSigners ( & BODY_CTX -> txHashBuilder ) ; break ; } case SIGN_STAGE_BODY_REQUIRED_SIGNERS : ASSERT ( BODY_CTX -> currentRequiredSigner == ctx -> numRequiredSigners ) ; if ( ctx -> includeNetworkId ) { txHashBuilder_addNetworkId ( & BODY_CTX -> txHashBuilder , ctx -> commonTxData . networkId ) ; } ctx -> stage = SIGN_STAGE_CONFIRM ; break ; case SIGN_STAGE_CONFIRM : ctx -> stage = SIGN_STAGE_WITNESSES ; initTxWitnessCtx ( ) ; if ( ctx -> numWitnesses > 0 ) { break ; } case SIGN_STAGE_WITNESSES : ctx -> stage = SIGN_STAGE_NONE ; ui_idle ( ) ; break ; case SIGN_STAGE_NONE : ASSERT ( false ) ; default : ASSERT ( false ) ; } TRACE ( " " , ctx -> stage ) ; }
advances the stage of the main state machine
advances the stage of the main state machine
// wait for aux data APDU(s) // intentional fallthrough // Note: make sure that everything in ctx is initialized properly // we should have received all inputs // wait for output APDUs // intentional fallthrough // we should have received all outputs // wait for TTL APDU // intentional fallthrough // intentional fallthrough // we should have received all certificates // intentional fallthrough // we should have received all withdrawals // add auxiliary data to tx // wait for Validity interval start APDU // intentional fallthrough // wait for mint APDU // intentional fallthrough // intentional fallthrough // intentional fallthrough // intentional fallthrough // we are not waiting for any APDU here, network id is already known from the init APDU // intentional fallthrough // we are done with this tx // advanceStage() not supposed to be called after tx processing is finished