/*
   * We completed handling of a filtered block. Update false-positive estimate based
   * on the total number of transactions in the original block.
   *
   * count includes filtered transactions, transactions that were passed in and were relevant
   * and transactions that were false positives (i.e. includes all transactions in the block).
   */
  protected void trackFilteredTransactions(int count) {
    // Track non-false-positives in batch.  Each non-false-positive counts as
    // 0.0 towards the estimate.
    //
    // This is slightly off because we are applying false positive tracking before non-FP tracking,
    // which counts FP as if they came at the beginning of the block.  Assuming uniform FP
    // spread in a block, this will somewhat underestimate the FP rate (5% for 1000 tx block).
    double alphaDecay = Math.pow(1 - FP_ESTIMATOR_ALPHA, count);

    // new_rate = alpha_decay * new_rate
    falsePositiveRate = alphaDecay * falsePositiveRate;

    double betaDecay = Math.pow(1 - FP_ESTIMATOR_BETA, count);

    // trend = beta * (new_rate - old_rate) + beta_decay * trend
    falsePositiveTrend =
        FP_ESTIMATOR_BETA * count * (falsePositiveRate - previousFalsePositiveRate)
            + betaDecay * falsePositiveTrend;

    // new_rate += alpha_decay * trend
    falsePositiveRate += alphaDecay * falsePositiveTrend;

    // Stash new_rate in old_rate
    previousFalsePositiveRate = falsePositiveRate;
  }
예제 #2
0
 @Override
 public int receiveBytes(ByteBuffer buff) {
   checkArgument(
       buff.position() == 0
           && buff.capacity() >= BitcoinSerializer.BitcoinPacketHeader.HEADER_LENGTH + 4);
   try {
     // Repeatedly try to deserialize messages until we hit a BufferUnderflowException
     boolean firstMessage = true;
     while (true) {
       // If we are in the middle of reading a message, try to fill that one first, before we
       // expect another
       if (largeReadBuffer != null) {
         // This can only happen in the first iteration
         checkState(firstMessage);
         // Read new bytes into the largeReadBuffer
         int bytesToGet = Math.min(buff.remaining(), largeReadBuffer.length - largeReadBufferPos);
         buff.get(largeReadBuffer, largeReadBufferPos, bytesToGet);
         largeReadBufferPos += bytesToGet;
         // Check the largeReadBuffer's status
         if (largeReadBufferPos == largeReadBuffer.length) {
           // ...processing a message if one is available
           processMessage(serializer.deserializePayload(header, ByteBuffer.wrap(largeReadBuffer)));
           largeReadBuffer = null;
           header = null;
           firstMessage = false;
         } else // ...or just returning if we don't have enough bytes yet
         return buff.position();
       }
       // Now try to deserialize any messages left in buff
       Message message;
       int preSerializePosition = buff.position();
       try {
         message = serializer.deserialize(buff);
       } catch (BufferUnderflowException e) {
         // If we went through the whole buffer without a full message, we need to use the
         // largeReadBuffer
         if (firstMessage && buff.limit() == buff.capacity()) {
           // ...so reposition the buffer to 0 and read the next message header
           buff.position(0);
           try {
             serializer.seekPastMagicBytes(buff);
             header = serializer.deserializeHeader(buff);
             // Initialize the largeReadBuffer with the next message's size and fill it with any
             // bytes
             // left in buff
             largeReadBuffer = new byte[header.size];
             largeReadBufferPos = buff.remaining();
             buff.get(largeReadBuffer, 0, largeReadBufferPos);
           } catch (BufferUnderflowException e1) {
             // If we went through a whole buffer's worth of bytes without getting a header, give
             // up
             // In cases where the buff is just really small, we could create a second
             // largeReadBuffer
             // that we use to deserialize the magic+header, but that is rather complicated when
             // the buff
             // should probably be at least that big anyway (for efficiency)
             throw new ProtocolException(
                 "No magic bytes+header after reading " + buff.capacity() + " bytes");
           }
         } else {
           // Reposition the buffer to its original position, which saves us from skipping messages
           // by
           // seeking past part of the magic bytes before all of them are in the buffer
           buff.position(preSerializePosition);
         }
         return buff.position();
       }
       // Process our freshly deserialized message
       processMessage(message);
       firstMessage = false;
     }
   } catch (Exception e) {
     exceptionCaught(e);
     return -1; // Returning -1 also throws an IllegalStateException upstream and kills the
                // connection
   }
 }
