|
|
|
@ -33,6 +33,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|
|
|
@ActiveProfiles("test")
|
|
|
|
@ActiveProfiles("test")
|
|
|
|
class ExchangeControllerTest {
|
|
|
|
class ExchangeControllerTest {
|
|
|
|
private static final String USER_ID = "00000000-0000-0000-0000-000000000999";
|
|
|
|
private static final String USER_ID = "00000000-0000-0000-0000-000000000999";
|
|
|
|
|
|
|
|
private static final String ISSUANCE_REQUEST_ID = "99999999-9999-9999-9999-999999999999";
|
|
|
|
|
|
|
|
private static final String DEDUCTION_TRANSACTION_ID = "EXCHANGE_TEST_DEDUCTION";
|
|
|
|
|
|
|
|
private static final String PRODUCTION_BATCH_ID = "EXCHANGE_TEST_BATCH";
|
|
|
|
|
|
|
|
private static final long CONTROL_SIGNATURE_ID = 990002L;
|
|
|
|
@Autowired private MockMvc mockMvc;
|
|
|
|
@Autowired private MockMvc mockMvc;
|
|
|
|
@Autowired private JdbcTemplate jdbc;
|
|
|
|
@Autowired private JdbcTemplate jdbc;
|
|
|
|
@Autowired private InstitutionIdentityCryptography cryptography;
|
|
|
|
@Autowired private InstitutionIdentityCryptography cryptography;
|
|
|
|
@ -62,7 +66,7 @@ class ExchangeControllerTest {
|
|
|
|
jdbc.update("DELETE FROM digital_wallet");
|
|
|
|
jdbc.update("DELETE FROM digital_wallet");
|
|
|
|
WalletOpeningTestData.deleteWalletFacts(jdbc, USER_ID);
|
|
|
|
WalletOpeningTestData.deleteWalletFacts(jdbc, USER_ID);
|
|
|
|
jdbc.update("DELETE FROM institution_identifier_application WHERE user_id=?", USER_ID);
|
|
|
|
jdbc.update("DELETE FROM institution_identifier_application WHERE user_id=?", USER_ID);
|
|
|
|
jdbc.update("DELETE FROM commercial_bank_currency WHERE issuance_request_id='EXCHANGE_TEST_ISSUANCE'");
|
|
|
|
deleteIssuanceProofData();
|
|
|
|
jdbc.update("INSERT INTO institution_identifier_application (id,bank_code,user_id,school_id,class_id," +
|
|
|
|
jdbc.update("INSERT INTO institution_identifier_application (id,bank_code,user_id,school_id,class_id," +
|
|
|
|
"request_timestamp,original_text,status,institution_identifier,training_round,scoring_criteria," +
|
|
|
|
"request_timestamp,original_text,status,institution_identifier,training_round,scoring_criteria," +
|
|
|
|
"created_at,updated_at,created_by,updated_by,deleted) VALUES " +
|
|
|
|
"created_at,updated_at,created_by,updated_by,deleted) VALUES " +
|
|
|
|
@ -72,6 +76,10 @@ class ExchangeControllerTest {
|
|
|
|
keyService.commercialBankKey(subject, "test");
|
|
|
|
keyService.commercialBankKey(subject, "test");
|
|
|
|
keyService.centralBankKey(subject, "test");
|
|
|
|
keyService.centralBankKey(subject, "test");
|
|
|
|
String issuanceSignature = keyService.signCentralBank(subject, "ISSUANCE_ORIGINAL");
|
|
|
|
String issuanceSignature = keyService.signCentralBank(subject, "ISSUANCE_ORIGINAL");
|
|
|
|
|
|
|
|
String controlOriginalText = "200.00|ORG_EXCHANGE_TEST|TXN_EXCHANGE_TEST";
|
|
|
|
|
|
|
|
String controlDigest = cryptography.sm3(controlOriginalText);
|
|
|
|
|
|
|
|
String controlSignature = keyService.signCentralBank(subject, controlDigest);
|
|
|
|
|
|
|
|
seedIssuanceProofData(controlOriginalText, controlDigest, controlSignature, issuanceSignature);
|
|
|
|
InstitutionSm2KeyPair walletKey = cryptography.generateSm2KeyPair();
|
|
|
|
InstitutionSm2KeyPair walletKey = cryptography.generateSm2KeyPair();
|
|
|
|
jdbc.update("INSERT INTO simulated_bank_account (account_id,user_id,bank_code,bank_name,card_number,card_last4," +
|
|
|
|
jdbc.update("INSERT INTO simulated_bank_account (account_id,user_id,bank_code,bank_name,card_number,card_last4," +
|
|
|
|
"balance,frozen_amount,status,created_at,updated_at) VALUES " +
|
|
|
|
"balance,frozen_amount,status,created_at,updated_at) VALUES " +
|
|
|
|
@ -93,7 +101,7 @@ class ExchangeControllerTest {
|
|
|
|
+ "received_at,received_by_user_id,received_by) VALUES (?,?,?,?,?,?,100,'DC',?,"
|
|
|
|
+ "received_at,received_by_user_id,received_by) VALUES (?,?,?,?,?,?,100,'DC',?,"
|
|
|
|
+ "'ISSUANCE_ORIGINAL',?,'AVAILABLE',"
|
|
|
|
+ "'ISSUANCE_ORIGINAL',?,'AVAILABLE',"
|
|
|
|
+ "CURRENT_TIMESTAMP,?,'test')",
|
|
|
|
+ "CURRENT_TIMESTAMP,?,'test')",
|
|
|
|
"DC_EXCHANGE_TEST_" + i, 9000 + i, 9000, "EXCHANGE_TEST_ISSUANCE", "BKCHCNBJ00001",
|
|
|
|
"DC_EXCHANGE_TEST_" + i, 9000 + i, 9000, ISSUANCE_REQUEST_ID, "BKCHCNBJ00001",
|
|
|
|
"ORG_EXCHANGE_TEST", "DC_TEST_COMPLETE_" + i, issuanceSignature, USER_ID);
|
|
|
|
"ORG_EXCHANGE_TEST", "DC_TEST_COMPLETE_" + i, issuanceSignature, USER_ID);
|
|
|
|
jdbc.update("INSERT INTO central_bank_currency_ownership (currency_id,owner_type,owner_id,status," +
|
|
|
|
jdbc.update("INSERT INTO central_bank_currency_ownership (currency_id,owner_type,owner_id,status," +
|
|
|
|
"last_transaction_id,updated_at) VALUES (?,'BANK','BKCHCNBJ00001','AVAILABLE',NULL,CURRENT_TIMESTAMP)",
|
|
|
|
"last_transaction_id,updated_at) VALUES (?,'BANK','BKCHCNBJ00001','AVAILABLE',NULL,CURRENT_TIMESTAMP)",
|
|
|
|
@ -119,7 +127,7 @@ class ExchangeControllerTest {
|
|
|
|
jdbc.update("DELETE FROM simulated_bank_account");
|
|
|
|
jdbc.update("DELETE FROM simulated_bank_account");
|
|
|
|
jdbc.update("DELETE FROM digital_wallet");
|
|
|
|
jdbc.update("DELETE FROM digital_wallet");
|
|
|
|
WalletOpeningTestData.deleteWalletFacts(jdbc, USER_ID);
|
|
|
|
WalletOpeningTestData.deleteWalletFacts(jdbc, USER_ID);
|
|
|
|
jdbc.update("DELETE FROM commercial_bank_currency WHERE issuance_request_id='EXCHANGE_TEST_ISSUANCE'");
|
|
|
|
deleteIssuanceProofData();
|
|
|
|
jdbc.update("DELETE FROM institution_sm2_key_audit WHERE user_id=?", USER_ID);
|
|
|
|
jdbc.update("DELETE FROM institution_sm2_key_audit WHERE user_id=?", USER_ID);
|
|
|
|
jdbc.update("DELETE FROM institution_sm2_key WHERE user_id=?", USER_ID);
|
|
|
|
jdbc.update("DELETE FROM institution_sm2_key WHERE user_id=?", USER_ID);
|
|
|
|
jdbc.update("DELETE FROM institution_identifier_application WHERE user_id=?", USER_ID);
|
|
|
|
jdbc.update("DELETE FROM institution_identifier_application WHERE user_id=?", USER_ID);
|
|
|
|
@ -170,9 +178,18 @@ class ExchangeControllerTest {
|
|
|
|
java.math.BigDecimal.class, accountId)).isEqualByComparingTo("200.00");
|
|
|
|
java.math.BigDecimal.class, accountId)).isEqualByComparingTo("200.00");
|
|
|
|
assertThat(jdbc.queryForObject("SELECT status FROM exchange_debit_record WHERE exchange_id=?",
|
|
|
|
assertThat(jdbc.queryForObject("SELECT status FROM exchange_debit_record WHERE exchange_id=?",
|
|
|
|
String.class, id)).isEqualTo("FROZEN");
|
|
|
|
String.class, id)).isEqualTo("FROZEN");
|
|
|
|
|
|
|
|
String expectedCbFinalSignature = jdbc.queryForObject(
|
|
|
|
|
|
|
|
"SELECT issuance_ownership_signature FROM commercial_bank_currency WHERE currency_id=?",
|
|
|
|
|
|
|
|
String.class, "DC_EXCHANGE_TEST_1");
|
|
|
|
|
|
|
|
String expectedCbCtrlSignature = jdbc.queryForObject(
|
|
|
|
|
|
|
|
"SELECT control_system_signature FROM draft_digital_currency WHERE coin_id=?",
|
|
|
|
|
|
|
|
String.class, "DC_EXCHANGE_TEST_1");
|
|
|
|
mockMvc.perform(post("/api/v1/exchanges/{id}/reserve-coins", id).with(user()))
|
|
|
|
mockMvc.perform(post("/api/v1/exchanges/{id}/reserve-coins", id).with(user()))
|
|
|
|
.andExpect(status().isOk()).andExpect(jsonPath("$.data.status").value("COINS_RESERVED"))
|
|
|
|
.andExpect(status().isOk()).andExpect(jsonPath("$.data.status").value("COINS_RESERVED"))
|
|
|
|
.andExpect(jsonPath("$.data.coinCount").value(2));
|
|
|
|
.andExpect(jsonPath("$.data.coinCount").value(2))
|
|
|
|
|
|
|
|
.andExpect(jsonPath("$.data.coins[0].completeCurrency").value("DC_TEST_COMPLETE_1"))
|
|
|
|
|
|
|
|
.andExpect(jsonPath("$.data.coins[0].cbCtrlSignature").value(expectedCbCtrlSignature))
|
|
|
|
|
|
|
|
.andExpect(jsonPath("$.data.coins[0].cbFinalSignature").value(expectedCbFinalSignature));
|
|
|
|
mockMvc.perform(post("/api/v1/exchanges/{id}/confirm-ownership", id).with(user()))
|
|
|
|
mockMvc.perform(post("/api/v1/exchanges/{id}/confirm-ownership", id).with(user()))
|
|
|
|
.andExpect(status().isOk()).andExpect(jsonPath("$.data.status").value("SUCCESS"))
|
|
|
|
.andExpect(status().isOk()).andExpect(jsonPath("$.data.status").value("SUCCESS"))
|
|
|
|
.andExpect(jsonPath("$.data.walletBalanceAfter").value(200.00))
|
|
|
|
.andExpect(jsonPath("$.data.walletBalanceAfter").value(200.00))
|
|
|
|
@ -316,6 +333,26 @@ class ExchangeControllerTest {
|
|
|
|
Integer.class, exchangeId)).isEqualTo(1);
|
|
|
|
Integer.class, exchangeId)).isEqualTo(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
|
|
void rejectsCoinWhenCentralBankControlSignatureIsTampered() throws Exception {
|
|
|
|
|
|
|
|
String[] values = createHeldExchange();
|
|
|
|
|
|
|
|
String attemptId = values[0];
|
|
|
|
|
|
|
|
executeAction(attemptId, "05", "receive-debit-voucher", "COMPLETED");
|
|
|
|
|
|
|
|
executeAction(attemptId, "05", "reserve-coins", "COMPLETED");
|
|
|
|
|
|
|
|
String[] actions = {"adjust-bank-ledger", "generate-transfer-request", "receive-transfer-request",
|
|
|
|
|
|
|
|
"reply-transfer-request", "verify-bank-signature", "recalculate-transfer-digest",
|
|
|
|
|
|
|
|
"compare-transfer-digest"};
|
|
|
|
|
|
|
|
for (String action : actions) executeAction(attemptId, "05", action, "COMPLETED");
|
|
|
|
|
|
|
|
jdbc.update("UPDATE draft_digital_currency SET control_system_signature=? WHERE coin_id=?",
|
|
|
|
|
|
|
|
"TAMPERED_CONTROL_SIGNATURE", "DC_EXCHANGE_TEST_1");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mockMvc.perform(post("/api/v1/exchange/attempts/{id}/steps/05/actions/verify-coin-ownership", attemptId)
|
|
|
|
|
|
|
|
.with(user()).contentType(MediaType.APPLICATION_JSON).content("{}"))
|
|
|
|
|
|
|
|
.andExpect(status().isBadRequest())
|
|
|
|
|
|
|
|
.andExpect(jsonPath("$.message").value(org.hamcrest.Matchers.containsString(
|
|
|
|
|
|
|
|
"央行控制系统签名验证失败")));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
@Test
|
|
|
|
void rejectsCentralConfirmationWhenItsOriginalTextNoLongerMatchesTheSignedDigest() throws Exception {
|
|
|
|
void rejectsCentralConfirmationWhenItsOriginalTextNoLongerMatchesTheSignedDigest() throws Exception {
|
|
|
|
String[] values = createHeldExchange();
|
|
|
|
String[] values = createHeldExchange();
|
|
|
|
@ -426,6 +463,58 @@ class ExchangeControllerTest {
|
|
|
|
.andExpect(jsonPath("$.data.actionStatus").value(expectedStatus));
|
|
|
|
.andExpect(jsonPath("$.data.actionStatus").value(expectedStatus));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void seedIssuanceProofData(String controlOriginalText, String controlDigest, String controlSignature,
|
|
|
|
|
|
|
|
String issuanceSignature) {
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO control_system_signature (id,transaction_identifier_id,control_id,amount," +
|
|
|
|
|
|
|
|
"institution_identifier,transaction_identifier,original_text,digest,signing_key_id,signature," +
|
|
|
|
|
|
|
|
"control_signature,response_message,status,user_id,school_id,class_id,created_at,updated_at," +
|
|
|
|
|
|
|
|
"created_by,updated_by,deleted) VALUES (?,?,?,200,?,?,?,?,?,?,?,?,'SENT',?,1999,2999," +
|
|
|
|
|
|
|
|
"CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,'test','test',FALSE)",
|
|
|
|
|
|
|
|
CONTROL_SIGNATURE_ID, 990003L, "CTRL_EXCHANGE_TEST", "ORG_EXCHANGE_TEST", "TXN_EXCHANGE_TEST",
|
|
|
|
|
|
|
|
controlOriginalText, controlDigest, InstitutionKeyService.CENTRAL_FIRST_KEY, controlSignature,
|
|
|
|
|
|
|
|
controlSignature, "{}", USER_ID);
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO central_bank_issuance_receipt (request_id,request_no,payload_json,received_at," +
|
|
|
|
|
|
|
|
"received_by_user_id,received_by) VALUES (?,?,?,CURRENT_TIMESTAMP,?,'test')",
|
|
|
|
|
|
|
|
ISSUANCE_REQUEST_ID, "REQ_EXCHANGE_TEST", "{}", USER_ID);
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO reserve_deduction_notification (request_id,transaction_id,bank_code,organization_id," +
|
|
|
|
|
|
|
|
"reserve_account_no,reserve_account_name,currency,deduction_amount,status,sent_at," +
|
|
|
|
|
|
|
|
"sent_by_user_id,sent_by) VALUES (?,?,?,?,?,?,?,200,'SUBMITTED',CURRENT_TIMESTAMP,?,'test')",
|
|
|
|
|
|
|
|
ISSUANCE_REQUEST_ID, DEDUCTION_TRANSACTION_ID, "BKCHCNBJ00001", "ORG_EXCHANGE_TEST",
|
|
|
|
|
|
|
|
"RESERVE_EXCHANGE_TEST", "兑换测试准备金账户", "DC", USER_ID);
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO reserve_deduction_execution (transaction_id,request_id,before_balance," +
|
|
|
|
|
|
|
|
"deduction_amount,after_balance,status,executed_at,executed_by_user_id,executed_by) " +
|
|
|
|
|
|
|
|
"VALUES (?,?,1000,200,800,'DEDUCTED',CURRENT_TIMESTAMP,?,'test')",
|
|
|
|
|
|
|
|
DEDUCTION_TRANSACTION_ID, ISSUANCE_REQUEST_ID, USER_ID);
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO digital_currency_production_batch (batch_id,request_id,deduction_transaction_id," +
|
|
|
|
|
|
|
|
"organization_id,currency,total_amount,status,created_at,created_by_user_id,created_by," +
|
|
|
|
|
|
|
|
"control_system_signature_id,complete_control_bit,control_system_signature) " +
|
|
|
|
|
|
|
|
"VALUES (?,?,?,?,?,200,'OWNERSHIP_CONFIRMED',CURRENT_TIMESTAMP,?,'test',?,?,?)",
|
|
|
|
|
|
|
|
PRODUCTION_BATCH_ID, ISSUANCE_REQUEST_ID, DEDUCTION_TRANSACTION_ID, "ORG_EXCHANGE_TEST", "DC",
|
|
|
|
|
|
|
|
USER_ID, CONTROL_SIGNATURE_ID, "CONTROL_BIT_EXCHANGE_TEST", controlSignature);
|
|
|
|
|
|
|
|
for (int i = 1; i <= 2; i++) {
|
|
|
|
|
|
|
|
jdbc.update("INSERT INTO draft_digital_currency (coin_id,batch_id,sequence_no,denomination," +
|
|
|
|
|
|
|
|
"organization_id,currency,status,created_at,created_by_user_id,created_by," +
|
|
|
|
|
|
|
|
"complete_control_bit,control_system_signature,ownership_original_text," +
|
|
|
|
|
|
|
|
"ownership_signature,complete_currency,confirmed_at,confirmed_by_user_id,confirmed_by) " +
|
|
|
|
|
|
|
|
"VALUES (?,?,?,100,'ORG_EXCHANGE_TEST','DC','AVAILABLE',CURRENT_TIMESTAMP,?,'test'," +
|
|
|
|
|
|
|
|
"?,?,'ISSUANCE_ORIGINAL',? ,?,CURRENT_TIMESTAMP,?,'test')",
|
|
|
|
|
|
|
|
"DC_EXCHANGE_TEST_" + i, PRODUCTION_BATCH_ID, i, USER_ID,
|
|
|
|
|
|
|
|
"CONTROL_BIT_EXCHANGE_TEST", controlSignature,
|
|
|
|
|
|
|
|
issuanceSignature, "DC_TEST_COMPLETE_" + i, USER_ID);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void deleteIssuanceProofData() {
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM commercial_bank_currency WHERE issuance_request_id IN (?,?)",
|
|
|
|
|
|
|
|
ISSUANCE_REQUEST_ID, "EXCHANGE_TEST_ISSUANCE");
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM draft_digital_currency WHERE batch_id=?", PRODUCTION_BATCH_ID);
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM digital_currency_production_batch WHERE batch_id=?", PRODUCTION_BATCH_ID);
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM reserve_deduction_execution WHERE transaction_id=?", DEDUCTION_TRANSACTION_ID);
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM reserve_deduction_notification WHERE request_id=?", ISSUANCE_REQUEST_ID);
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM central_bank_issuance_receipt WHERE request_id=?", ISSUANCE_REQUEST_ID);
|
|
|
|
|
|
|
|
jdbc.update("DELETE FROM control_system_signature WHERE id=?", CONTROL_SIGNATURE_ID);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String repeat(char value, int count) {
|
|
|
|
private String repeat(char value, int count) {
|
|
|
|
StringBuilder text = new StringBuilder(count);
|
|
|
|
StringBuilder text = new StringBuilder(count);
|
|
|
|
for (int i = 0; i < count; i++) text.append(value);
|
|
|
|
for (int i = 0; i < count; i++) text.append(value);
|
|
|
|
|