private void parsePaymentRequest(Protos.PaymentRequest request) throws PaymentProtocolException { try { if (request == null) throw new PaymentProtocolException("request cannot be null"); if (request.getPaymentDetailsVersion() != 1) throw new PaymentProtocolException.InvalidVersion( "Version 1 required. Received version " + request.getPaymentDetailsVersion()); paymentRequest = request; if (!request.hasSerializedPaymentDetails()) throw new PaymentProtocolException("No PaymentDetails"); paymentDetails = Protos.PaymentDetails.newBuilder() .mergeFrom(request.getSerializedPaymentDetails()) .build(); if (paymentDetails == null) throw new PaymentProtocolException("Invalid PaymentDetails"); if (!paymentDetails.hasNetwork()) params = MainNetParams.get(); else params = NetworkParameters.fromPmtProtocolID(paymentDetails.getNetwork()); if (params == null) throw new PaymentProtocolException.InvalidNetwork( "Invalid network " + paymentDetails.getNetwork()); if (paymentDetails.getOutputsCount() < 1) throw new PaymentProtocolException.InvalidOutputs("No outputs"); for (Protos.Output output : paymentDetails.getOutputsList()) { if (output.hasAmount()) totalValue = totalValue.add(Coin.valueOf(output.getAmount())); } // This won't ever happen in practice. It would only happen if the user provided outputs // that are obviously invalid. Still, we don't want to silently overflow. if (params.hasMaxMoney() && totalValue.compareTo(params.getMaxMoney()) > 0) throw new PaymentProtocolException.InvalidOutputs("The outputs are way too big."); } catch (InvalidProtocolBufferException e) { throw new PaymentProtocolException(e); } }
@Test public void testLastBlockSeenHash() throws Exception { // Test the lastBlockSeenHash field works. // LastBlockSeenHash should be empty if never set. Wallet wallet = new Wallet(params); Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(wallet); ByteString lastSeenBlockHash = walletProto.getLastSeenBlockHash(); assertTrue(lastSeenBlockHash.isEmpty()); // Create a block. Block block = params.getDefaultSerializer().makeBlock(BlockTest.blockBytes); Sha256Hash blockHash = block.getHash(); wallet.setLastBlockSeenHash(blockHash); wallet.setLastBlockSeenHeight(1); // Roundtrip the wallet and check it has stored the blockHash. Wallet wallet1 = roundTrip(wallet); assertEquals(blockHash, wallet1.getLastBlockSeenHash()); assertEquals(1, wallet1.getLastBlockSeenHeight()); // Test the Satoshi genesis block (hash of all zeroes) is roundtripped ok. Block genesisBlock = MainNetParams.get().getGenesisBlock(); wallet.setLastBlockSeenHash(genesisBlock.getHash()); Wallet wallet2 = roundTrip(wallet); assertEquals(genesisBlock.getHash(), wallet2.getLastBlockSeenHash()); }
@Test public void isBIPs() throws Exception { final MainNetParams mainnet = MainNetParams.get(); final Block genesis = mainnet.getGenesisBlock(); assertFalse(genesis.isBIP34()); assertFalse(genesis.isBIP66()); assertFalse(genesis.isBIP65()); assertFalse(genesis.isBIP101()); // 227835/00000000000001aa077d7aa84c532a4d69bdbff519609d1da0835261b7a74eb6: last version 1 block final Block block227835 = mainnet .getDefaultSerializer() .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block227835.dat"))); assertFalse(block227835.isBIP34()); assertFalse(block227835.isBIP66()); assertFalse(block227835.isBIP65()); assertFalse(block227835.isBIP101()); // 227836/00000000000000d0dfd4c9d588d325dce4f32c1b31b7c0064cba7025a9b9adcc: version 2 block final Block block227836 = mainnet .getDefaultSerializer() .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block227836.dat"))); assertTrue(block227836.isBIP34()); assertFalse(block227836.isBIP66()); assertFalse(block227836.isBIP65()); assertFalse(block227836.isBIP101()); // 363703/0000000000000000011b2a4cb91b63886ffe0d2263fd17ac5a9b902a219e0a14: version 3 block final Block block363703 = mainnet .getDefaultSerializer() .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block363703.dat"))); assertTrue(block363703.isBIP34()); assertTrue(block363703.isBIP66()); assertFalse(block363703.isBIP65()); assertFalse(block363703.isBIP101()); // 383616/00000000000000000aab6a2b34e979b09ca185584bd1aecf204f24d150ff55e9: version 4 block final Block block383616 = mainnet .getDefaultSerializer() .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block383616.dat"))); assertTrue(block383616.isBIP34()); assertTrue(block383616.isBIP66()); assertTrue(block383616.isBIP65()); assertFalse(block383616.isBIP101()); // 370661/00000000000000001416a613602d73bbe5c79170fd8f39d509896b829cf9021e final Block block370661 = mainnet .getDefaultSerializer() .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block370661.dat"))); assertTrue(block370661.isBIP34()); assertTrue(block370661.isBIP66()); assertTrue(block370661.isBIP65()); assertTrue(block370661.isBIP101()); }
/** * Returns the network parameters for the given string paymentProtocolID or NULL if not * recognized. */ @Nullable public static NetworkParameters fromPmtProtocolID(String pmtProtocolId) { if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_MAINNET)) { return MainNetParams.get(); } else if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_TESTNET)) { return TestNet3Params.get(); } else { return null; } }
public NetworkParameters get() { switch (this) { case MAIN: case PROD: return MainNetParams.get(); case TEST: return TestNet3Params.get(); case REGTEST: default: return RegTestParams.get(); } }
public static NetworkParameters getNetworkParameter(BlockchainNetworkType blockchainNetworkType) { switch (blockchainNetworkType) { case PRODUCTION: return MainNetParams.get(); case TEST_NET: return TestNet3Params.get(); case REG_TEST: return RegTestParams.get(); default: return getNetworkParameter(BitcoinNetworkConfiguration.DEFAULT_NETWORK_TYPE); } }
/** Returns the network parameters for the given string ID or NULL if not recognized. */ @Nullable public static NetworkParameters fromID(String id) { if (id.equals(ID_MAINNET)) { return MainNetParams.get(); } else if (id.equals(ID_TESTNET)) { return TestNet3Params.get(); } else if (id.equals(ID_UNITTESTNET)) { return UnitTestParams.get(); } else if (id.equals(ID_REGTEST)) { return RegTestParams.get(); } else { return null; } }
/** * Gets the correct BlockchainNetworkType based in the passed NetworkParameters * * @param networkParameters * @return */ public static BlockchainNetworkType getBlockchainNetworkType( NetworkParameters networkParameters) { /** I will return the correct network type. */ BlockchainNetworkType blockchainNetworkType = null; if (networkParameters == RegTestParams.get()) { blockchainNetworkType = BlockchainNetworkType.REG_TEST; } else if (networkParameters == MainNetParams.get()) { blockchainNetworkType = BlockchainNetworkType.PRODUCTION; } else if (networkParameters == TestNet3Params.get()) { blockchainNetworkType = BlockchainNetworkType.TEST_NET; } return blockchainNetworkType; }
@Test public void testFirst100KBlocks() throws Exception { NetworkParameters params = MainNetParams.get(); Context context = new Context(params); File blockFile = new File(getClass().getResource("first-100k-blocks.dat").getFile()); BlockFileLoader loader = new BlockFileLoader(params, Arrays.asList(blockFile)); store = createStore(params, 10); resetStore(store); chain = new FullPrunedBlockChain(context, store); for (Block block : loader) chain.add(block); try { store.close(); } catch (Exception e) { } }
@Test public void testReceiveCoinbaseTransaction() throws Exception { // Block 169482 (hash 0000000000000756935f1ee9d5987857b604046f846d3df56d024cdb5f368665) // contains coinbase transactions that are mining pool shares. // The private key MINERS_KEY is used to check transactions are received by a wallet correctly. // The address for this private key is 1GqtGtn4fctXuKxsVzRPSLmYWN1YioLi9y. final String MINING_PRIVATE_KEY = "5JDxPrBRghF1EvSBjDigywqfmAjpHPmTJxYtQTYJxJRHLLQA4mG"; final long BLOCK_NONCE = 3973947400L; final Coin BALANCE_AFTER_BLOCK = Coin.valueOf(22223642); final NetworkParameters PARAMS = MainNetParams.get(); Block block169482 = PARAMS .getDefaultSerializer() .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block169482.dat"))); // Check block. assertNotNull(block169482); block169482.verify(169482, EnumSet.noneOf(Block.VerifyFlag.class)); assertEquals(BLOCK_NONCE, block169482.getNonce()); StoredBlock storedBlock = new StoredBlock(block169482, BigInteger.ONE, 169482); // Nonsense work - not used in test. // Create a wallet contain the miner's key that receives a spend from a coinbase. ECKey miningKey = DumpedPrivateKey.fromBase58(PARAMS, MINING_PRIVATE_KEY).getKey(); assertNotNull(miningKey); Context context = new Context(PARAMS); Wallet wallet = new Wallet(context); wallet.importKey(miningKey); // Initial balance should be zero by construction. assertEquals(Coin.ZERO, wallet.getBalance()); // Give the wallet the first transaction in the block - this is the coinbase tx. List<Transaction> transactions = block169482.getTransactions(); assertNotNull(transactions); wallet.receiveFromBlock(transactions.get(0), storedBlock, NewBlockType.BEST_CHAIN, 0); // Coinbase transaction should have been received successfully but be unavailable to spend (too // young). assertEquals(BALANCE_AFTER_BLOCK, wallet.getBalance(BalanceType.ESTIMATED)); assertEquals(Coin.ZERO, wallet.getBalance(BalanceType.AVAILABLE)); }
public void checkUpgrade(Context context, NetworkParameters params) { if (checkDone) { // skip if already done return; } String appVersion = SharedPrefUtils.getAppVersion(context); if (appVersion == null) { // first start - no app version yet. Log.d(TAG, "No appVersion yet - first launch"); } else if (appVersion.equals(BuildConfig.VERSION_NAME)) { Log.d(TAG, "appVersion '" + appVersion + "' equals current version - no action required"); } else { // add upgrade instructions as needed. } if (migrateFrom_v1_0_262(context)) { Log.d(TAG, "Migrate from v1.0.262 / 2of2 multisig (CeBIT) to CLTV"); /* special case: migrate from objectstore and 2of2 multisig wallet * - migrate from early version v1.0.262 (CeBIT) * - enable transfer of funds to new address (2of2 multisig to cltv) */ try { // migration is done for mainnet and testnet regardless of the current network setting of // the app! NetworkParameters[] cltvMigrationParams = new NetworkParameters[] {MainNetParams.get(), TestNet3Params.get()}; for (NetworkParameters migrationParams : cltvMigrationParams) { doMigrateFrom_v1_0_262(context, migrationParams); } } catch (Exception e) { Log.e(TAG, "Migration failed: ", e); } } SharedPrefUtils.setAppVersion(context, BuildConfig.VERSION_NAME); checkDone = true; }
/** @author Andreas Schildbach */ public final class Constants { public static final boolean TEST = R.class.getPackage().getName().contains("_test"); /** Network this wallet is on (e.g. testnet or mainnet). */ public static final NetworkParameters NETWORK_PARAMETERS = TEST ? TestNet3Params.get() : MainNetParams.get(); public static final class Files { private static final String FILENAME_NETWORK_SUFFIX = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) ? "" : "-testnet"; /** Filename of the wallet. */ public static final String WALLET_FILENAME_PROTOBUF = "wallet-protobuf" + FILENAME_NETWORK_SUFFIX; /** Filename of the automatic key backup (old format, can only be read). */ public static final String WALLET_KEY_BACKUP_BASE58 = "key-backup-base58" + FILENAME_NETWORK_SUFFIX; /** Filename of the automatic wallet backup. */ public static final String WALLET_KEY_BACKUP_PROTOBUF = "key-backup-protobuf" + FILENAME_NETWORK_SUFFIX; /** Path to external storage */ public static final File EXTERNAL_STORAGE_DIR = Environment.getExternalStorageDirectory(); /** Manual backups go here. */ public static final File EXTERNAL_WALLET_BACKUP_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); /** Filename of the manual key backup (old format, can only be read). */ public static final String EXTERNAL_WALLET_KEY_BACKUP = "bitcoin-wallet-keys" + FILENAME_NETWORK_SUFFIX; /** Filename of the manual wallet backup. */ public static final String EXTERNAL_WALLET_BACKUP = "bitcoin-wallet-backup" + FILENAME_NETWORK_SUFFIX; /** Filename of the block store for storing the chain. */ public static final String BLOCKCHAIN_FILENAME = "blockchain" + FILENAME_NETWORK_SUFFIX; /** Filename of the block checkpoints file. */ public static final String CHECKPOINTS_FILENAME = "checkpoints" + FILENAME_NETWORK_SUFFIX + ".txt"; } /** Maximum size of backups. Files larger will be rejected. */ public static final long BACKUP_MAX_CHARS = 10000000; private static final String BITEASY_API_URL_PROD = "https://api.biteasy.com/blockchain/v1/"; private static final String BITEASY_API_URL_TEST = "https://api.biteasy.com/testnet/v1/"; /** Base URL for blockchain API. */ public static final String BITEASY_API_URL = NETWORK_PARAMETERS.getId().equals(NetworkParameters.ID_MAINNET) ? BITEASY_API_URL_PROD : BITEASY_API_URL_TEST; /** URL to fetch version alerts from. */ public static final String VERSION_URL = "https://wallet.schildbach.de/version"; /** MIME type used for transmitting single transactions. */ public static final String MIMETYPE_TRANSACTION = "application/x-btctx"; /** MIME type used for transmitting wallet backups. */ public static final String MIMETYPE_WALLET_BACKUP = "application/x-bitcoin-wallet-backup"; /** Number of confirmations until a transaction is fully confirmed. */ public static final int MAX_NUM_CONFIRMATIONS = 7; /** User-agent to use for network access. */ public static final String USER_AGENT = "Bitcoin Wallet"; /** Default currency to use if all default mechanisms fail. */ public static final String DEFAULT_EXCHANGE_CURRENCY = "USD"; /** Donation address for tip/donate action. */ public static final String DONATION_ADDRESS = "18CK5k1gajRKKSC7yVSTXT9LUzbheh1XY4"; /** Recipient e-mail address for reports. */ public static final String REPORT_EMAIL = "*****@*****.**"; /** Subject line for manually reported issues. */ public static final String REPORT_SUBJECT_ISSUE = "Reported issue"; /** Subject line for crash reports. */ public static final String REPORT_SUBJECT_CRASH = "Crash report"; public static final char CHAR_HAIR_SPACE = '\u200a'; public static final char CHAR_THIN_SPACE = '\u2009'; public static final char CHAR_ALMOST_EQUAL_TO = '\u2248'; public static final char CHAR_CHECKMARK = '\u2713'; public static final char CURRENCY_PLUS_SIGN = '\uff0b'; public static final char CURRENCY_MINUS_SIGN = '\uff0d'; public static final String PREFIX_ALMOST_EQUAL_TO = Character.toString(CHAR_ALMOST_EQUAL_TO) + CHAR_THIN_SPACE; public static final int ADDRESS_FORMAT_GROUP_SIZE = 4; public static final int ADDRESS_FORMAT_LINE_SIZE = 12; public static final MonetaryFormat LOCAL_FORMAT = new MonetaryFormat().noCode().minDecimals(2).optionalDecimals(); public static final BaseEncoding HEX = BaseEncoding.base16().lowerCase(); public static final String SOURCE_URL = "https://github.com/schildbach/bitcoin-wallet"; public static final String BINARY_URL = "https://github.com/schildbach/bitcoin-wallet/releases"; public static final String MARKET_APP_URL = "market://details?id=%s"; public static final String WEBMARKET_APP_URL = "https://play.google.com/store/apps/details?id=%s"; public static final int HTTP_TIMEOUT_MS = 15 * (int) DateUtils.SECOND_IN_MILLIS; public static final int PEER_TIMEOUT_MS = 15 * (int) DateUtils.SECOND_IN_MILLIS; public static final long LAST_USAGE_THRESHOLD_JUST_MS = DateUtils.HOUR_IN_MILLIS; public static final long LAST_USAGE_THRESHOLD_RECENTLY_MS = 2 * DateUtils.DAY_IN_MILLIS; public static final int SDK_JELLY_BEAN = 16; public static final int SDK_JELLY_BEAN_MR2 = 18; public static final int SDK_LOLLIPOP = 21; public static final int SDK_DEPRECATED_BELOW = Build.VERSION_CODES.ICE_CREAM_SANDWICH; public static final boolean BUG_OPENSSL_HEARTBLEED = Build.VERSION.SDK_INT == Constants.SDK_JELLY_BEAN && Build.VERSION.RELEASE.startsWith("4.1.1"); public static final int MEMORY_CLASS_LOWEND = 48; }
/** Alias for MainNetParams.get(), use that instead */ @Deprecated public static NetworkParameters prodNet() { return MainNetParams.get(); }