/** Read a transaction from the stream, parse it and ask the user * if they approve it. * \param out_approved A non-zero value will be written to here if the * user approved the transaction, otherwise a zero value * will be written. * \param sig_hash The signature hash of the transaction will be written to * here by parseTransaction(). This must be an array of 32 * bytes. * \param transaction_length The length of the transaction, in number of * bytes. This can be derived from the payload * length of a packet. */ static NOINLINE void parseTransactionAndAsk(uint8_t *out_approved, uint8_t *sig_hash, uint32_t transaction_length) { TransactionErrors r; uint8_t transaction_hash[32]; // Validate transaction and calculate hashes of it. *out_approved = 0; clearOutputsSeen(); r = parseTransaction(sig_hash, transaction_hash, transaction_length); if (r != TRANSACTION_NO_ERROR) { // Transaction parse error. writeString(STRINGSET_TRANSACTION, (uint8_t)r, PACKET_TYPE_FAILURE); return; } // Get permission from user. *out_approved = 0; // Does transaction_hash match previous approved transaction? if (prev_transaction_hash_valid) { if (bigCompare(transaction_hash, prev_transaction_hash) == BIGCMP_EQUAL) { *out_approved = 1; prev_transaction_hash_valid--; } } if (!(*out_approved)) { // Need to explicitly get permission from user. // The call to parseTransaction() should have logged all the outputs // to the user interface. if (askUser(ASKUSER_SIGN_TRANSACTION)) { writeString(STRINGSET_MISC, MISCSTR_PERMISSION_DENIED, PACKET_TYPE_FAILURE); } else { // User approved transaction. *out_approved = 1; memcpy(prev_transaction_hash, transaction_hash, 32); // The transaction hash can only be reused another // (number of inputs) - 1 times. This is to prevent an exploit // where an attacker crafts a lot of copies (with differing inputs // but identical outputs) of a genuine transaction. With unlimited // reuse of the transaction hash, acceptance of the original // genuine transaction would also allow all the copies to be // automatically accepted, causing the user to spend more than // they intended. prev_transaction_hash_valid = getTransactionNumInputs(); if (prev_transaction_hash_valid) { prev_transaction_hash_valid--; } } } // if (!(*out_approved)) }
/** Initialise wallet (load it if it's there). * \return #WALLET_NO_ERROR on success, or one of #WalletErrorsEnum if an * error occurred. */ WalletErrors initWallet(void) { uint8_t buffer[32]; uint8_t hash[32]; uint32_t version; wallet_loaded = 0; // Read version. if (nonVolatileRead(buffer, OFFSET_VERSION, 4) != NV_NO_ERROR) { last_error = WALLET_READ_ERROR; return last_error; } version = readU32LittleEndian(buffer); if ((version != VERSION_UNENCRYPTED) && (version != VERSION_IS_ENCRYPTED)) { last_error = WALLET_NOT_THERE; return last_error; } // Calculate checksum and check that it matches. if (calculateWalletChecksum(hash) != NV_NO_ERROR) { last_error = WALLET_READ_ERROR; return last_error; } if (encryptedNonVolatileRead(buffer, OFFSET_CHECKSUM, 32) != NV_NO_ERROR) { last_error = WALLET_READ_ERROR; return last_error; } if (bigCompare(buffer, hash) != BIGCMP_EQUAL) { last_error = WALLET_NOT_THERE; return last_error; } // Read number of addresses. if (encryptedNonVolatileRead(buffer, OFFSET_NUM_ADDRESSES, 4) != NV_NO_ERROR) { last_error = WALLET_READ_ERROR; return last_error; } num_addresses = readU32LittleEndian(buffer); wallet_loaded = 1; last_error = WALLET_NO_ERROR; return last_error; }
// (for sym 'num ['any | (NIL 'any . prg) | (T 'any . prg) ..]) -> any // (for sym|(sym2 . sym) 'lst ['any | (NIL 'any . prg) | (T 'any . prg) ..]) -> any // (for (sym|(sym2 . sym) 'any1 'any2 [. prg]) ['any | (NIL 'any . prg) | (T 'any . prg) ..]) -> any any doFor(any x) { any y, body, cond, a; cell c1; struct { // bindFrame struct bindFrame *link; int i, cnt; struct {any sym; any val;} bnd[2]; } f; f.link = Env.bind, Env.bind = (bindFrame*)&f; f.i = 0; if (!isCell(y = car(x = cdr(x))) || !isCell(cdr(y))) { if (!isCell(y)) { f.cnt = 1; f.bnd[0].sym = y; f.bnd[0].val = val(y); } else { f.cnt = 2; f.bnd[0].sym = cdr(y); f.bnd[0].val = val(cdr(y)); f.bnd[1].sym = car(y); f.bnd[1].val = val(car(y)); val(f.bnd[1].sym) = Zero; } y = Nil; x = cdr(x), Push(c1, EVAL(car(x))); if (isNum(data(c1))) val(f.bnd[0].sym) = Zero; body = x = cdr(x); for (;;) { if (isNum(data(c1))) { val(f.bnd[0].sym) = bigCopy(val(f.bnd[0].sym)); digAdd(val(f.bnd[0].sym), 2); if (bigCompare(val(f.bnd[0].sym), data(c1)) > 0) break; } else { if (!isCell(data(c1))) break; val(f.bnd[0].sym) = car(data(c1)); if (!isCell(data(c1) = cdr(data(c1)))) data(c1) = Nil; } if (f.cnt == 2) { val(f.bnd[1].sym) = bigCopy(val(f.bnd[1].sym)); digAdd(val(f.bnd[1].sym), 2); } do { if (!isNum(y = car(x))) { if (isSym(y)) y = val(y); else if (isNil(car(y))) { y = cdr(y); if (isNil(a = EVAL(car(y)))) { y = prog(cdr(y)); goto for1; } val(At) = a; y = Nil; } else if (car(y) == T) { y = cdr(y); if (!isNil(a = EVAL(car(y)))) { val(At) = a; y = prog(cdr(y)); goto for1; } y = Nil; } else y = evList(y); } } while (isCell(x = cdr(x))); x = body; } for1: drop(c1); if (f.cnt == 2) val(f.bnd[1].sym) = f.bnd[1].val; val(f.bnd[0].sym) = f.bnd[0].val; Env.bind = f.link; return y; } if (!isCell(car(y))) { f.cnt = 1; f.bnd[0].sym = car(y); f.bnd[0].val = val(car(y)); } else { f.cnt = 2; f.bnd[0].sym = cdar(y); f.bnd[0].val = val(cdar(y)); f.bnd[1].sym = caar(y); f.bnd[1].val = val(caar(y)); val(f.bnd[1].sym) = Zero; } y = cdr(y); val(f.bnd[0].sym) = EVAL(car(y)); y = cdr(y), cond = car(y), y = cdr(y); Push(c1,Nil); body = x = cdr(x); while (!isNil(a = EVAL(cond))) { val(At) = a; if (f.cnt == 2) { val(f.bnd[1].sym) = bigCopy(val(f.bnd[1].sym)); digAdd(val(f.bnd[1].sym), 2); } do { if (!isNum(data(c1) = car(x))) { if (isSym(data(c1))) data(c1) = val(data(c1)); else if (isNil(car(data(c1)))) { data(c1) = cdr(data(c1)); if (isNil(a = EVAL(car(data(c1))))) { data(c1) = prog(cdr(data(c1))); goto for2; } val(At) = a; data(c1) = Nil; } else if (car(data(c1)) == T) { data(c1) = cdr(data(c1)); if (!isNil(a = EVAL(car(data(c1))))) { val(At) = a; data(c1) = prog(cdr(data(c1))); goto for2; } data(c1) = Nil; } else data(c1) = evList(data(c1)); } } while (isCell(x = cdr(x))); if (isCell(y)) val(f.bnd[0].sym) = prog(y); x = body; } for2: if (f.cnt == 2) val(f.bnd[1].sym) = f.bnd[1].val; val(f.bnd[0].sym) = f.bnd[0].val; Env.bind = f.link; return Pop(c1); }
/** A proper test suite for randomness would be quite big, so this test * spits out samples into random.dat, where they can be analysed using * an external program. */ int main(int argc, char **argv) { uint8_t r[32]; int i, j; int num_samples; int abort; unsigned int bytes_written; FILE *f; uint8_t seed[64]; uint8_t keys[64][32]; uint8_t key2[32]; initTests(__FILE__); // Before outputting samples, do a sanity check that // generateDeterministic256() actually has different outputs when // each byte of the seed is changed. abort = 0; for (i = 0; i < 64; i++) { memset(seed, 0, 64); seed[i] = 1; generateDeterministic256(keys[i], seed, 0); for (j = 0; j < i; j++) { if (bigCompare(keys[i], keys[j]) == BIGCMP_EQUAL) { printf("generateDeterministic256() is ignoring byte %d of seed\n", i); abort = 1; break; } } if (abort) { break; } } if (abort) { reportFailure(); } else { reportSuccess(); } // Check that generateDeterministic256() isn't ignoring num. memset(seed, 0, 64); seed[0] = 1; generateDeterministic256(key2, seed, 1); abort = 0; for (j = 0; j < 64; j++) { if (bigCompare(key2, keys[j]) == BIGCMP_EQUAL) { printf("generateDeterministic256() is ignoring num\n"); abort = 1; break; } } if (abort) { reportFailure(); } else { reportSuccess(); } // Check that generateDeterministic256() is actually deterministic. generateDeterministic256(key2, seed, 0); if (bigCompare(key2, keys[0]) != BIGCMP_EQUAL) { printf("generateDeterministic256() is not deterministic\n"); reportFailure(); } else { reportSuccess(); } if (argc != 2) { printf("Usage: %s <n>, where <n> is number of 256 bit samples to take\n", argv[0]); printf("Samples will go into random.dat\n"); exit(1); } sscanf(argv[1], "%d", &num_samples); if (num_samples <= 0) { printf("Invalid number of samples specified\n"); exit(1); } f = fopen("random.dat", "wb"); if (f == NULL) { printf("Could not open random.dat for writing\n"); exit(1); } srand(42); bytes_written = 0; for (i = 0; i < num_samples; i++) { getRandom256(r); bytes_written += fwrite(r, 1, 32, f); } fclose(f); printf("%u bytes written to random.dat\n", bytes_written); finishTests(); exit(0); }
int main(void) { uint8_t temp[128]; uint8_t address1[20]; uint8_t address2[20]; uint8_t name[NAME_LENGTH]; uint8_t encryption_key[WALLET_ENCRYPTION_KEY_LENGTH]; uint8_t new_encryption_key[WALLET_ENCRYPTION_KEY_LENGTH]; uint8_t version[4]; uint8_t *address_buffer; uint8_t one_byte; AddressHandle *handles_buffer; AddressHandle ah; PointAffine public_key; PointAffine *public_key_buffer; int abort; int is_zero; int abort_duplicate; int abort_error; int i; int j; initTests(__FILE__); initWalletTest(); memset(encryption_key, 0, WALLET_ENCRYPTION_KEY_LENGTH); setEncryptionKey(encryption_key); // Blank out non-volatile storage area (set to all nulls). temp[0] = 0; for (i = 0; i < TEST_FILE_SIZE; i++) { fwrite(temp, 1, 1, wallet_test_file); } // sanitiseNonVolatileStorage() should nuke everything. if (sanitiseNonVolatileStorage(0, 0xffffffff) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("Cannot nuke NV storage using sanitiseNonVolatileStorage()\n"); reportFailure(); } // Check that the version field is "wallet not there". if (getWalletInfo(version, temp) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("getWalletInfo() failed after sanitiseNonVolatileStorage() was called\n"); reportFailure(); } if (readU32LittleEndian(version) == VERSION_NOTHING_THERE) { reportSuccess(); } else { printf("sanitiseNonVolatileStorage() does not set version to nothing there\n"); reportFailure(); } // initWallet() hasn't been called yet, so nearly every function should // return WALLET_NOT_THERE somehow. checkFunctionsReturnWalletNotThere(); // The non-volatile storage area was blanked out, so there shouldn't be a // (valid) wallet there. if (initWallet() == WALLET_NOT_THERE) { reportSuccess(); } else { printf("initWallet() doesn't recognise when wallet isn't there\n"); reportFailure(); } // Try creating a wallet and testing initWallet() on it. memcpy(name, "123456789012345678901234567890abcdefghij", NAME_LENGTH); if (newWallet(name) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("Could not create new wallet\n"); reportFailure(); } if (initWallet() == WALLET_NO_ERROR) { reportSuccess(); } else { printf("initWallet() does not recognise new wallet\n"); reportFailure(); } if ((getNumAddresses() == 0) && (walletGetLastError() == WALLET_EMPTY)) { reportSuccess(); } else { printf("New wallet isn't empty\n"); reportFailure(); } // Check that the version field is "unencrypted wallet". if (getWalletInfo(version, temp) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("getWalletInfo() failed after newWallet() was called\n"); reportFailure(); } if (readU32LittleEndian(version) == VERSION_UNENCRYPTED) { reportSuccess(); } else { printf("newWallet() does not set version to unencrypted wallet\n"); reportFailure(); } // Check that sanitise_nv_wallet() deletes wallet. if (sanitiseNonVolatileStorage(0, 0xffffffff) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("Cannot nuke NV storage using sanitiseNonVolatileStorage()\n"); reportFailure(); } if (initWallet() == WALLET_NOT_THERE) { reportSuccess(); } else { printf("sanitiseNonVolatileStorage() isn't deleting wallet\n"); reportFailure(); } // Make some new addresses, then create a new wallet and make sure the // new wallet is empty (i.e. check that newWallet() deletes existing // wallet). newWallet(name); if (makeNewAddress(temp, &public_key) != BAD_ADDRESS_HANDLE) { reportSuccess(); } else { printf("Couldn't create new address in new wallet\n"); reportFailure(); } newWallet(name); if ((getNumAddresses() == 0) && (walletGetLastError() == WALLET_EMPTY)) { reportSuccess(); } else { printf("newWallet() doesn't delete existing wallet\n"); reportFailure(); } // Unload wallet and make sure everything realises that the wallet is // not loaded. if (uninitWallet() == WALLET_NO_ERROR) { reportSuccess(); } else { printf("uninitWallet() failed to do its basic job\n"); reportFailure(); } checkFunctionsReturnWalletNotThere(); // Load wallet again. Since there is actually a wallet there, this // should succeed. if (initWallet() == WALLET_NO_ERROR) { reportSuccess(); } else { printf("uninitWallet() appears to be permanent\n"); reportFailure(); } // Change bytes in non-volatile memory and make sure initWallet() fails // because of the checksum check. if (uninitWallet() != WALLET_NO_ERROR) { printf("uninitWallet() failed to do its basic job 2\n"); reportFailure(); } abort = 0; for (i = 0; i < WALLET_RECORD_LENGTH; i++) { if (nonVolatileRead(&one_byte, (uint32_t)i, 1) != NV_NO_ERROR) { printf("NV read fail\n"); abort = 1; break; } one_byte++; if (nonVolatileWrite(&one_byte, (uint32_t)i, 1) != NV_NO_ERROR) { printf("NV write fail\n"); abort = 1; break; } if (initWallet() == WALLET_NO_ERROR) { printf("Wallet still loads when wallet checksum is wrong, offset = %d\n", i); abort = 1; break; } one_byte--; if (nonVolatileWrite(&one_byte, (uint32_t)i, 1) != NV_NO_ERROR) { printf("NV write fail\n"); abort = 1; break; } } if (!abort) { reportSuccess(); } else { reportFailure(); } // Create 2 new wallets and check that their addresses aren't the same newWallet(name); if (makeNewAddress(address1, &public_key) != BAD_ADDRESS_HANDLE) { reportSuccess(); } else { printf("Couldn't create new address in new wallet\n"); reportFailure(); } newWallet(name); memset(address2, 0, 20); memset(&public_key, 0, sizeof(PointAffine)); if (makeNewAddress(address2, &public_key) != BAD_ADDRESS_HANDLE) { reportSuccess(); } else { printf("Couldn't create new address in new wallet\n"); reportFailure(); } if (memcmp(address1, address2, 20)) { reportSuccess(); } else { printf("New wallets are creating identical addresses\n"); reportFailure(); } // Check that makeNewAddress() wrote to its outputs. is_zero = 1; for (i = 0; i < 20; i++) { if (address2[i] != 0) { is_zero = 0; break; } } if (is_zero) { printf("makeNewAddress() doesn't write the address\n"); reportFailure(); } else { reportSuccess(); } if (bigIsZero(public_key.x)) { printf("makeNewAddress() doesn't write the public key\n"); reportFailure(); } else { reportSuccess(); } // Make some new addresses, up to a limit. // Also check that addresses are unique. newWallet(name); abort = 0; address_buffer = malloc(MAX_TESTING_ADDRESSES * 20); for (i = 0; i < MAX_TESTING_ADDRESSES; i++) { if (makeNewAddress(&(address_buffer[i * 20]), &public_key) == BAD_ADDRESS_HANDLE) { printf("Couldn't create new address in new wallet\n"); abort = 1; break; } for (j = 0; j < i; j++) { if (!memcmp(&(address_buffer[i * 20]), &(address_buffer[j * 20]), 20)) { printf("Wallet addresses aren't unique\n"); abort = 1; break; } } if (abort) { break; } } free(address_buffer); if (!abort) { reportSuccess(); } else { reportFailure(); } // The wallet should be full now. // Check that making a new address now causes an appropriate error. if (makeNewAddress(temp, &public_key) == BAD_ADDRESS_HANDLE) { if (walletGetLastError() == WALLET_FULL) { reportSuccess(); } else { printf("Creating a new address on a full wallet gives incorrect error\n"); reportFailure(); } } else { printf("Creating a new address on a full wallet succeeds (it's not supposed to)\n"); reportFailure(); } // Check that getNumAddresses() fails when the wallet is empty. newWallet(name); if (getNumAddresses() == 0) { if (walletGetLastError() == WALLET_EMPTY) { reportSuccess(); } else { printf("getNumAddresses() doesn't recognise wallet is empty\n"); reportFailure(); } } else { printf("getNumAddresses() succeeds when used on empty wallet\n"); reportFailure(); } // Create a bunch of addresses in the (now empty) wallet and check that // getNumAddresses() returns the right number. address_buffer = malloc(MAX_TESTING_ADDRESSES * 20); public_key_buffer = malloc(MAX_TESTING_ADDRESSES * sizeof(PointAffine)); handles_buffer = malloc(MAX_TESTING_ADDRESSES * sizeof(AddressHandle)); abort = 0; for (i = 0; i < MAX_TESTING_ADDRESSES; i++) { ah = makeNewAddress(&(address_buffer[i * 20]), &(public_key_buffer[i])); handles_buffer[i] = ah; if (ah == BAD_ADDRESS_HANDLE) { printf("Couldn't create new address in new wallet\n"); abort = 1; reportFailure(); break; } } if (!abort) { reportSuccess(); } if (getNumAddresses() == MAX_TESTING_ADDRESSES) { reportSuccess(); } else { printf("getNumAddresses() returns wrong number of addresses\n"); reportFailure(); } // The wallet should contain unique addresses. abort_duplicate = 0; for (i = 0; i < MAX_TESTING_ADDRESSES; i++) { for (j = 0; j < i; j++) { if (!memcmp(&(address_buffer[i * 20]), &(address_buffer[j * 20]), 20)) { printf("Wallet has duplicate addresses\n"); abort_duplicate = 1; reportFailure(); break; } } } if (!abort_duplicate) { reportSuccess(); } // The wallet should contain unique public keys. abort_duplicate = 0; for (i = 0; i < MAX_TESTING_ADDRESSES; i++) { for (j = 0; j < i; j++) { if (bigCompare(public_key_buffer[i].x, public_key_buffer[j].x) == BIGCMP_EQUAL) { printf("Wallet has duplicate public keys\n"); abort_duplicate = 1; reportFailure(); break; } } } if (!abort_duplicate) { reportSuccess(); } // The address handles should start at 1 and be sequential. abort = 0; for (i = 0; i < MAX_TESTING_ADDRESSES; i++) { if (handles_buffer[i] != (AddressHandle)(i + 1)) { printf("Address handle %d should be %d, but got %d\n", i, i + 1, (int)handles_buffer[i]); abort = 1; reportFailure(); break; } } if (!abort) { reportSuccess(); } // While there's a bunch of addresses in the wallet, check that // getAddressAndPublicKey() obtains the same address and public key as // makeNewAddress(). abort_error = 0; abort = 0; for (i = 0; i < MAX_TESTING_ADDRESSES; i++) { ah = handles_buffer[i]; if (getAddressAndPublicKey(address1, &public_key, ah) != WALLET_NO_ERROR) { printf("Couldn't obtain address in wallet\n"); abort_error = 1; reportFailure(); break; } if ((memcmp(address1, &(address_buffer[i * 20]), 20)) || (bigCompare(public_key.x, public_key_buffer[i].x) != BIGCMP_EQUAL) || (bigCompare(public_key.y, public_key_buffer[i].y) != BIGCMP_EQUAL)) { printf("getAddressAndPublicKey() returned mismatching address or public key, ah = %d\n", i); abort = 1; reportFailure(); break; } } if (!abort) { reportSuccess(); } if (!abort_error) { reportSuccess(); } // Test getAddressAndPublicKey() and getPrivateKey() functions using // invalid and then valid address handles. if (getAddressAndPublicKey(temp, &public_key, 0) == WALLET_INVALID_HANDLE) { reportSuccess(); } else { printf("getAddressAndPublicKey() doesn't recognise 0 as invalid address handle\n"); reportFailure(); } if (getPrivateKey(temp, 0) == WALLET_INVALID_HANDLE) { reportSuccess(); } else { printf("getPrivateKey() doesn't recognise 0 as invalid address handle\n"); reportFailure(); } if (getAddressAndPublicKey(temp, &public_key, BAD_ADDRESS_HANDLE) == WALLET_INVALID_HANDLE) { reportSuccess(); } else { printf("getAddressAndPublicKey() doesn't recognise BAD_ADDRESS_HANDLE as invalid address handle\n"); reportFailure(); } if (getPrivateKey(temp, BAD_ADDRESS_HANDLE) == WALLET_INVALID_HANDLE) { reportSuccess(); } else { printf("getPrivateKey() doesn't recognise BAD_ADDRESS_HANDLE as invalid address handle\n"); reportFailure(); } if (getAddressAndPublicKey(temp, &public_key, handles_buffer[0]) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("getAddressAndPublicKey() doesn't recognise valid address handle\n"); reportFailure(); } if (getPrivateKey(temp, handles_buffer[0]) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("getPrivateKey() doesn't recognise valid address handle\n"); reportFailure(); } free(address_buffer); free(public_key_buffer); free(handles_buffer); // Check that changeEncryptionKey() works. memset(new_encryption_key, 0, WALLET_ENCRYPTION_KEY_LENGTH); new_encryption_key[0] = 1; if (changeEncryptionKey(new_encryption_key) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("Couldn't change encryption key\n"); reportFailure(); } // Check that the version field is "encrypted wallet". if (getWalletInfo(version, temp) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("getWalletInfo() failed after changeEncryptionKey() was called\n"); reportFailure(); } if (readU32LittleEndian(version) == VERSION_IS_ENCRYPTED) { reportSuccess(); } else { printf("changeEncryptionKey() does not set version to encrypted wallet\n"); reportFailure(); } // Check name matches what was given in newWallet(). if (!memcmp(temp, name, NAME_LENGTH)) { reportSuccess(); } else { printf("getWalletInfo() doesn't return correct name when wallet is loaded\n"); reportFailure(); } // Check that getWalletInfo() still works after unloading wallet. uninitWallet(); if (getWalletInfo(version, temp) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("getWalletInfo() failed after uninitWallet() was called\n"); reportFailure(); } if (readU32LittleEndian(version) == VERSION_IS_ENCRYPTED) { reportSuccess(); } else { printf("uninitWallet() caused wallet version to change\n"); reportFailure(); } // Check name matches what was given in newWallet(). if (!memcmp(temp, name, NAME_LENGTH)) { reportSuccess(); } else { printf("getWalletInfo() doesn't return correct name when wallet is not loaded\n"); reportFailure(); } // Change wallet's name and check that getWalletInfo() reflects the // name change. initWallet(); memcpy(name, "HHHHH HHHHHHHHHHHHHHHHH HHHHHHHHHHHHHH ", NAME_LENGTH); if (changeWalletName(name) == WALLET_NO_ERROR) { reportSuccess(); } else { printf("changeWalletName() couldn't change name\n"); reportFailure(); } getWalletInfo(version, temp); if (!memcmp(temp, name, NAME_LENGTH)) { reportSuccess(); } else { printf("getWalletInfo() doesn't reflect name change\n"); reportFailure(); } // Check that name change is preserved when unloading and loading a // wallet. uninitWallet(); getWalletInfo(version, temp); if (!memcmp(temp, name, NAME_LENGTH)) { reportSuccess(); } else { printf("getWalletInfo() doesn't reflect name change after unloading wallet\n"); reportFailure(); } // Check that initWallet() succeeds (changing the name changes the // checksum, so this tests whether the checksum was updated). if (initWallet() == WALLET_NO_ERROR) { reportSuccess(); } else { printf("initWallet() failed after name change\n"); reportFailure(); } getWalletInfo(version, temp); if (!memcmp(temp, name, NAME_LENGTH)) { reportSuccess(); } else { printf("getWalletInfo() doesn't reflect name change after reloading wallet\n"); reportFailure(); } // Check that loading the wallet with the old key fails. uninitWallet(); setEncryptionKey(encryption_key); if (initWallet() == WALLET_NOT_THERE) { reportSuccess(); } else { printf("Loading wallet with old encryption key succeeds\n"); reportFailure(); } // Check that loading the wallet with the new key succeeds. uninitWallet(); setEncryptionKey(new_encryption_key); if (initWallet() == WALLET_NO_ERROR) { reportSuccess(); } else { printf("Loading wallet with new encryption key fails\n"); reportFailure(); } // Test the getAddressAndPublicKey() and getPrivateKey() functions on an // empty wallet. newWallet(name); if (getAddressAndPublicKey(temp, &public_key, 0) == WALLET_EMPTY) { reportSuccess(); } else { printf("getAddressAndPublicKey() doesn't deal with empty wallets correctly\n"); reportFailure(); } if (getPrivateKey(temp, 0) == WALLET_EMPTY) { reportSuccess(); } else { printf("getPrivateKey() doesn't deal with empty wallets correctly\n"); reportFailure(); } fclose(wallet_test_file); finishTests(); exit(0); }