예제 #3
0
 /**
  * Returns all the key chains found in the given list of keys. Typically there will only be one,
  * but in the case of key rotation it can happen that there are multiple chains found.
  */
 public static List<DeterministicKeyChain> fromProtobuf(
     List<Protos.Key> keys, @Nullable KeyCrypter crypter) throws UnreadableWalletException {
   List<DeterministicKeyChain> chains = newLinkedList();
   DeterministicSeed seed = null;
   DeterministicKeyChain chain = null;
   int lookaheadSize = -1;
   for (Protos.Key key : keys) {
     final Protos.Key.Type t = key.getType();
     if (t == Protos.Key.Type.DETERMINISTIC_MNEMONIC) {
       if (chain != null) {
         checkState(lookaheadSize >= 0);
         chain.setLookaheadSize(lookaheadSize);
         chain.maybeLookAhead();
         chains.add(chain);
         chain = null;
       }
       long timestamp = key.getCreationTimestamp() / 1000;
       String passphrase = DEFAULT_PASSPHRASE_FOR_MNEMONIC; // FIXME allow non-empty passphrase
       if (key.hasSecretBytes()) {
         seed = new DeterministicSeed(key.getSecretBytes().toStringUtf8(), passphrase, timestamp);
       } else if (key.hasEncryptedData()) {
         EncryptedData data =
             new EncryptedData(
                 key.getEncryptedData().getInitialisationVector().toByteArray(),
                 key.getEncryptedData().getEncryptedPrivateKey().toByteArray());
         seed = new DeterministicSeed(data, timestamp);
       } else {
         throw new UnreadableWalletException("Malformed key proto: " + key.toString());
       }
       if (log.isDebugEnabled()) log.debug("Deserializing: DETERMINISTIC_MNEMONIC: {}", seed);
     } else if (t == Protos.Key.Type.DETERMINISTIC_KEY) {
       if (!key.hasDeterministicKey())
         throw new UnreadableWalletException(
             "Deterministic key missing extra data: " + key.toString());
       byte[] chainCode = key.getDeterministicKey().getChainCode().toByteArray();
       // Deserialize the path through the tree.
       LinkedList<ChildNumber> path = newLinkedList();
       for (int i : key.getDeterministicKey().getPathList()) path.add(new ChildNumber(i));
       // Deserialize the public key and path.
       ECPoint pubkey = ECKey.CURVE.getCurve().decodePoint(key.getPublicKey().toByteArray());
       final ImmutableList<ChildNumber> immutablePath = ImmutableList.copyOf(path);
       // Possibly create the chain, if we didn't already do so yet.
       boolean isWatchingAccountKey = false;
       boolean isFollowingKey = false;
       // save previous chain if any if the key is marked as following. Current key and the next
       // ones are to be
       // placed in new following key chain
       if (key.getDeterministicKey().getIsFollowing()) {
         if (chain != null) {
           checkState(lookaheadSize >= 0);
           chain.setLookaheadSize(lookaheadSize);
           chain.maybeLookAhead();
           chains.add(chain);
           chain = null;
           seed = null;
         }
         isFollowingKey = true;
       }
       if (chain == null) {
         if (seed == null) {
           DeterministicKey accountKey =
               new DeterministicKey(immutablePath, chainCode, pubkey, null, null);
           if (!accountKey.getPath().equals(ACCOUNT_ZERO_PATH))
             throw new UnreadableWalletException(
                 "Expecting account key but found key with path: "
                     + HDUtils.formatPath(accountKey.getPath()));
           chain = new DeterministicKeyChain(accountKey, isFollowingKey);
           isWatchingAccountKey = true;
         } else {
           chain = new DeterministicKeyChain(seed, crypter);
           chain.lookaheadSize = LAZY_CALCULATE_LOOKAHEAD;
           // If the seed is encrypted, then the chain is incomplete at this point. However, we
           // will load
           // it up below as we parse in the keys. We just need to check at the end that we've
           // loaded
           // everything afterwards.
         }
       }
       // Find the parent key assuming this is not the root key, and not an account key for a
       // watching chain.
       DeterministicKey parent = null;
       if (!path.isEmpty() && !isWatchingAccountKey) {
         ChildNumber index = path.removeLast();
         parent = chain.hierarchy.get(path, false, false);
         path.add(index);
       }
       DeterministicKey detkey;
       if (key.hasSecretBytes()) {
         // Not encrypted: private key is available.
         final BigInteger priv = new BigInteger(1, key.getSecretBytes().toByteArray());
         detkey = new DeterministicKey(immutablePath, chainCode, pubkey, priv, parent);
       } else {
         if (key.hasEncryptedData()) {
           Protos.EncryptedData proto = key.getEncryptedData();
           EncryptedData data =
               new EncryptedData(
                   proto.getInitialisationVector().toByteArray(),
                   proto.getEncryptedPrivateKey().toByteArray());
           checkNotNull(crypter, "Encountered an encrypted key but no key crypter provided");
           detkey = new DeterministicKey(immutablePath, chainCode, crypter, pubkey, data, parent);
         } else {
           // No secret key bytes and key is not encrypted: either a watching key or private key
           // bytes
           // will be rederived on the fly from the parent.
           detkey = new DeterministicKey(immutablePath, chainCode, pubkey, null, parent);
         }
       }
       if (key.hasCreationTimestamp())
         detkey.setCreationTimeSeconds(key.getCreationTimestamp() / 1000);
       if (log.isDebugEnabled()) log.debug("Deserializing: DETERMINISTIC_KEY: {}", detkey);
       if (!isWatchingAccountKey) {
         // If the non-encrypted case, the non-leaf keys (account, internal, external) have already
         // been
         // rederived and inserted at this point and the two lines below are just a no-op. In the
         // encrypted
         // case though, we can't rederive and we must reinsert, potentially building the heirarchy
         // object
         // if need be.
         if (path.size() == 0) {
           // Master key.
           chain.rootKey = detkey;
           chain.hierarchy = new DeterministicHierarchy(detkey);
         } else if (path.size() == 2) {
           if (detkey.getChildNumber().num() == 0) {
             chain.externalKey = detkey;
             chain.issuedExternalKeys = key.getDeterministicKey().getIssuedSubkeys();
             lookaheadSize = Math.max(lookaheadSize, key.getDeterministicKey().getLookaheadSize());
           } else if (detkey.getChildNumber().num() == 1) {
             chain.internalKey = detkey;
             chain.issuedInternalKeys = key.getDeterministicKey().getIssuedSubkeys();
           }
         }
       }
       chain.hierarchy.putKey(detkey);
       chain.basicKeyChain.importKey(detkey);
     }
   }
   if (chain != null) {
     checkState(lookaheadSize >= 0);
     chain.setLookaheadSize(lookaheadSize);
     chain.maybeLookAhead();
     chains.add(chain);
   }
   return chains;
 }