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());
  }
Exemple #3
0
  @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;
   }
 }
Exemple #5
0
 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) {
    }
  }
Exemple #10
0
  @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();
 }