Example #1
0
  public static void main(String[] args) throws Exception {
    OptionParser parser = new OptionParser();
    parser.accepts("help");
    parser.accepts("force");
    parser.accepts("debuglog");
    OptionSpec<String> walletFileName =
        parser.accepts("wallet").withRequiredArg().defaultsTo("wallet");
    OptionSpec<NetworkEnum> netFlag =
        parser
            .accepts("net")
            .withOptionalArg()
            .ofType(NetworkEnum.class)
            .defaultsTo(NetworkEnum.PROD);
    dateFlag =
        parser
            .accepts("date")
            .withRequiredArg()
            .ofType(Date.class)
            .withValuesConvertedBy(DateConverter.datePattern("yyyy/MM/dd"));
    OptionSpec<WaitForEnum> waitForFlag =
        parser.accepts("waitfor").withRequiredArg().ofType(WaitForEnum.class);
    OptionSpec<ValidationMode> modeFlag =
        parser
            .accepts("mode")
            .withRequiredArg()
            .ofType(ValidationMode.class)
            .defaultsTo(ValidationMode.SPV);
    OptionSpec<String> chainFlag = parser.accepts("chain").withRequiredArg();
    // For addkey/delkey.
    parser.accepts("pubkey").withRequiredArg();
    parser.accepts("privkey").withRequiredArg();
    parser.accepts("addr").withRequiredArg();
    parser.accepts("peers").withRequiredArg();
    OptionSpec<String> outputFlag = parser.accepts("output").withRequiredArg();
    parser.accepts("value").withRequiredArg();
    parser.accepts("fee").withRequiredArg();
    unixtimeFlag = parser.accepts("unixtime").withRequiredArg().ofType(Integer.class);
    OptionSpec<String> conditionFlag = parser.accepts("condition").withRequiredArg();
    parser.accepts("locktime").withRequiredArg();
    parser.accepts("allow-unconfirmed");
    parser.accepts("offline");
    parser.accepts("ignore-mandatory-extensions");
    OptionSpec<String> passwordFlag = parser.accepts("password").withRequiredArg();
    OptionSpec<String> paymentRequestLocation = parser.accepts("payment-request").withRequiredArg();
    parser.accepts("no-pki");
    options = parser.parse(args);

    final String HELP_TEXT =
        Resources.toString(WalletTool.class.getResource("wallet-tool-help.txt"), Charsets.UTF_8);

    if (args.length == 0 || options.has("help") || options.nonOptionArguments().size() < 1) {
      System.out.println(HELP_TEXT);
      return;
    }

    ActionEnum action;
    try {
      String actionStr = options.nonOptionArguments().get(0);
      actionStr = actionStr.toUpperCase().replace("-", "_");
      action = ActionEnum.valueOf(actionStr);
    } catch (IllegalArgumentException e) {
      System.err.println("Could not understand action name " + options.nonOptionArguments().get(0));
      return;
    }

    if (options.has("debuglog")) {
      BriefLogFormatter.init();
      log.info("Starting up ...");
    } else {
      // Disable logspam unless there is a flag.
      java.util.logging.Logger logger = LogManager.getLogManager().getLogger("");
      logger.setLevel(Level.SEVERE);
    }
    switch (netFlag.value(options)) {
      case PROD:
        params = MainNetParams.get();
        chainFileName = new File("prodnet.chain");
        break;
      case TEST:
        params = TestNet3Params.get();
        chainFileName = new File("testnet.chain");
        break;
      case REGTEST:
        params = RegTestParams.get();
        chainFileName = new File("regtest.chain");
        break;
      default:
        throw new RuntimeException("Unreachable.");
    }
    mode = modeFlag.value(options);

    // Allow the user to override the name of the chain used.
    if (options.has(chainFlag)) {
      chainFileName = new File(chainFlag.value(options));
    }

    if (options.has("condition")) {
      condition = new Condition(conditionFlag.value(options));
    }

    if (options.has(passwordFlag)) {
      password = passwordFlag.value(options);
    }

    walletFile = new File(walletFileName.value(options));
    if (action == ActionEnum.CREATE) {
      createWallet(options, params, walletFile);
      return; // We're done.
    }
    if (!walletFile.exists()) {
      System.err.println(
          "Specified wallet file "
              + walletFile
              + " does not exist. Try wallet-tool --wallet="
              + walletFile
              + " create");
      return;
    }

    if (action == ActionEnum.RAW_DUMP) {
      // Just parse the protobuf and print, then bail out. Don't try and do a real deserialization.
      // This is
      // useful mostly for investigating corrupted wallets.
      FileInputStream stream = new FileInputStream(walletFile);
      try {
        Protos.Wallet proto = WalletProtobufSerializer.parseToProto(stream);
        System.out.println(proto.toString());
        return;
      } finally {
        stream.close();
      }
    }

    try {
      WalletProtobufSerializer loader = new WalletProtobufSerializer();
      if (options.has("ignore-mandatory-extensions")) loader.setRequireMandatoryExtensions(false);
      wallet = loader.readWallet(new BufferedInputStream(new FileInputStream(walletFile)));
      if (!wallet.getParams().equals(params)) {
        System.err.println(
            "Wallet does not match requested network parameters: "
                + wallet.getParams().getId()
                + " vs "
                + params.getId());
        return;
      }
    } catch (Exception e) {
      System.err.println("Failed to load wallet '" + walletFile + "': " + e.getMessage());
      e.printStackTrace();
      return;
    }

    // What should we do?
    switch (action) {
      case DUMP:
        dumpWallet();
        break;
      case ADD_KEY:
        addKey();
        break;
      case ADD_ADDR:
        addAddr();
        break;
      case DELETE_KEY:
        deleteKey();
        break;
      case RESET:
        reset();
        break;
      case SYNC:
        syncChain();
        break;
      case SEND:
        if (options.has(paymentRequestLocation) && options.has(outputFlag)) {
          System.err.println("--payment-request and --output cannot be used together.");
          return;
        } else if (options.has(outputFlag)) {
          BigInteger fee = BigInteger.ZERO;
          if (options.has("fee")) {
            fee = Utils.toNanoCoins((String) options.valueOf("fee"));
          }
          String lockTime = null;
          if (options.has("locktime")) {
            lockTime = (String) options.valueOf("locktime");
          }
          boolean allowUnconfirmed = options.has("allow-unconfirmed");
          send(outputFlag.values(options), fee, lockTime, allowUnconfirmed);
        } else if (options.has(paymentRequestLocation)) {
          sendPaymentRequest(paymentRequestLocation.value(options), !options.has("no-pki"));
        } else {
          System.err.println(
              "You must specify a --payment-request or at least one --output=addr:value.");
          return;
        }
        break;
    }

    if (!wallet.isConsistent()) {
      System.err.println("************** WALLET IS INCONSISTENT *****************");
      return;
    }

    saveWallet(walletFile);

    if (options.has(waitForFlag)) {
      WaitForEnum value;
      try {
        value = waitForFlag.value(options);
      } catch (Exception e) {
        System.err.println(
            "Could not understand the --waitfor flag: Valid options are WALLET_TX, BLOCK, "
                + "BALANCE and EVER");
        return;
      }
      wait(value);
      if (!wallet.isConsistent()) {
        System.err.println("************** WALLET IS INCONSISTENT *****************");
        return;
      }
      saveWallet(walletFile);
    }
    shutdown();
  }